mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 08:52:36 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
81bc56b5d2
55
.github/ISSUE_TEMPLATE/app-bug-report.yaml
vendored
Normal file
55
.github/ISSUE_TEMPLATE/app-bug-report.yaml
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# Docs - https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||||
|
name: Application Bug Report
|
||||||
|
description: Problem with the application itself (ie. bad file path handling, UX issue)
|
||||||
|
title: "[APP BUG]: "
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Important: Read First
|
||||||
|
|
||||||
|
**Please do not make support requests on GitHub. Our issue tracker is for tracking bugs and feature requests only.
|
||||||
|
If you have a support request or are unsure about the nature of your issue please contact us on [discord](https://discord.gg/bFJxfftGW6).**
|
||||||
|
|
||||||
|
Please make an effort to make sure your issue isn't already reported.
|
||||||
|
|
||||||
|
Do not create issues involving software piracy, our rules specifically prohibit this. Otherwise your issue will be closed and you will be banned in this repository.
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
options:
|
||||||
|
- label: I have searched for a similar issue in this repository and did not find one.
|
||||||
|
required: true
|
||||||
|
- label: I am using an official build obtained from [releases](https://github.com/shadps4-emu/shadPS4/releases) or updated one of those builds using its in-app updater.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: desc
|
||||||
|
attributes:
|
||||||
|
label: Describe the Bug
|
||||||
|
description: "A clear and concise description of what the bug is"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: repro
|
||||||
|
attributes:
|
||||||
|
label: Reproduction Steps
|
||||||
|
description: "Detailed steps to reproduce the behavior"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: Expected Behavior
|
||||||
|
description: "A clear and concise description of what you expected to happen"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: Specify OS Version
|
||||||
|
placeholder: "Example: Windows 11, Arch Linux, MacOS 15"
|
||||||
|
validations:
|
||||||
|
required: true
|
10
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
10
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Discord
|
||||||
|
url: https://discord.gg/bFJxfftGW6
|
||||||
|
about: Get direct support and hang out with us
|
||||||
|
- name: Wiki
|
||||||
|
url: https://github.com/shadps4-emu/shadPS4/wiki
|
||||||
|
about: Information, guides, etc.
|
54
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
Normal file
54
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# Docs - https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||||
|
name: Feature Request
|
||||||
|
description: Suggest a new feature or improve an existing one
|
||||||
|
title: "[Feature Request]: "
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Important: Read First
|
||||||
|
|
||||||
|
Please make an effort to make sure your issue isn't already reported.
|
||||||
|
|
||||||
|
Do not create issues involving software piracy, our rules specifically prohibit this. Otherwise your issue will be closed and you will be banned in this repository.
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
options:
|
||||||
|
- label: I have searched for a similar issue in this repository and did not find one.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: desc
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
A concise description of the feature you want
|
||||||
|
|
||||||
|
Include step by step examples of how the feature should work under various circumstances
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reason
|
||||||
|
attributes:
|
||||||
|
label: Reason
|
||||||
|
description: |
|
||||||
|
Give a reason why you want this feature
|
||||||
|
- How will it make things easier for you?
|
||||||
|
- How does this feature help your enjoyment of the emulator?
|
||||||
|
- What does it provide that isn't being provided currently?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: examples
|
||||||
|
attributes:
|
||||||
|
label: Examples
|
||||||
|
description: |
|
||||||
|
Provide examples of the feature as implemented by other software
|
||||||
|
|
||||||
|
Include screenshots or video if you like to help demonstrate how you'd like this feature to work
|
||||||
|
validations:
|
||||||
|
required: false
|
95
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
Normal file
95
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# Docs - https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||||
|
name: Game Emulation Bug Report
|
||||||
|
description: Problem in a game (ie. graphical artifacts, crashes, etc.)
|
||||||
|
title: "[GAME BUG]: "
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Important: Read First
|
||||||
|
|
||||||
|
**Please do not make support requests on GitHub. Our issue tracker is for tracking bugs and feature requests only.
|
||||||
|
If you have a support request or are unsure about the nature of your issue please contact us on [discord](https://discord.gg/bFJxfftGW6).**
|
||||||
|
|
||||||
|
This repository does not provide support for modded games. You should perform and test a clean game installation before submitting an issue.
|
||||||
|
|
||||||
|
This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats).
|
||||||
|
|
||||||
|
Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-emu/shadps4-game-compatibility) for the information about the status of the game.
|
||||||
|
|
||||||
|
Please make an effort to make sure your issue isn't already reported.
|
||||||
|
|
||||||
|
Do not create issues involving software piracy, our rules specifically prohibit this. Otherwise your issue will be closed and you will be banned in this repository.
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist (we expect you to perform these steps before opening the issue)
|
||||||
|
options:
|
||||||
|
- label: I have searched for a similar issue in this repository and did not find one.
|
||||||
|
required: true
|
||||||
|
- label: I am using an official build obtained from [releases](https://github.com/shadps4-emu/shadPS4/releases) or updated one of those builds using its in-app updater.
|
||||||
|
required: true
|
||||||
|
- label: I have re-dumped the game and performed a clean install without mods and the issue is still present.
|
||||||
|
required: true
|
||||||
|
- label: I have disabled all patches and cheats and the issue is still present.
|
||||||
|
required: true
|
||||||
|
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadps4-game-compatibility?tab=readme-ov-file#informations) installed.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: desc
|
||||||
|
attributes:
|
||||||
|
label: Describe the Bug
|
||||||
|
description: "A clear and concise description of what the bug is"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: repro
|
||||||
|
attributes:
|
||||||
|
label: Reproduction Steps
|
||||||
|
description: "Detailed steps to reproduce the behavior"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: Specify OS Version
|
||||||
|
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
|
||||||
|
- type: input
|
||||||
|
id: vram
|
||||||
|
attributes:
|
||||||
|
label: Amount of VRAM in GB
|
||||||
|
placeholder: "Example: 8 GB"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: "Log File"
|
||||||
|
description: Drag and drop the log file here. It can be found by right clicking on a game name -> Open Folder... -> Open Log Folder. Make sure that the log type is set to `sync`.
|
||||||
|
validations:
|
||||||
|
required: true
|
82
.github/workflows/build.yml
vendored
82
.github/workflows/build.yml
vendored
@ -14,14 +14,14 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
reuse:
|
reuse:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: fsfe/reuse-action@v5
|
- uses: fsfe/reuse-action@v5
|
||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@ -39,7 +39,7 @@ jobs:
|
|||||||
run: ./.ci/clang-format.sh
|
run: ./.ci/clang-format.sh
|
||||||
|
|
||||||
get-info:
|
get-info:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
outputs:
|
outputs:
|
||||||
date: ${{ steps.vars.outputs.date }}
|
date: ${{ steps.vars.outputs.date }}
|
||||||
shorthash: ${{ steps.vars.outputs.shorthash }}
|
shorthash: ${{ steps.vars.outputs.shorthash }}
|
||||||
@ -57,7 +57,7 @@ jobs:
|
|||||||
echo "fullhash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
echo "fullhash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
windows-sdl:
|
windows-sdl:
|
||||||
runs-on: windows-latest
|
runs-on: windows-2025
|
||||||
needs: get-info
|
needs: get-info
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@ -101,7 +101,7 @@ jobs:
|
|||||||
path: ${{github.workspace}}/build/shadPS4.exe
|
path: ${{github.workspace}}/build/shadPS4.exe
|
||||||
|
|
||||||
windows-qt:
|
windows-qt:
|
||||||
runs-on: windows-latest
|
runs-on: windows-2025
|
||||||
needs: get-info
|
needs: get-info
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@ -376,6 +376,78 @@ jobs:
|
|||||||
name: shadps4-linux-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
|
name: shadps4-linux-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
|
||||||
path: Shadps4-qt.AppImage
|
path: Shadps4-qt.AppImage
|
||||||
|
|
||||||
|
linux-sdl-gcc:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: get-info
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||||
|
|
||||||
|
- name: Cache CMake Configuration
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: ${{ runner.os }}-sdl-cache-cmake-configuration
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/build
|
||||||
|
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ env.cache-name }}-
|
||||||
|
|
||||||
|
- name: Cache CMake Build
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||||
|
env:
|
||||||
|
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||||
|
with:
|
||||||
|
append-timestamp: false
|
||||||
|
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||||
|
|
||||||
|
linux-qt-gcc:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: get-info
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||||
|
|
||||||
|
- name: Cache CMake Configuration
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
${{github.workspace}}/build
|
||||||
|
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ env.cache-name }}-
|
||||||
|
|
||||||
|
- name: Cache CMake Build
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||||
|
env:
|
||||||
|
cache-name: ${{ runner.os }}-qt-cache-cmake-build
|
||||||
|
with:
|
||||||
|
append-timestamp: false
|
||||||
|
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_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
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||||
|
|
||||||
pre-release:
|
pre-release:
|
||||||
if: github.ref == 'refs/heads/main' && github.repository == 'shadps4-emu/shadPS4' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/main' && github.repository == 'shadps4-emu/shadPS4' && github.event_name == 'push'
|
||||||
needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
|
needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
|
||||||
|
@ -106,7 +106,7 @@ git_describe(GIT_DESC --always --long --dirty)
|
|||||||
git_branch_name(GIT_BRANCH)
|
git_branch_name(GIT_BRANCH)
|
||||||
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
|
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp" @ONLY)
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
|
||||||
|
|
||||||
find_package(Boost 1.84.0 CONFIG)
|
find_package(Boost 1.84.0 CONFIG)
|
||||||
find_package(FFmpeg 5.1.2 MODULE)
|
find_package(FFmpeg 5.1.2 MODULE)
|
||||||
@ -188,6 +188,8 @@ set(AJM_LIB src/core/libraries/ajm/ajm.cpp
|
|||||||
src/core/libraries/ajm/ajm_context.cpp
|
src/core/libraries/ajm/ajm_context.cpp
|
||||||
src/core/libraries/ajm/ajm_context.h
|
src/core/libraries/ajm/ajm_context.h
|
||||||
src/core/libraries/ajm/ajm_error.h
|
src/core/libraries/ajm/ajm_error.h
|
||||||
|
src/core/libraries/ajm/ajm_instance_statistics.cpp
|
||||||
|
src/core/libraries/ajm/ajm_instance_statistics.h
|
||||||
src/core/libraries/ajm/ajm_instance.cpp
|
src/core/libraries/ajm/ajm_instance.cpp
|
||||||
src/core/libraries/ajm/ajm_instance.h
|
src/core/libraries/ajm/ajm_instance.h
|
||||||
src/core/libraries/ajm/ajm_mp3.cpp
|
src/core/libraries/ajm/ajm_mp3.cpp
|
||||||
@ -198,15 +200,16 @@ set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
|
|||||||
src/core/libraries/audio/audioin.h
|
src/core/libraries/audio/audioin.h
|
||||||
src/core/libraries/audio/audioout.cpp
|
src/core/libraries/audio/audioout.cpp
|
||||||
src/core/libraries/audio/audioout.h
|
src/core/libraries/audio/audioout.h
|
||||||
src/core/libraries/audio/sdl_audio.cpp
|
src/core/libraries/audio/audioout_backend.h
|
||||||
src/core/libraries/audio/sdl_audio.h
|
|
||||||
src/core/libraries/audio/audioout_error.h
|
src/core/libraries/audio/audioout_error.h
|
||||||
|
src/core/libraries/audio/sdl_audio.cpp
|
||||||
src/core/libraries/ngs2/ngs2.cpp
|
src/core/libraries/ngs2/ngs2.cpp
|
||||||
src/core/libraries/ngs2/ngs2.h
|
src/core/libraries/ngs2/ngs2.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
|
set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
|
||||||
src/core/libraries/gnmdriver/gnmdriver.h
|
src/core/libraries/gnmdriver/gnmdriver.h
|
||||||
|
src/core/libraries/gnmdriver/gnmdriver_init.h
|
||||||
src/core/libraries/gnmdriver/gnm_error.h
|
src/core/libraries/gnmdriver/gnm_error.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -333,6 +336,8 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
|||||||
src/core/libraries/share_play/shareplay.h
|
src/core/libraries/share_play/shareplay.h
|
||||||
src/core/libraries/razor_cpu/razor_cpu.cpp
|
src/core/libraries/razor_cpu/razor_cpu.cpp
|
||||||
src/core/libraries/razor_cpu/razor_cpu.h
|
src/core/libraries/razor_cpu/razor_cpu.h
|
||||||
|
src/core/libraries/mouse/mouse.cpp
|
||||||
|
src/core/libraries/mouse/mouse.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
||||||
@ -423,6 +428,8 @@ set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
|||||||
|
|
||||||
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||||
src/core/libraries/screenshot/screenshot.h
|
src/core/libraries/screenshot/screenshot.h
|
||||||
|
src/core/libraries/move/move.cpp
|
||||||
|
src/core/libraries/move/move.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||||
@ -517,7 +524,7 @@ set(COMMON src/common/logging/backend.cpp
|
|||||||
src/common/number_utils.cpp
|
src/common/number_utils.cpp
|
||||||
src/common/memory_patcher.h
|
src/common/memory_patcher.h
|
||||||
src/common/memory_patcher.cpp
|
src/common/memory_patcher.cpp
|
||||||
src/common/scm_rev.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp
|
||||||
src/common/scm_rev.h
|
src/common/scm_rev.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -694,6 +701,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||||||
src/shader_recompiler/ir/post_order.h
|
src/shader_recompiler/ir/post_order.h
|
||||||
src/shader_recompiler/ir/program.cpp
|
src/shader_recompiler/ir/program.cpp
|
||||||
src/shader_recompiler/ir/program.h
|
src/shader_recompiler/ir/program.h
|
||||||
|
src/shader_recompiler/ir/reinterpret.h
|
||||||
src/shader_recompiler/ir/reg.h
|
src/shader_recompiler/ir/reg.h
|
||||||
src/shader_recompiler/ir/type.cpp
|
src/shader_recompiler/ir/type.cpp
|
||||||
src/shader_recompiler/ir/type.h
|
src/shader_recompiler/ir/type.h
|
||||||
@ -907,11 +915,19 @@ endif()
|
|||||||
if (APPLE)
|
if (APPLE)
|
||||||
if (ENABLE_QT_GUI)
|
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.
|
# 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.
|
||||||
target_sources(shadps4 PRIVATE externals/MoltenVK/MoltenVK_icd.json)
|
set(MVK_ICD ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK_icd.json)
|
||||||
set_source_files_properties(externals/MoltenVK/MoltenVK_icd.json
|
target_sources(shadps4 PRIVATE ${MVK_ICD})
|
||||||
PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
|
set_source_files_properties(${MVK_ICD} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
|
||||||
add_custom_command(TARGET shadps4 POST_BUILD
|
|
||||||
COMMAND cmake -E copy $<TARGET_LINKER_FILE:MoltenVK> $<TARGET_BUNDLE_DIR:shadps4>/Contents/Frameworks/libMoltenVK.dylib)
|
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)
|
||||||
|
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})
|
||||||
|
add_dependencies(CopyMoltenVK MoltenVK)
|
||||||
|
add_dependencies(shadps4 CopyMoltenVK)
|
||||||
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
|
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
|
||||||
else()
|
else()
|
||||||
# For non-bundled SDL build, just do a normal library link.
|
# For non-bundled SDL build, just do a normal library link.
|
||||||
@ -1032,7 +1048,6 @@ install(TARGETS shadps4 BUNDLE DESTINATION .)
|
|||||||
|
|
||||||
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
install(FILES "dist/net.shadps4.shadPS4.desktop" DESTINATION "share/applications")
|
install(FILES "dist/net.shadps4.shadPS4.desktop" DESTINATION "share/applications")
|
||||||
install(FILES "dist/net.shadps4.shadPS4.releases.xml" DESTINATION "share/metainfo/releases")
|
|
||||||
install(FILES "dist/net.shadps4.shadPS4.metainfo.xml" DESTINATION "share/metainfo")
|
install(FILES "dist/net.shadps4.shadPS4.metainfo.xml" DESTINATION "share/metainfo")
|
||||||
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps" RENAME "net.shadps4.shadPS4.png")
|
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps" RENAME "net.shadps4.shadPS4.png")
|
||||||
install(FILES "src/images/net.shadps4.shadPS4.svg" DESTINATION "share/icons/hicolor/scalable/apps")
|
install(FILES "src/images/net.shadps4.shadPS4.svg" DESTINATION "share/icons/hicolor/scalable/apps")
|
||||||
|
@ -123,6 +123,11 @@ Keyboard and mouse inputs can be customized in the settings menu by clicking the
|
|||||||
- [**skmp**](https://github.com/skmp)
|
- [**skmp**](https://github.com/skmp)
|
||||||
- [**wheremyfoodat**](https://github.com/wheremyfoodat)
|
- [**wheremyfoodat**](https://github.com/wheremyfoodat)
|
||||||
- [**raziel1000**](https://github.com/raziel1000)
|
- [**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)
|
||||||
|
|
||||||
Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
|
Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ path = [
|
|||||||
"dist/net.shadps4.shadPS4.desktop",
|
"dist/net.shadps4.shadPS4.desktop",
|
||||||
"dist/net.shadps4.shadPS4_metadata.pot",
|
"dist/net.shadps4.shadPS4_metadata.pot",
|
||||||
"dist/net.shadps4.shadPS4.metainfo.xml",
|
"dist/net.shadps4.shadPS4.metainfo.xml",
|
||||||
"dist/net.shadps4.shadPS4.releases.xml",
|
|
||||||
"documents/changelog.md",
|
"documents/changelog.md",
|
||||||
"documents/Quickstart/2.png",
|
"documents/Quickstart/2.png",
|
||||||
"documents/Screenshots/*",
|
"documents/Screenshots/*",
|
||||||
|
27
dist/net.shadps4.shadPS4.metainfo.xml
vendored
27
dist/net.shadps4.shadPS4.metainfo.xml
vendored
@ -36,9 +36,30 @@
|
|||||||
<categories>
|
<categories>
|
||||||
<category translate="no">Game</category>
|
<category translate="no">Game</category>
|
||||||
</categories>
|
</categories>
|
||||||
<releases type="external" url="https://cdn.jsdelivr.net/gh/fpiesche/flatpak-builds/apps/net.shadps4.shadPS4/net.shadps4.shadPS4.releases.xml">
|
<releases>
|
||||||
<release version="v.0.4.0" date="2024-11-03">
|
<release version="0.5.0" date="2024-12-25">
|
||||||
<description></description>
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.5.0</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.4.0" date="2024-10-31">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.4.0</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.3.0" date="2024-09-23">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.3.0</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.2.0" date="2024-08-15">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.2.0</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.1.0" date="2024-07-01">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/0.1.0</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.0.3" date="2024-03-23">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.3</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.0.2" date="2023-10-21">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.2</url>
|
||||||
|
</release>
|
||||||
|
<release version="0.0.1" date="2024-09-29">
|
||||||
|
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.1</url>
|
||||||
</release>
|
</release>
|
||||||
</releases>
|
</releases>
|
||||||
<content_rating type="oars-1.1"/>
|
<content_rating type="oars-1.1"/>
|
||||||
|
23
dist/net.shadps4.shadPS4.releases.xml
vendored
23
dist/net.shadps4.shadPS4.releases.xml
vendored
@ -1,23 +0,0 @@
|
|||||||
<releases>
|
|
||||||
<release version="0.4.0" date="2024-10-31">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.4.0</url>
|
|
||||||
</release>
|
|
||||||
<release version="0.3.0" date="2024-09-23">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.3.0</url>
|
|
||||||
</release>
|
|
||||||
<release version="0.2.0" date="2024-08-15">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.2.0</url>
|
|
||||||
</release>
|
|
||||||
<release version="0.1.0" date="2024-07-01">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/0.1.0</url>
|
|
||||||
</release>
|
|
||||||
<release version="0.0.3" date="2024-03-23">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.3</url>
|
|
||||||
</release>
|
|
||||||
<release version="0.0.2" date="2023-10-21">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.2</url>
|
|
||||||
</release>
|
|
||||||
<release version="0.0.1" date="2024-09-29">
|
|
||||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v0.0.1</url>
|
|
||||||
</release>
|
|
||||||
</releases>
|
|
@ -64,7 +64,7 @@ Go through the Git for Windows installation as normal
|
|||||||
Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
|
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:
|
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\windeployqt.exe "C:\path\to\shadps4.exe"`
|
`C:\Qt\6.7.3\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
|
||||||
(Change Qt path if you've installed it to non-default path)
|
(Change Qt path if you've installed it to non-default path)
|
||||||
|
|
||||||
## Option 2: MSYS2/MinGW
|
## Option 2: MSYS2/MinGW
|
||||||
|
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
@ -213,9 +213,7 @@ endif()
|
|||||||
|
|
||||||
# Discord RPC
|
# Discord RPC
|
||||||
if (ENABLE_DISCORD_RPC)
|
if (ENABLE_DISCORD_RPC)
|
||||||
set(BUILD_EXAMPLES OFF)
|
|
||||||
add_subdirectory(discord-rpc)
|
add_subdirectory(discord-rpc)
|
||||||
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# GCN Headers
|
# GCN Headers
|
||||||
|
2
externals/MoltenVK/MoltenVK
vendored
2
externals/MoltenVK/MoltenVK
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 5ad3ee5d2f84342950c3fe93dec97719574d1932
|
Subproject commit 9f0b616d9e2c39464d2a859b79dbc655c4a30e7e
|
2
externals/discord-rpc
vendored
2
externals/discord-rpc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 4ec218155d73bcb8022f8f7ca72305d801f84beb
|
Subproject commit 51b09d426a4a1bcfa6ee6d4894e57d669f4a2e65
|
2
externals/sirit
vendored
2
externals/sirit
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 1e74f4ef8d2a0e3221a4de51977663f342b53c35
|
Subproject commit 26ad5a9d0fe13260b0d7d6c64419d01a196b2e32
|
@ -33,6 +33,7 @@ namespace Config {
|
|||||||
|
|
||||||
static bool isNeo = false;
|
static bool isNeo = false;
|
||||||
static bool isFullscreen = false;
|
static bool isFullscreen = false;
|
||||||
|
static std::string fullscreenMode = "borderless";
|
||||||
static bool playBGM = false;
|
static bool playBGM = false;
|
||||||
static bool isTrophyPopupDisabled = false;
|
static bool isTrophyPopupDisabled = false;
|
||||||
static int BGMvolume = 50;
|
static int BGMvolume = 50;
|
||||||
@ -47,6 +48,7 @@ static std::string updateChannel;
|
|||||||
static std::string backButtonBehavior = "left";
|
static std::string backButtonBehavior = "left";
|
||||||
static bool useSpecialPad = false;
|
static bool useSpecialPad = false;
|
||||||
static int specialPadClass = 1;
|
static int specialPadClass = 1;
|
||||||
|
static bool isMotionControlsEnabled = true;
|
||||||
static bool isDebugDump = false;
|
static bool isDebugDump = false;
|
||||||
static bool isShaderDebug = false;
|
static bool isShaderDebug = false;
|
||||||
static bool isShowSplash = false;
|
static bool isShowSplash = false;
|
||||||
@ -67,6 +69,7 @@ static int cursorHideTimeout = 5; // 5 seconds (default)
|
|||||||
static bool separateupdatefolder = false;
|
static bool separateupdatefolder = false;
|
||||||
static bool compatibilityData = false;
|
static bool compatibilityData = false;
|
||||||
static bool checkCompatibilityOnStartup = false;
|
static bool checkCompatibilityOnStartup = false;
|
||||||
|
static std::string trophyKey;
|
||||||
|
|
||||||
// Gui
|
// Gui
|
||||||
std::vector<std::filesystem::path> settings_install_dirs = {};
|
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||||
@ -91,14 +94,26 @@ std::string emulator_language = "en";
|
|||||||
// Language
|
// Language
|
||||||
u32 m_language = 1; // english
|
u32 m_language = 1; // english
|
||||||
|
|
||||||
bool isNeoMode() {
|
std::string getTrophyKey() {
|
||||||
|
return trophyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTrophyKey(std::string key) {
|
||||||
|
trophyKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNeoModeConsole() {
|
||||||
return isNeo;
|
return isNeo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFullscreenMode() {
|
bool getIsFullscreen() {
|
||||||
return isFullscreen;
|
return isFullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getFullscreenMode() {
|
||||||
|
return fullscreenMode;
|
||||||
|
}
|
||||||
|
|
||||||
bool getisTrophyPopupDisabled() {
|
bool getisTrophyPopupDisabled() {
|
||||||
return isTrophyPopupDisabled;
|
return isTrophyPopupDisabled;
|
||||||
}
|
}
|
||||||
@ -163,6 +178,10 @@ int getSpecialPadClass() {
|
|||||||
return specialPadClass;
|
return specialPadClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getIsMotionControlsEnabled() {
|
||||||
|
return isMotionControlsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
bool debugDump() {
|
bool debugDump() {
|
||||||
return isDebugDump;
|
return isDebugDump;
|
||||||
}
|
}
|
||||||
@ -295,10 +314,14 @@ void setVblankDiv(u32 value) {
|
|||||||
vblankDivider = value;
|
vblankDivider = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFullscreenMode(bool enable) {
|
void setIsFullscreen(bool enable) {
|
||||||
isFullscreen = enable;
|
isFullscreen = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setFullscreenMode(std::string mode) {
|
||||||
|
fullscreenMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
void setisTrophyPopupDisabled(bool disable) {
|
void setisTrophyPopupDisabled(bool disable) {
|
||||||
isTrophyPopupDisabled = disable;
|
isTrophyPopupDisabled = disable;
|
||||||
}
|
}
|
||||||
@ -359,6 +382,10 @@ void setSpecialPadClass(int type) {
|
|||||||
specialPadClass = type;
|
specialPadClass = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setIsMotionControlsEnabled(bool use) {
|
||||||
|
isMotionControlsEnabled = use;
|
||||||
|
}
|
||||||
|
|
||||||
void setSeparateUpdateEnabled(bool use) {
|
void setSeparateUpdateEnabled(bool use) {
|
||||||
separateupdatefolder = use;
|
separateupdatefolder = use;
|
||||||
}
|
}
|
||||||
@ -557,6 +584,7 @@ void load(const std::filesystem::path& path) {
|
|||||||
|
|
||||||
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
||||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
||||||
|
fullscreenMode = toml::find_or<std::string>(general, "FullscreenMode", "borderless");
|
||||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||||
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
|
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
|
||||||
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
||||||
@ -585,6 +613,7 @@ void load(const std::filesystem::path& path) {
|
|||||||
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
||||||
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
||||||
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
||||||
|
isMotionControlsEnabled = toml::find_or<bool>(input, "isMotionControlsEnabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.contains("GPU")) {
|
if (data.contains("GPU")) {
|
||||||
@ -652,6 +681,11 @@ void load(const std::filesystem::path& path) {
|
|||||||
|
|
||||||
m_language = toml::find_or<int>(settings, "consoleLanguage", 1);
|
m_language = toml::find_or<int>(settings, "consoleLanguage", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.contains("Keys")) {
|
||||||
|
const toml::value& keys = data.at("Keys");
|
||||||
|
trophyKey = toml::find_or<std::string>(keys, "TrophyKey", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void save(const std::filesystem::path& path) {
|
void save(const std::filesystem::path& path) {
|
||||||
@ -677,6 +711,7 @@ void save(const std::filesystem::path& path) {
|
|||||||
|
|
||||||
data["General"]["isPS4Pro"] = isNeo;
|
data["General"]["isPS4Pro"] = isNeo;
|
||||||
data["General"]["Fullscreen"] = isFullscreen;
|
data["General"]["Fullscreen"] = isFullscreen;
|
||||||
|
data["General"]["FullscreenMode"] = fullscreenMode;
|
||||||
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
|
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
|
||||||
data["General"]["playBGM"] = playBGM;
|
data["General"]["playBGM"] = playBGM;
|
||||||
data["General"]["BGMvolume"] = BGMvolume;
|
data["General"]["BGMvolume"] = BGMvolume;
|
||||||
@ -695,6 +730,7 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||||
data["Input"]["useSpecialPad"] = useSpecialPad;
|
data["Input"]["useSpecialPad"] = useSpecialPad;
|
||||||
data["Input"]["specialPadClass"] = specialPadClass;
|
data["Input"]["specialPadClass"] = specialPadClass;
|
||||||
|
data["Input"]["isMotionControlsEnabled"] = isMotionControlsEnabled;
|
||||||
data["GPU"]["screenWidth"] = screenWidth;
|
data["GPU"]["screenWidth"] = screenWidth;
|
||||||
data["GPU"]["screenHeight"] = screenHeight;
|
data["GPU"]["screenHeight"] = screenHeight;
|
||||||
data["GPU"]["nullGpu"] = isNullGpu;
|
data["GPU"]["nullGpu"] = isNullGpu;
|
||||||
@ -712,6 +748,8 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["Debug"]["DebugDump"] = isDebugDump;
|
data["Debug"]["DebugDump"] = isDebugDump;
|
||||||
data["Debug"]["CollectShader"] = isShaderDebug;
|
data["Debug"]["CollectShader"] = isShaderDebug;
|
||||||
|
|
||||||
|
data["Keys"]["TrophyKey"] = trophyKey;
|
||||||
|
|
||||||
std::vector<std::string> install_dirs;
|
std::vector<std::string> install_dirs;
|
||||||
for (const auto& dirString : settings_install_dirs) {
|
for (const auto& dirString : settings_install_dirs) {
|
||||||
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||||
|
@ -15,8 +15,11 @@ void load(const std::filesystem::path& path);
|
|||||||
void save(const std::filesystem::path& path);
|
void save(const std::filesystem::path& path);
|
||||||
void saveMainWindow(const std::filesystem::path& path);
|
void saveMainWindow(const std::filesystem::path& path);
|
||||||
|
|
||||||
bool isNeoMode();
|
std::string getTrophyKey();
|
||||||
bool isFullscreenMode();
|
void setTrophyKey(std::string key);
|
||||||
|
bool getIsFullscreen();
|
||||||
|
std::string getFullscreenMode();
|
||||||
|
bool isNeoModeConsole();
|
||||||
bool getPlayBGM();
|
bool getPlayBGM();
|
||||||
int getBGMvolume();
|
int getBGMvolume();
|
||||||
bool getisTrophyPopupDisabled();
|
bool getisTrophyPopupDisabled();
|
||||||
@ -35,6 +38,7 @@ int getCursorHideTimeout();
|
|||||||
std::string getBackButtonBehavior();
|
std::string getBackButtonBehavior();
|
||||||
bool getUseSpecialPad();
|
bool getUseSpecialPad();
|
||||||
int getSpecialPadClass();
|
int getSpecialPadClass();
|
||||||
|
bool getIsMotionControlsEnabled();
|
||||||
|
|
||||||
u32 getScreenWidth();
|
u32 getScreenWidth();
|
||||||
u32 getScreenHeight();
|
u32 getScreenHeight();
|
||||||
@ -62,7 +66,8 @@ void setVblankDiv(u32 value);
|
|||||||
void setGpuId(s32 selectedGpuId);
|
void setGpuId(s32 selectedGpuId);
|
||||||
void setScreenWidth(u32 width);
|
void setScreenWidth(u32 width);
|
||||||
void setScreenHeight(u32 height);
|
void setScreenHeight(u32 height);
|
||||||
void setFullscreenMode(bool enable);
|
void setIsFullscreen(bool enable);
|
||||||
|
void setFullscreenMode(std::string mode);
|
||||||
void setisTrophyPopupDisabled(bool disable);
|
void setisTrophyPopupDisabled(bool disable);
|
||||||
void setPlayBGM(bool enable);
|
void setPlayBGM(bool enable);
|
||||||
void setBGMvolume(int volume);
|
void setBGMvolume(int volume);
|
||||||
@ -81,6 +86,7 @@ void setCursorHideTimeout(int newcursorHideTimeout);
|
|||||||
void setBackButtonBehavior(const std::string& type);
|
void setBackButtonBehavior(const std::string& type);
|
||||||
void setUseSpecialPad(bool use);
|
void setUseSpecialPad(bool use);
|
||||||
void setSpecialPadClass(int type);
|
void setSpecialPadClass(int type);
|
||||||
|
void setIsMotionControlsEnabled(bool use);
|
||||||
|
|
||||||
void setLogType(const std::string& type);
|
void setLogType(const std::string& type);
|
||||||
void setLogFilter(const std::string& type);
|
void setLogFilter(const std::string& type);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "bit_field.h"
|
||||||
#include "singleton.h"
|
#include "singleton.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
@ -16,6 +17,46 @@ class Emulator;
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
union PSFAttributes {
|
||||||
|
/// Supports initial user's logout
|
||||||
|
BitField<0, 1, u32> support_initial_user_logout;
|
||||||
|
/// Enter button for the common dialog is cross.
|
||||||
|
BitField<1, 1, u32> enter_button_cross;
|
||||||
|
/// Warning dialog for PS Move is displayed in the options menu.
|
||||||
|
BitField<2, 1, u32> ps_move_warning;
|
||||||
|
/// Supports stereoscopic 3D.
|
||||||
|
BitField<3, 1, u32> support_stereoscopic_3d;
|
||||||
|
/// Suspends when PS button is pressed.
|
||||||
|
BitField<4, 1, u32> ps_button_suspend;
|
||||||
|
/// Enter button for the common dialog is assigned by the system software.
|
||||||
|
BitField<5, 1, u32> enter_button_system;
|
||||||
|
/// Overrides share menu behavior.
|
||||||
|
BitField<6, 1, u32> override_share_menu;
|
||||||
|
/// Suspends when PS button is pressed and special output resolution is set.
|
||||||
|
BitField<8, 1, u32> special_res_ps_button_suspend;
|
||||||
|
/// Enable HDCP.
|
||||||
|
BitField<9, 1, u32> enable_hdcp;
|
||||||
|
/// Disable HDCP for non-game.
|
||||||
|
BitField<10, 1, u32> disable_hdcp_non_game;
|
||||||
|
/// Supports PS VR.
|
||||||
|
BitField<14, 1, u32> support_ps_vr;
|
||||||
|
/// CPU mode (6 CPU)
|
||||||
|
BitField<15, 1, u32> six_cpu_mode;
|
||||||
|
/// CPU mode (7 CPU)
|
||||||
|
BitField<16, 1, u32> seven_cpu_mode;
|
||||||
|
/// Supports PS4 Pro (Neo) mode.
|
||||||
|
BitField<23, 1, u32> support_neo_mode;
|
||||||
|
/// Requires PS VR.
|
||||||
|
BitField<26, 1, u32> require_ps_vr;
|
||||||
|
/// Supports HDR.
|
||||||
|
BitField<29, 1, u32> support_hdr;
|
||||||
|
/// Display location.
|
||||||
|
BitField<31, 1, u32> display_location;
|
||||||
|
|
||||||
|
u32 raw{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PSFAttributes) == 4);
|
||||||
|
|
||||||
class ElfInfo {
|
class ElfInfo {
|
||||||
friend class Core::Emulator;
|
friend class Core::Emulator;
|
||||||
|
|
||||||
@ -26,6 +67,7 @@ class ElfInfo {
|
|||||||
std::string app_ver{};
|
std::string app_ver{};
|
||||||
u32 firmware_ver = 0;
|
u32 firmware_ver = 0;
|
||||||
u32 raw_firmware_ver = 0;
|
u32 raw_firmware_ver = 0;
|
||||||
|
PSFAttributes psf_attributes{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr u32 FW_15 = 0x1500000;
|
static constexpr u32 FW_15 = 0x1500000;
|
||||||
@ -34,6 +76,7 @@ public:
|
|||||||
static constexpr u32 FW_20 = 0x2000000;
|
static constexpr u32 FW_20 = 0x2000000;
|
||||||
static constexpr u32 FW_25 = 0x2500000;
|
static constexpr u32 FW_25 = 0x2500000;
|
||||||
static constexpr u32 FW_30 = 0x3000000;
|
static constexpr u32 FW_30 = 0x3000000;
|
||||||
|
static constexpr u32 FW_35 = 0x3500000;
|
||||||
static constexpr u32 FW_40 = 0x4000000;
|
static constexpr u32 FW_40 = 0x4000000;
|
||||||
static constexpr u32 FW_45 = 0x4500000;
|
static constexpr u32 FW_45 = 0x4500000;
|
||||||
static constexpr u32 FW_50 = 0x5000000;
|
static constexpr u32 FW_50 = 0x5000000;
|
||||||
@ -67,6 +110,11 @@ public:
|
|||||||
ASSERT(initialized);
|
ASSERT(initialized);
|
||||||
return raw_firmware_ver;
|
return raw_firmware_ver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const PSFAttributes& GetPSFAttributes() const {
|
||||||
|
ASSERT(initialized);
|
||||||
|
return psf_attributes;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
@ -97,6 +97,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||||||
SUB(Lib, Http) \
|
SUB(Lib, Http) \
|
||||||
SUB(Lib, Ssl) \
|
SUB(Lib, Ssl) \
|
||||||
SUB(Lib, SysModule) \
|
SUB(Lib, SysModule) \
|
||||||
|
SUB(Lib, Move) \
|
||||||
SUB(Lib, NpManager) \
|
SUB(Lib, NpManager) \
|
||||||
SUB(Lib, NpScore) \
|
SUB(Lib, NpScore) \
|
||||||
SUB(Lib, NpTrophy) \
|
SUB(Lib, NpTrophy) \
|
||||||
@ -125,6 +126,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||||||
SUB(Lib, Vdec2) \
|
SUB(Lib, Vdec2) \
|
||||||
SUB(Lib, Videodec) \
|
SUB(Lib, Videodec) \
|
||||||
SUB(Lib, RazorCpu) \
|
SUB(Lib, RazorCpu) \
|
||||||
|
SUB(Lib, Mouse) \
|
||||||
CLS(Frontend) \
|
CLS(Frontend) \
|
||||||
CLS(Render) \
|
CLS(Render) \
|
||||||
SUB(Render, Vulkan) \
|
SUB(Render, Vulkan) \
|
||||||
|
@ -57,8 +57,9 @@ enum class Class : u8 {
|
|||||||
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
|
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
|
||||||
Lib_AudioOut, ///< The LibSceAudioOut implementation.
|
Lib_AudioOut, ///< The LibSceAudioOut implementation.
|
||||||
Lib_AudioIn, ///< The LibSceAudioIn implementation.
|
Lib_AudioIn, ///< The LibSceAudioIn implementation.
|
||||||
|
Lib_Move, ///< The LibSceMove implementation.
|
||||||
Lib_Net, ///< The LibSceNet implementation.
|
Lib_Net, ///< The LibSceNet implementation.
|
||||||
Lib_NetCtl, ///< The LibSecNetCtl implementation.
|
Lib_NetCtl, ///< The LibSceNetCtl implementation.
|
||||||
Lib_SaveData, ///< The LibSceSaveData implementation.
|
Lib_SaveData, ///< The LibSceSaveData implementation.
|
||||||
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
|
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
|
||||||
Lib_Ssl, ///< The LibSceSsl implementation.
|
Lib_Ssl, ///< The LibSceSsl implementation.
|
||||||
@ -92,6 +93,7 @@ enum class Class : u8 {
|
|||||||
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
|
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
|
||||||
Lib_Videodec, ///< The LibSceVideodec implementation.
|
Lib_Videodec, ///< The LibSceVideodec implementation.
|
||||||
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
||||||
|
Lib_Mouse, ///< The LibSceMouse implementation
|
||||||
Frontend, ///< Emulator UI
|
Frontend, ///< Emulator UI
|
||||||
Render, ///< Video Core
|
Render, ///< Video Core
|
||||||
Render_Vulkan, ///< Vulkan backend
|
Render_Vulkan, ///< Vulkan backend
|
||||||
|
@ -4,11 +4,6 @@
|
|||||||
#include "common/native_clock.h"
|
#include "common/native_clock.h"
|
||||||
#include "common/rdtsc.h"
|
#include "common/rdtsc.h"
|
||||||
#include "common/uint128.h"
|
#include "common/uint128.h"
|
||||||
#ifdef _WIN64
|
|
||||||
#include <pthread_time.h>
|
|
||||||
#else
|
|
||||||
#include <time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
@ -34,10 +29,4 @@ u64 NativeClock::GetUptime() const {
|
|||||||
return FencedRDTSC();
|
return FencedRDTSC();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NativeClock::GetProcessTimeUS() const {
|
|
||||||
timespec ret;
|
|
||||||
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ret);
|
|
||||||
return ret.tv_nsec / 1000 + ret.tv_sec * 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
@ -20,7 +20,6 @@ public:
|
|||||||
u64 GetTimeUS(u64 base_ptc = 0) const;
|
u64 GetTimeUS(u64 base_ptc = 0) const;
|
||||||
u64 GetTimeMS(u64 base_ptc = 0) const;
|
u64 GetTimeMS(u64 base_ptc = 0) const;
|
||||||
u64 GetUptime() const;
|
u64 GetUptime() const;
|
||||||
u64 GetProcessTimeUS() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u64 rdtsc_frequency;
|
u64 rdtsc_frequency;
|
||||||
|
@ -26,7 +26,7 @@ asm(".zerofill GUEST_SYSTEM,GUEST_SYSTEM,__guest_system,0xFBFC00000");
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE_PRO;
|
static constexpr size_t BackingSize = SCE_KERNEL_TOTAL_MEM_PRO;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
|
||||||
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
|
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
|
||||||
@ -137,20 +138,20 @@ void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> NPcommID,
|
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, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
|
||||||
std::span<CryptoPP::byte> decrypted) {
|
std::span<CryptoPP::byte> decrypted) {
|
||||||
|
|
||||||
std::vector<CryptoPP::byte> TrophyKey = {0x21, 0xF4, 0x1A, 0x6B, 0xAD, 0x8A, 0x1D, 0x3E,
|
|
||||||
0xCA, 0x7A, 0xD5, 0x86, 0xC1, 0x01, 0xB7, 0xA9};
|
|
||||||
std::vector<CryptoPP::byte> TrophyIV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
// step 1: Encrypt NPcommID
|
// step 1: Encrypt NPcommID
|
||||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
|
||||||
encrypt.SetKeyWithIV(TrophyKey.data(), TrophyKey.size(), TrophyIV.data());
|
|
||||||
|
|
||||||
|
std::vector<CryptoPP::byte> trophyIv(16, 0);
|
||||||
std::vector<CryptoPP::byte> trpKey(16);
|
std::vector<CryptoPP::byte> trpKey(16);
|
||||||
|
|
||||||
|
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
|
||||||
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
|
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
|
||||||
|
|
||||||
// step 2: decrypt efsm.
|
// step 2: decrypt efsm.
|
||||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
|
||||||
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
|
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
|
||||||
|
@ -32,7 +32,8 @@ public:
|
|||||||
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
||||||
std::span<CryptoPP::byte> ciphertext,
|
std::span<CryptoPP::byte> ciphertext,
|
||||||
std::span<CryptoPP::byte> decrypted);
|
std::span<CryptoPP::byte> decrypted);
|
||||||
void decryptEFSM(std::span<CryptoPP::byte, 16>, std::span<CryptoPP::byte, 16> efsmIv,
|
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);
|
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
|
||||||
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
||||||
std::span<const CryptoPP::byte, 16> seed,
|
std::span<const CryptoPP::byte, 16> seed,
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "libraries/kernel/time.h"
|
#include "libraries/kernel/time.h"
|
||||||
#include "libraries/system/msgdialog.h"
|
#include "libraries/system/msgdialog.h"
|
||||||
#include "video_core/amdgpu/pm4_cmds.h"
|
#include "video_core/amdgpu/pm4_cmds.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||||
|
|
||||||
using namespace DebugStateType;
|
using namespace DebugStateType;
|
||||||
|
|
||||||
@ -168,8 +169,12 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
|||||||
if ((*dump)->regs.stage_enable.IsStageEnabled(i)) {
|
if ((*dump)->regs.stage_enable.IsStageEnabled(i)) {
|
||||||
auto stage = (*dump)->regs.ProgramForStage(i);
|
auto stage = (*dump)->regs.ProgramForStage(i);
|
||||||
if (stage->address_lo != 0) {
|
if (stage->address_lo != 0) {
|
||||||
|
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(stage->Address<u32*>());
|
||||||
auto code = stage->Code();
|
auto code = stage->Code();
|
||||||
(*dump)->stages[i] = PipelineShaderProgramDump{
|
(*dump)->stages[i] = PipelineShaderProgramDump{
|
||||||
|
.name = Vulkan::PipelineCache::GetShaderName(Shader::StageFromIndex(i),
|
||||||
|
info.shader_hash),
|
||||||
|
.hash = info.shader_hash,
|
||||||
.user_data = *stage,
|
.user_data = *stage,
|
||||||
.code = std::vector<u32>{code.begin(), code.end()},
|
.code = std::vector<u32>{code.begin(), code.end()},
|
||||||
};
|
};
|
||||||
@ -191,7 +196,10 @@ void DebugStateImpl::PushRegsDumpCompute(uintptr_t base_addr, uintptr_t header_a
|
|||||||
auto& cs = (*dump)->regs.cs_program;
|
auto& cs = (*dump)->regs.cs_program;
|
||||||
cs = cs_state;
|
cs = cs_state;
|
||||||
|
|
||||||
|
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(cs.Address<u32*>());
|
||||||
(*dump)->cs_data = PipelineComputerProgramDump{
|
(*dump)->cs_data = PipelineComputerProgramDump{
|
||||||
|
.name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, info.shader_hash),
|
||||||
|
.hash = info.shader_hash,
|
||||||
.cs_program = cs,
|
.cs_program = cs,
|
||||||
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
||||||
};
|
};
|
||||||
|
@ -50,11 +50,15 @@ struct QueueDump {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineShaderProgramDump {
|
struct PipelineShaderProgramDump {
|
||||||
|
std::string name;
|
||||||
|
u64 hash;
|
||||||
Vulkan::Liverpool::ShaderProgram user_data{};
|
Vulkan::Liverpool::ShaderProgram user_data{};
|
||||||
std::vector<u32> code{};
|
std::vector<u32> code{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineComputerProgramDump {
|
struct PipelineComputerProgramDump {
|
||||||
|
std::string name;
|
||||||
|
u64 hash;
|
||||||
Vulkan::Liverpool::ComputeProgram cs_program{};
|
Vulkan::Liverpool::ComputeProgram cs_program{};
|
||||||
std::vector<u32> code{};
|
std::vector<u32> code{};
|
||||||
};
|
};
|
||||||
|
@ -1174,7 +1174,7 @@ CmdListViewer::CmdListViewer(DebugStateType::FrameDump* _frame_dump,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdListViewer::Draw(bool only_batches_view) {
|
void CmdListViewer::Draw(bool only_batches_view, CmdListFilter& filter) {
|
||||||
const auto& ctx = *GetCurrentContext();
|
const auto& ctx = *GetCurrentContext();
|
||||||
|
|
||||||
if (batch_view.open) {
|
if (batch_view.open) {
|
||||||
@ -1285,6 +1285,41 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& batch = std::get<BatchInfo>(event);
|
auto& batch = std::get<BatchInfo>(event);
|
||||||
|
|
||||||
|
// filtering
|
||||||
|
{
|
||||||
|
bool remove = false;
|
||||||
|
|
||||||
|
if (filter.shader_name[0] != '\0') {
|
||||||
|
remove = true;
|
||||||
|
std::string_view shader_name{filter.shader_name};
|
||||||
|
const auto& data = frame_dump->regs.find(batch.command_addr);
|
||||||
|
if (data != frame_dump->regs.end()) {
|
||||||
|
DebugStateType::RegDump& dump = data->second;
|
||||||
|
if (dump.is_compute) {
|
||||||
|
if (dump.cs_data.name.contains(shader_name)) {
|
||||||
|
remove = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; ++i) {
|
||||||
|
if (dump.regs.stage_enable.IsStageEnabled(i)) {
|
||||||
|
auto& stage = dump.stages[i];
|
||||||
|
if (stage.name.contains(shader_name)) {
|
||||||
|
remove = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto const* pm4_hdr =
|
auto const* pm4_hdr =
|
||||||
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);
|
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);
|
||||||
|
|
||||||
|
@ -35,6 +35,10 @@ void ParseDepthControl(u32 value, bool begin_table = true);
|
|||||||
void ParseEqaa(u32 value, bool begin_table = true);
|
void ParseEqaa(u32 value, bool begin_table = true);
|
||||||
void ParseZInfo(u32 value, bool begin_table = true);
|
void ParseZInfo(u32 value, bool begin_table = true);
|
||||||
|
|
||||||
|
struct CmdListFilter {
|
||||||
|
char shader_name[128]{};
|
||||||
|
};
|
||||||
|
|
||||||
class CmdListViewer {
|
class CmdListViewer {
|
||||||
|
|
||||||
DebugStateType::FrameDump* frame_dump;
|
DebugStateType::FrameDump* frame_dump;
|
||||||
@ -70,7 +74,7 @@ public:
|
|||||||
explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list,
|
explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list,
|
||||||
uintptr_t base_addr = 0, std::string name = "");
|
uintptr_t base_addr = 0, std::string name = "");
|
||||||
|
|
||||||
void Draw(bool only_batches_view = false);
|
void Draw(bool only_batches_view, CmdListFilter& filter);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
||||||
|
@ -117,7 +117,7 @@ static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
|
|||||||
inline std::optional<std::string> exec_cli(const char* cli) {
|
inline std::optional<std::string> exec_cli(const char* cli) {
|
||||||
std::array<char, 64> buffer{};
|
std::array<char, 64> buffer{};
|
||||||
std::string output;
|
std::string output;
|
||||||
const auto f = popen(cli, "rt");
|
const auto f = popen(cli, "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
pclose(f);
|
pclose(f);
|
||||||
return {};
|
return {};
|
||||||
|
@ -132,6 +132,15 @@ void FrameDumpViewer::Draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndDisabled();
|
EndDisabled();
|
||||||
|
SameLine();
|
||||||
|
if (BeginMenu("Filter")) {
|
||||||
|
|
||||||
|
TextUnformatted("Shader name");
|
||||||
|
SameLine();
|
||||||
|
InputText("##filter_shader", filter.shader_name, sizeof(filter.shader_name));
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
TextEx("Submit num");
|
TextEx("Submit num");
|
||||||
SameLine();
|
SameLine();
|
||||||
@ -187,7 +196,7 @@ void FrameDumpViewer::Draw() {
|
|||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
if (is_showing && selected_cmd != -1) {
|
if (is_showing && selected_cmd != -1) {
|
||||||
cmd_list_viewer[selected_cmd].Draw(is_collapsed);
|
cmd_list_viewer[selected_cmd].Draw(is_collapsed, filter);
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ class FrameDumpViewer {
|
|||||||
s32 selected_queue_num2;
|
s32 selected_queue_num2;
|
||||||
s32 selected_cmd = -1;
|
s32 selected_cmd = -1;
|
||||||
|
|
||||||
|
CmdListFilter filter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
|
|
||||||
|
@ -19,6 +19,57 @@ constexpr float BAR_HEIGHT_MULT = 1.25f;
|
|||||||
constexpr float FRAME_GRAPH_PADDING_Y = 3.0f;
|
constexpr float FRAME_GRAPH_PADDING_Y = 3.0f;
|
||||||
constexpr static float FRAME_GRAPH_HEIGHT = 50.0f;
|
constexpr static float FRAME_GRAPH_HEIGHT = 50.0f;
|
||||||
|
|
||||||
|
void FrameGraph::DrawFrameGraph() {
|
||||||
|
// Frame graph - inspired by
|
||||||
|
// https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
||||||
|
const float full_width = GetContentRegionAvail().x;
|
||||||
|
auto pos = GetCursorScreenPos();
|
||||||
|
const ImVec2 size{full_width, FRAME_GRAPH_HEIGHT + FRAME_GRAPH_PADDING_Y * 2.0f};
|
||||||
|
ItemSize(size);
|
||||||
|
if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv());
|
||||||
|
float cur_pos_x = pos.x + full_width;
|
||||||
|
pos.y += FRAME_GRAPH_PADDING_Y;
|
||||||
|
const float final_pos_y = pos.y + FRAME_GRAPH_HEIGHT;
|
||||||
|
|
||||||
|
auto& draw_list = *GetWindowDrawList();
|
||||||
|
draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y},
|
||||||
|
{pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y},
|
||||||
|
IM_COL32(0x33, 0x33, 0x33, 0xFF));
|
||||||
|
draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true);
|
||||||
|
for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) {
|
||||||
|
const auto& frame_info = frame_list[(DebugState.GetFrameNum() - i) % FRAME_BUFFER_SIZE];
|
||||||
|
const float dt_factor = target_dt / frame_info.delta;
|
||||||
|
|
||||||
|
const float width = std::ceil(BAR_WIDTH_MULT / dt_factor);
|
||||||
|
const float height =
|
||||||
|
std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * FRAME_GRAPH_HEIGHT;
|
||||||
|
|
||||||
|
ImU32 color;
|
||||||
|
if (dt_factor >= 0.95f) { // BLUE
|
||||||
|
color = IM_COL32(0x33, 0x33, 0xFF, 0xFF);
|
||||||
|
} else if (dt_factor >= 0.5f) { // GREEN <> YELLOW
|
||||||
|
float t = 1.0f - (dt_factor - 0.5f) * 2.0f;
|
||||||
|
int r = (int)(0xFF * t);
|
||||||
|
color = IM_COL32(r, 0xFF, 0, 0xFF);
|
||||||
|
} else { // YELLOW <> RED
|
||||||
|
float t = dt_factor * 2.0f;
|
||||||
|
int g = (int)(0xFF * t);
|
||||||
|
color = IM_COL32(0xFF, g, 0, 0xFF);
|
||||||
|
}
|
||||||
|
draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height}, {cur_pos_x, final_pos_y},
|
||||||
|
color);
|
||||||
|
cur_pos_x -= width;
|
||||||
|
if (cur_pos_x < width) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_list.PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
void FrameGraph::Draw() {
|
void FrameGraph::Draw() {
|
||||||
if (!is_open) {
|
if (!is_open) {
|
||||||
return;
|
return;
|
||||||
@ -43,55 +94,9 @@ void FrameGraph::Draw() {
|
|||||||
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
|
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
|
||||||
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
|
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
|
||||||
DebugState.gnm_frame_count.load());
|
DebugState.gnm_frame_count.load());
|
||||||
|
|
||||||
SeparatorText("Frame graph");
|
SeparatorText("Frame graph");
|
||||||
|
DrawFrameGraph();
|
||||||
const float full_width = GetContentRegionAvail().x;
|
|
||||||
// Frame graph - inspired by
|
|
||||||
// https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
|
||||||
auto pos = GetCursorScreenPos();
|
|
||||||
const ImVec2 size{full_width, FRAME_GRAPH_HEIGHT + FRAME_GRAPH_PADDING_Y * 2.0f};
|
|
||||||
ItemSize(size);
|
|
||||||
if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv());
|
|
||||||
float cur_pos_x = pos.x + full_width;
|
|
||||||
pos.y += FRAME_GRAPH_PADDING_Y;
|
|
||||||
const float final_pos_y = pos.y + FRAME_GRAPH_HEIGHT;
|
|
||||||
|
|
||||||
draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y},
|
|
||||||
{pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y},
|
|
||||||
IM_COL32(0x33, 0x33, 0x33, 0xFF));
|
|
||||||
draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true);
|
|
||||||
for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) {
|
|
||||||
const auto& frame_info = frame_list[(DebugState.GetFrameNum() - i) % FRAME_BUFFER_SIZE];
|
|
||||||
const float dt_factor = target_dt / frame_info.delta;
|
|
||||||
|
|
||||||
const float width = std::ceil(BAR_WIDTH_MULT / dt_factor);
|
|
||||||
const float height =
|
|
||||||
std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * FRAME_GRAPH_HEIGHT;
|
|
||||||
|
|
||||||
ImU32 color;
|
|
||||||
if (dt_factor >= 0.95f) { // BLUE
|
|
||||||
color = IM_COL32(0x33, 0x33, 0xFF, 0xFF);
|
|
||||||
} else if (dt_factor >= 0.5f) { // GREEN <> YELLOW
|
|
||||||
float t = 1.0f - (dt_factor - 0.5f) * 2.0f;
|
|
||||||
int r = (int)(0xFF * t);
|
|
||||||
color = IM_COL32(r, 0xFF, 0, 0xFF);
|
|
||||||
} else { // YELLOW <> RED
|
|
||||||
float t = dt_factor * 2.0f;
|
|
||||||
int g = (int)(0xFF * t);
|
|
||||||
color = IM_COL32(0xFF, g, 0, 0xFF);
|
|
||||||
}
|
|
||||||
draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height},
|
|
||||||
{cur_pos_x, final_pos_y}, color);
|
|
||||||
cur_pos_x -= width;
|
|
||||||
if (cur_pos_x < width) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
draw_list.PopClipRect();
|
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ class FrameGraph {
|
|||||||
|
|
||||||
std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{};
|
std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{};
|
||||||
|
|
||||||
|
void DrawFrameGraph();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
|||||||
"GetColorSliceSize()", buffer.GetColorSliceSize(),
|
"GetColorSliceSize()", buffer.GetColorSliceSize(),
|
||||||
"GetTilingMode()", buffer.GetTilingMode(),
|
"GetTilingMode()", buffer.GetTilingMode(),
|
||||||
"IsTiled()", buffer.IsTiled(),
|
"IsTiled()", buffer.IsTiled(),
|
||||||
"NumFormat()", buffer.NumFormat()
|
"NumFormat()", buffer.GetNumberFmt()
|
||||||
);
|
);
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -292,6 +292,17 @@ void RegView::Draw() {
|
|||||||
EndMenuBar();
|
EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* shader_name = "_";
|
||||||
|
if (data.is_compute) {
|
||||||
|
shader_name = data.cs_data.name.c_str();
|
||||||
|
} else if (selected_shader >= 0) {
|
||||||
|
shader_name = data.stages[selected_shader].name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextUnformatted("Shader: ");
|
||||||
|
SameLine();
|
||||||
|
TextUnformatted(shader_name);
|
||||||
|
|
||||||
if (!data.is_compute &&
|
if (!data.is_compute &&
|
||||||
BeginChild("STAGES", {},
|
BeginChild("STAGES", {},
|
||||||
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) {
|
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) {
|
||||||
|
@ -112,6 +112,10 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
|
|||||||
ReloadShader(value);
|
ReloadShader(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SameLine();
|
||||||
|
if (Button("Copy name")) {
|
||||||
|
SetClipboardText(value.name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (value.is_patched) {
|
if (value.is_patched) {
|
||||||
if (BeginCombo("Shader type", showing_bin ? "SPIRV" : "GLSL",
|
if (BeginCombo("Shader type", showing_bin ? "SPIRV" : "GLSL",
|
||||||
@ -229,9 +233,16 @@ void ShaderList::Draw() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputTextEx("##search_shader", "Search by name", search_box, sizeof(search_box), {},
|
||||||
|
ImGuiInputTextFlags_None);
|
||||||
|
|
||||||
auto width = GetContentRegionAvail().x;
|
auto width = GetContentRegionAvail().x;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (const auto& shader : DebugState.shader_dump_list) {
|
for (const auto& shader : DebugState.shader_dump_list) {
|
||||||
|
if (search_box[0] != '\0' && !shader.name.contains(search_box)) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
char name[128];
|
char name[128];
|
||||||
if (shader.is_patched) {
|
if (shader.is_patched) {
|
||||||
snprintf(name, sizeof(name), "%s (PATCH ON)", shader.name.c_str());
|
snprintf(name, sizeof(name), "%s (PATCH ON)", shader.name.c_str());
|
||||||
|
@ -31,6 +31,8 @@ class ShaderList {
|
|||||||
|
|
||||||
std::vector<Selection> open_shaders{};
|
std::vector<Selection> open_shaders{};
|
||||||
|
|
||||||
|
char search_box[128]{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/config.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "trp.h"
|
#include "trp.h"
|
||||||
@ -33,12 +34,29 @@ static void removePadding(std::vector<u8>& vec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hexToBytes(const char* hex, unsigned char* dst) {
|
||||||
|
for (size_t i = 0; hex[i] != 0; i++) {
|
||||||
|
const unsigned char value = (hex[i] < 0x3A) ? (hex[i] - 0x30) : (hex[i] - 0x37);
|
||||||
|
dst[i / 2] |= ((i % 2) == 0) ? (value << 4) : (value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string titleId) {
|
bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string titleId) {
|
||||||
std::filesystem::path gameSysDir = trophyPath / "sce_sys/trophy/";
|
std::filesystem::path gameSysDir = trophyPath / "sce_sys/trophy/";
|
||||||
if (!std::filesystem::exists(gameSysDir)) {
|
if (!std::filesystem::exists(gameSysDir)) {
|
||||||
LOG_CRITICAL(Common_Filesystem, "Game sce_sys directory doesn't exist");
|
LOG_CRITICAL(Common_Filesystem, "Game sce_sys directory doesn't exist");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto user_key_str = Config::getTrophyKey();
|
||||||
|
if (user_key_str.size() != 32) {
|
||||||
|
LOG_CRITICAL(Common_Filesystem, "Trophy decryption key is not specified");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<CryptoPP::byte, 16> user_key{};
|
||||||
|
hexToBytes(user_key_str.c_str(), user_key.data());
|
||||||
|
|
||||||
for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) {
|
for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) {
|
||||||
if (it.is_regular_file()) {
|
if (it.is_regular_file()) {
|
||||||
GetNPcommID(trophyPath, index);
|
GetNPcommID(trophyPath, index);
|
||||||
@ -97,7 +115,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
file.Read(ESFM);
|
file.Read(ESFM);
|
||||||
crypto.decryptEFSM(np_comm_id, esfmIv, ESFM, XML); // decrypt
|
crypto.decryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
|
||||||
removePadding(XML);
|
removePadding(XML);
|
||||||
std::string xml_name = entry.entry_name;
|
std::string xml_name = entry.entry_name;
|
||||||
size_t pos = xml_name.find("ESFM");
|
size_t pos = xml_name.find("ESFM");
|
||||||
|
@ -40,7 +40,8 @@ void MntPoints::UnmountAll() {
|
|||||||
m_mnt_pairs.clear();
|
m_mnt_pairs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only) {
|
std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only,
|
||||||
|
bool force_base_path) {
|
||||||
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf
|
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf
|
||||||
std::string corrected_path(path);
|
std::string corrected_path(path);
|
||||||
size_t pos = corrected_path.find("//");
|
size_t pos = corrected_path.find("//");
|
||||||
@ -72,7 +73,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
|
|||||||
patch_path /= rel_path;
|
patch_path /= rel_path;
|
||||||
|
|
||||||
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&
|
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&
|
||||||
std::filesystem::exists(patch_path)) {
|
!force_base_path && std::filesystem::exists(patch_path)) {
|
||||||
return patch_path;
|
return patch_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +133,11 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
|
|||||||
return std::optional<std::filesystem::path>(current_path);
|
return std::optional<std::filesystem::path>(current_path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!force_base_path) {
|
||||||
if (const auto path = search(patch_path)) {
|
if (const auto path = search(patch_path)) {
|
||||||
return *path;
|
return *path;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (const auto path = search(host_path)) {
|
if (const auto path = search(host_path)) {
|
||||||
return *path;
|
return *path;
|
||||||
}
|
}
|
||||||
@ -144,6 +147,39 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
|
|||||||
return host_path;
|
return host_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Does not handle mount points inside mount points.
|
||||||
|
void MntPoints::IterateDirectory(std::string_view guest_directory,
|
||||||
|
const IterateDirectoryCallback& callback) {
|
||||||
|
const auto base_path = GetHostPath(guest_directory, nullptr, true);
|
||||||
|
const auto patch_path = GetHostPath(guest_directory, nullptr, false);
|
||||||
|
// Only need to consider patch path if it exists and does not resolve to the same as base.
|
||||||
|
const auto apply_patch = base_path != patch_path && std::filesystem::exists(patch_path);
|
||||||
|
|
||||||
|
// Pass 1: Any files that existed in the base directory, using patch directory if needed.
|
||||||
|
if (std::filesystem::exists(base_path)) {
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(base_path)) {
|
||||||
|
if (apply_patch) {
|
||||||
|
const auto patch_entry_path = patch_path / entry.path().filename();
|
||||||
|
if (std::filesystem::exists(patch_entry_path)) {
|
||||||
|
callback(patch_entry_path, !std::filesystem::is_directory(patch_entry_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback(entry.path(), !entry.is_directory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass 2: Any files that exist only in the patch directory.
|
||||||
|
if (apply_patch) {
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(patch_path)) {
|
||||||
|
const auto base_entry_path = base_path / entry.path().filename();
|
||||||
|
if (!std::filesystem::exists(base_entry_path)) {
|
||||||
|
callback(entry.path(), !entry.is_directory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int HandleTable::CreateHandle() {
|
int HandleTable::CreateHandle() {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
|
@ -36,7 +36,11 @@ public:
|
|||||||
void UnmountAll();
|
void UnmountAll();
|
||||||
|
|
||||||
std::filesystem::path GetHostPath(std::string_view guest_directory,
|
std::filesystem::path GetHostPath(std::string_view guest_directory,
|
||||||
bool* is_read_only = nullptr);
|
bool* is_read_only = nullptr, bool force_base_path = false);
|
||||||
|
using IterateDirectoryCallback =
|
||||||
|
std::function<void(const std::filesystem::path& host_path, bool is_file)>;
|
||||||
|
void IterateDirectory(std::string_view guest_directory,
|
||||||
|
const IterateDirectoryCallback& callback);
|
||||||
|
|
||||||
const MntPair* GetMountFromHostPath(const std::string& host_path) {
|
const MntPair* GetMountFromHostPath(const std::string& host_path) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
@ -183,13 +183,15 @@ int PS4_SYSV_ABI sceAjmInstanceSwitch() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmMemoryRegister() {
|
int PS4_SYSV_ABI sceAjmMemoryRegister(u32 context_id, void* ptr, size_t num_pages) {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
// All memory is already shared with our implementation since we do not use any hardware.
|
||||||
|
LOG_TRACE(Lib_Ajm, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmMemoryUnregister() {
|
int PS4_SYSV_ABI sceAjmMemoryUnregister(u32 context_id, void* ptr) {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
// All memory is already shared with our implementation since we do not use any hardware.
|
||||||
|
LOG_TRACE(Lib_Ajm, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,26 @@ union AjmJobFlags {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class AjmStatisticsFlags : u64 {
|
||||||
|
Memory = 1 << 0,
|
||||||
|
EnginePerCodec = 1 << 15,
|
||||||
|
Engine = 1 << 16,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(AjmStatisticsFlags)
|
||||||
|
|
||||||
|
union AjmStatisticsJobFlags {
|
||||||
|
AjmStatisticsJobFlags(AjmJobFlags job_flags) : raw(job_flags.raw) {}
|
||||||
|
|
||||||
|
u64 raw;
|
||||||
|
struct {
|
||||||
|
u64 version : 3;
|
||||||
|
u64 : 12;
|
||||||
|
AjmStatisticsFlags statistics_flags : 17;
|
||||||
|
u64 : 32;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(AjmStatisticsJobFlags) == 8);
|
||||||
|
|
||||||
struct AjmSidebandResult {
|
struct AjmSidebandResult {
|
||||||
s32 result;
|
s32 result;
|
||||||
s32 internal_result;
|
s32 internal_result;
|
||||||
@ -126,6 +146,31 @@ union AjmSidebandInitParameters {
|
|||||||
u8 reserved[8];
|
u8 reserved[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandStatisticsEngine {
|
||||||
|
float usage_batch;
|
||||||
|
float usage_interval[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandStatisticsEnginePerCodec {
|
||||||
|
u8 codec_count;
|
||||||
|
u8 codec_id[3];
|
||||||
|
float codec_percentage[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandStatisticsMemory {
|
||||||
|
u32 instance_free;
|
||||||
|
u32 buffer_free;
|
||||||
|
u32 batch_size;
|
||||||
|
u32 input_size;
|
||||||
|
u32 output_size;
|
||||||
|
u32 small_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandStatisticsEngineParameters {
|
||||||
|
u32 interval_count;
|
||||||
|
float interval[3];
|
||||||
|
};
|
||||||
|
|
||||||
union AjmInstanceFlags {
|
union AjmInstanceFlags {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
struct {
|
struct {
|
||||||
@ -178,8 +223,8 @@ int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmI
|
|||||||
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance);
|
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance);
|
||||||
int PS4_SYSV_ABI sceAjmInstanceExtend();
|
int PS4_SYSV_ABI sceAjmInstanceExtend();
|
||||||
int PS4_SYSV_ABI sceAjmInstanceSwitch();
|
int PS4_SYSV_ABI sceAjmInstanceSwitch();
|
||||||
int PS4_SYSV_ABI sceAjmMemoryRegister();
|
int PS4_SYSV_ABI sceAjmMemoryRegister(u32 context_id, void* ptr, size_t num_pages);
|
||||||
int PS4_SYSV_ABI sceAjmMemoryUnregister();
|
int PS4_SYSV_ABI sceAjmMemoryUnregister(u32 context_id, void* ptr);
|
||||||
int PS4_SYSV_ABI sceAjmModuleRegister(u32 context, AjmCodecType codec_type, s64 reserved);
|
int PS4_SYSV_ABI sceAjmModuleRegister(u32 context, AjmCodecType codec_type, s64 reserved);
|
||||||
int PS4_SYSV_ABI sceAjmModuleUnregister();
|
int PS4_SYSV_ABI sceAjmModuleUnregister();
|
||||||
int PS4_SYSV_ABI sceAjmStrError();
|
int PS4_SYSV_ABI sceAjmStrError();
|
||||||
|
@ -54,6 +54,8 @@ public:
|
|||||||
: m_p_begin(begin), m_p_current(m_p_begin), m_size(size) {}
|
: m_p_begin(begin), m_p_current(m_p_begin), m_size(size) {}
|
||||||
AjmBatchBuffer(std::span<u8> data)
|
AjmBatchBuffer(std::span<u8> data)
|
||||||
: m_p_begin(data.data()), m_p_current(m_p_begin), m_size(data.size()) {}
|
: m_p_begin(data.data()), m_p_current(m_p_begin), m_size(data.size()) {}
|
||||||
|
AjmBatchBuffer(AjmChunkBuffer& buffer)
|
||||||
|
: AjmBatchBuffer(reinterpret_cast<u8*>(buffer.p_address), buffer.size) {}
|
||||||
|
|
||||||
AjmBatchBuffer SubBuffer(size_t size = s_dynamic_extent) {
|
AjmBatchBuffer SubBuffer(size_t size = s_dynamic_extent) {
|
||||||
auto current = m_p_current;
|
auto current = m_p_current;
|
||||||
@ -113,6 +115,88 @@ private:
|
|||||||
size_t m_size{};
|
size_t m_size{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AjmJob AjmStatisticsJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
||||||
|
std::optional<AjmJobFlags> job_flags = {};
|
||||||
|
std::optional<AjmChunkBuffer> input_control_buffer = {};
|
||||||
|
std::optional<AjmChunkBuffer> output_control_buffer = {};
|
||||||
|
|
||||||
|
AjmJob job;
|
||||||
|
job.instance_id = instance_id;
|
||||||
|
|
||||||
|
while (!batch_buffer.IsEmpty()) {
|
||||||
|
auto& header = batch_buffer.Peek<AjmChunkHeader>();
|
||||||
|
switch (header.ident) {
|
||||||
|
case Identifier::AjmIdentInputControlBuf: {
|
||||||
|
ASSERT_MSG(!input_control_buffer.has_value(),
|
||||||
|
"Only one instance of input control buffer is allowed per job");
|
||||||
|
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
|
||||||
|
if (buffer.p_address != nullptr && buffer.size != 0) {
|
||||||
|
input_control_buffer = buffer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Identifier::AjmIdentControlFlags: {
|
||||||
|
ASSERT_MSG(!job_flags.has_value(), "Only one instance of job flags is allowed per job");
|
||||||
|
auto& chunk = batch_buffer.Consume<AjmChunkFlags>();
|
||||||
|
job_flags = AjmJobFlags{
|
||||||
|
.raw = (u64(chunk.header.payload) << 32) + chunk.flags_low,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Identifier::AjmIdentReturnAddressBuf: {
|
||||||
|
// Ignore return address buffers.
|
||||||
|
batch_buffer.Skip<AjmChunkBuffer>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Identifier::AjmIdentOutputControlBuf: {
|
||||||
|
ASSERT_MSG(!output_control_buffer.has_value(),
|
||||||
|
"Only one instance of output control buffer is allowed per job");
|
||||||
|
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
|
||||||
|
if (buffer.p_address != nullptr && buffer.size != 0) {
|
||||||
|
output_control_buffer = buffer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
UNREACHABLE_MSG("Unknown chunk: {}", header.ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(job_flags.has_value());
|
||||||
|
job.flags = job_flags.value();
|
||||||
|
|
||||||
|
AjmStatisticsJobFlags flags(job.flags);
|
||||||
|
if (input_control_buffer.has_value()) {
|
||||||
|
AjmBatchBuffer input_batch(input_control_buffer.value());
|
||||||
|
if (True(flags.statistics_flags & AjmStatisticsFlags::Engine)) {
|
||||||
|
job.input.statistics_engine_parameters =
|
||||||
|
input_batch.Consume<AjmSidebandStatisticsEngineParameters>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_control_buffer.has_value()) {
|
||||||
|
AjmBatchBuffer output_batch(output_control_buffer.value());
|
||||||
|
job.output.p_result = &output_batch.Consume<AjmSidebandResult>();
|
||||||
|
*job.output.p_result = AjmSidebandResult{};
|
||||||
|
|
||||||
|
if (True(flags.statistics_flags & AjmStatisticsFlags::Engine)) {
|
||||||
|
job.output.p_engine = &output_batch.Consume<AjmSidebandStatisticsEngine>();
|
||||||
|
*job.output.p_engine = AjmSidebandStatisticsEngine{};
|
||||||
|
}
|
||||||
|
if (True(flags.statistics_flags & AjmStatisticsFlags::EnginePerCodec)) {
|
||||||
|
job.output.p_engine_per_codec =
|
||||||
|
&output_batch.Consume<AjmSidebandStatisticsEnginePerCodec>();
|
||||||
|
*job.output.p_engine_per_codec = AjmSidebandStatisticsEnginePerCodec{};
|
||||||
|
}
|
||||||
|
if (True(flags.statistics_flags & AjmStatisticsFlags::Memory)) {
|
||||||
|
job.output.p_memory = &output_batch.Consume<AjmSidebandStatisticsMemory>();
|
||||||
|
*job.output.p_memory = AjmSidebandStatisticsMemory{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
||||||
std::optional<AjmJobFlags> job_flags = {};
|
std::optional<AjmJobFlags> job_flags = {};
|
||||||
std::optional<AjmChunkBuffer> input_control_buffer = {};
|
std::optional<AjmChunkBuffer> input_control_buffer = {};
|
||||||
@ -155,15 +239,6 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
|||||||
batch_buffer.Skip<AjmChunkBuffer>();
|
batch_buffer.Skip<AjmChunkBuffer>();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Identifier::AjmIdentInlineBuf: {
|
|
||||||
ASSERT_MSG(!output_control_buffer.has_value(),
|
|
||||||
"Only one instance of inline buffer is allowed per job");
|
|
||||||
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
|
|
||||||
if (buffer.p_address != nullptr && buffer.size != 0) {
|
|
||||||
inline_buffer = buffer;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Identifier::AjmIdentOutputRunBuf: {
|
case Identifier::AjmIdentOutputRunBuf: {
|
||||||
auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
|
auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
|
||||||
u8* p_begin = reinterpret_cast<u8*>(buffer.p_address);
|
u8* p_begin = reinterpret_cast<u8*>(buffer.p_address);
|
||||||
@ -186,13 +261,12 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT(job_flags.has_value());
|
||||||
job.flags = job_flags.value();
|
job.flags = job_flags.value();
|
||||||
|
|
||||||
// Initialize sideband input parameters
|
// Initialize sideband input parameters
|
||||||
if (input_control_buffer.has_value()) {
|
if (input_control_buffer.has_value()) {
|
||||||
AjmBatchBuffer input_batch(reinterpret_cast<u8*>(input_control_buffer->p_address),
|
AjmBatchBuffer input_batch(input_control_buffer.value());
|
||||||
input_control_buffer->size);
|
|
||||||
|
|
||||||
const auto sideband_flags = job_flags->sideband_flags;
|
const auto sideband_flags = job_flags->sideband_flags;
|
||||||
if (True(sideband_flags & AjmJobSidebandFlags::Format) && !input_batch.IsEmpty()) {
|
if (True(sideband_flags & AjmJobSidebandFlags::Format) && !input_batch.IsEmpty()) {
|
||||||
job.input.format = input_batch.Consume<AjmSidebandFormat>();
|
job.input.format = input_batch.Consume<AjmSidebandFormat>();
|
||||||
@ -202,6 +276,9 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto control_flags = job_flags.value().control_flags;
|
const auto control_flags = job_flags.value().control_flags;
|
||||||
|
if (True(control_flags & AjmJobControlFlags::Resample)) {
|
||||||
|
job.input.resample_parameters = input_batch.Consume<AjmSidebandResampleParameters>();
|
||||||
|
}
|
||||||
if (True(control_flags & AjmJobControlFlags::Initialize)) {
|
if (True(control_flags & AjmJobControlFlags::Initialize)) {
|
||||||
job.input.init_params = AjmDecAt9InitializeParameters{};
|
job.input.init_params = AjmDecAt9InitializeParameters{};
|
||||||
std::memcpy(&job.input.init_params.value(), input_batch.GetCurrent(),
|
std::memcpy(&job.input.init_params.value(), input_batch.GetCurrent(),
|
||||||
@ -209,21 +286,9 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inline_buffer.has_value()) {
|
|
||||||
AjmBatchBuffer inline_batch(reinterpret_cast<u8*>(inline_buffer->p_address),
|
|
||||||
inline_buffer->size);
|
|
||||||
|
|
||||||
const auto control_flags = job_flags.value().control_flags;
|
|
||||||
if (True(control_flags & AjmJobControlFlags::Resample)) {
|
|
||||||
job.input.resample_parameters = inline_batch.Consume<AjmSidebandResampleParameters>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize sideband output parameters
|
// Initialize sideband output parameters
|
||||||
if (output_control_buffer.has_value()) {
|
if (output_control_buffer.has_value()) {
|
||||||
AjmBatchBuffer output_batch(reinterpret_cast<u8*>(output_control_buffer->p_address),
|
AjmBatchBuffer output_batch(output_control_buffer.value());
|
||||||
output_control_buffer->size);
|
|
||||||
|
|
||||||
job.output.p_result = &output_batch.Consume<AjmSidebandResult>();
|
job.output.p_result = &output_batch.Consume<AjmSidebandResult>();
|
||||||
*job.output.p_result = AjmSidebandResult{};
|
*job.output.p_result = AjmSidebandResult{};
|
||||||
|
|
||||||
@ -260,9 +325,21 @@ std::shared_ptr<AjmBatch> AjmBatch::FromBatchBuffer(std::span<u8> data) {
|
|||||||
AjmBatchBuffer buffer(data);
|
AjmBatchBuffer buffer(data);
|
||||||
while (!buffer.IsEmpty()) {
|
while (!buffer.IsEmpty()) {
|
||||||
auto& job_chunk = buffer.Consume<AjmChunkJob>();
|
auto& job_chunk = buffer.Consume<AjmChunkJob>();
|
||||||
|
if (job_chunk.header.ident == AjmIdentInlineBuf) {
|
||||||
|
// Inline buffers are used to store sideband input data.
|
||||||
|
// We should just skip them as they do not require any special handling.
|
||||||
|
buffer.Advance(job_chunk.size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ASSERT(job_chunk.header.ident == AjmIdentJob);
|
ASSERT(job_chunk.header.ident == AjmIdentJob);
|
||||||
auto instance_id = job_chunk.header.payload;
|
auto instance_id = job_chunk.header.payload;
|
||||||
batch->jobs.push_back(AjmJobFromBatchBuffer(instance_id, buffer.SubBuffer(job_chunk.size)));
|
if (instance_id == AJM_INSTANCE_STATISTICS) {
|
||||||
|
batch->jobs.push_back(
|
||||||
|
AjmStatisticsJobFromBatchBuffer(instance_id, buffer.SubBuffer(job_chunk.size)));
|
||||||
|
} else {
|
||||||
|
batch->jobs.push_back(
|
||||||
|
AjmJobFromBatchBuffer(instance_id, buffer.SubBuffer(job_chunk.size)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return batch;
|
return batch;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <semaphore>
|
#include <semaphore>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -22,6 +23,7 @@ struct AjmJob {
|
|||||||
struct Input {
|
struct Input {
|
||||||
std::optional<AjmDecAt9InitializeParameters> init_params;
|
std::optional<AjmDecAt9InitializeParameters> init_params;
|
||||||
std::optional<AjmSidebandResampleParameters> resample_parameters;
|
std::optional<AjmSidebandResampleParameters> resample_parameters;
|
||||||
|
std::optional<AjmSidebandStatisticsEngineParameters> statistics_engine_parameters;
|
||||||
std::optional<AjmSidebandFormat> format;
|
std::optional<AjmSidebandFormat> format;
|
||||||
std::optional<AjmSidebandGaplessDecode> gapless_decode;
|
std::optional<AjmSidebandGaplessDecode> gapless_decode;
|
||||||
std::vector<u8> buffer;
|
std::vector<u8> buffer;
|
||||||
@ -32,6 +34,9 @@ struct AjmJob {
|
|||||||
AjmSidebandResult* p_result = nullptr;
|
AjmSidebandResult* p_result = nullptr;
|
||||||
AjmSidebandStream* p_stream = nullptr;
|
AjmSidebandStream* p_stream = nullptr;
|
||||||
AjmSidebandFormat* p_format = nullptr;
|
AjmSidebandFormat* p_format = nullptr;
|
||||||
|
AjmSidebandStatisticsMemory* p_memory = nullptr;
|
||||||
|
AjmSidebandStatisticsEnginePerCodec* p_engine_per_codec = nullptr;
|
||||||
|
AjmSidebandStatisticsEngine* p_engine = nullptr;
|
||||||
AjmSidebandGaplessDecode* p_gapless_decode = nullptr;
|
AjmSidebandGaplessDecode* p_gapless_decode = nullptr;
|
||||||
AjmSidebandMFrame* p_mframe = nullptr;
|
AjmSidebandMFrame* p_mframe = nullptr;
|
||||||
u8* p_codec_info = nullptr;
|
u8* p_codec_info = nullptr;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "core/libraries/ajm/ajm_context.h"
|
#include "core/libraries/ajm/ajm_context.h"
|
||||||
#include "core/libraries/ajm/ajm_error.h"
|
#include "core/libraries/ajm/ajm_error.h"
|
||||||
#include "core/libraries/ajm/ajm_instance.h"
|
#include "core/libraries/ajm/ajm_instance.h"
|
||||||
|
#include "core/libraries/ajm/ajm_instance_statistics.h"
|
||||||
#include "core/libraries/ajm/ajm_mp3.h"
|
#include "core/libraries/ajm/ajm_mp3.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
|
|
||||||
@ -70,6 +71,9 @@ void AjmContext::ProcessBatch(u32 id, std::span<AjmJob> jobs) {
|
|||||||
LOG_TRACE(Lib_Ajm, "Processing job {} for instance {}. flags = {:#x}", id, job.instance_id,
|
LOG_TRACE(Lib_Ajm, "Processing job {} for instance {}. flags = {:#x}", id, job.instance_id,
|
||||||
job.flags.raw);
|
job.flags.raw);
|
||||||
|
|
||||||
|
if (job.instance_id == AJM_INSTANCE_STATISTICS) {
|
||||||
|
AjmInstanceStatistics::Getinstance().ExecuteJob(job);
|
||||||
|
} else {
|
||||||
std::shared_ptr<AjmInstance> instance;
|
std::shared_ptr<AjmInstance> instance;
|
||||||
{
|
{
|
||||||
std::shared_lock lock(instances_mutex);
|
std::shared_lock lock(instances_mutex);
|
||||||
@ -80,6 +84,7 @@ void AjmContext::ProcessBatch(u32 id, std::span<AjmJob> jobs) {
|
|||||||
|
|
||||||
instance->ExecuteJob(job);
|
instance->ExecuteJob(job);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 AjmContext::BatchWait(const u32 batch_id, const u32 timeout, AjmBatchError* const batch_error) {
|
s32 AjmContext::BatchWait(const u32 batch_id, const u32 timeout, AjmBatchError* const batch_error) {
|
||||||
|
@ -68,11 +68,11 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
|||||||
m_codec->Initialize(¶ms, sizeof(params));
|
m_codec->Initialize(¶ms, sizeof(params));
|
||||||
}
|
}
|
||||||
if (job.input.resample_parameters.has_value()) {
|
if (job.input.resample_parameters.has_value()) {
|
||||||
UNREACHABLE_MSG("Unimplemented: resample parameters");
|
LOG_ERROR(Lib_Ajm, "Unimplemented: resample parameters");
|
||||||
m_resample_parameters = job.input.resample_parameters.value();
|
m_resample_parameters = job.input.resample_parameters.value();
|
||||||
}
|
}
|
||||||
if (job.input.format.has_value()) {
|
if (job.input.format.has_value()) {
|
||||||
UNREACHABLE_MSG("Unimplemented: format parameters");
|
LOG_ERROR(Lib_Ajm, "Unimplemented: format parameters");
|
||||||
m_format = job.input.format.value();
|
m_format = job.input.format.value();
|
||||||
}
|
}
|
||||||
if (job.input.gapless_decode.has_value()) {
|
if (job.input.gapless_decode.has_value()) {
|
||||||
|
37
src/core/libraries/ajm/ajm_instance_statistics.cpp
Normal file
37
src/core/libraries/ajm/ajm_instance_statistics.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "core/libraries/ajm/ajm.h"
|
||||||
|
#include "core/libraries/ajm/ajm_instance_statistics.h"
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
void AjmInstanceStatistics::ExecuteJob(AjmJob& job) {
|
||||||
|
if (job.output.p_engine) {
|
||||||
|
job.output.p_engine->usage_batch = 0.01;
|
||||||
|
const auto ic = job.input.statistics_engine_parameters->interval_count;
|
||||||
|
for (u32 idx = 0; idx < ic; ++idx) {
|
||||||
|
job.output.p_engine->usage_interval[idx] = 0.01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (job.output.p_engine_per_codec) {
|
||||||
|
job.output.p_engine_per_codec->codec_count = 1;
|
||||||
|
job.output.p_engine_per_codec->codec_id[0] = static_cast<u8>(AjmCodecType::At9Dec);
|
||||||
|
job.output.p_engine_per_codec->codec_percentage[0] = 0.01;
|
||||||
|
}
|
||||||
|
if (job.output.p_memory) {
|
||||||
|
job.output.p_memory->instance_free = 0x400000;
|
||||||
|
job.output.p_memory->buffer_free = 0x400000;
|
||||||
|
job.output.p_memory->batch_size = 0x4200;
|
||||||
|
job.output.p_memory->input_size = 0x2000;
|
||||||
|
job.output.p_memory->output_size = 0x2000;
|
||||||
|
job.output.p_memory->small_size = 0x200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AjmInstanceStatistics& AjmInstanceStatistics::Getinstance() {
|
||||||
|
static AjmInstanceStatistics instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
17
src/core/libraries/ajm/ajm_instance_statistics.h
Normal file
17
src/core/libraries/ajm/ajm_instance_statistics.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/libraries/ajm/ajm_batch.h"
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
class AjmInstanceStatistics {
|
||||||
|
public:
|
||||||
|
void ExecuteJob(AjmJob& job);
|
||||||
|
|
||||||
|
static AjmInstanceStatistics& Getinstance();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
@ -145,8 +145,10 @@ int PS4_SYSV_ABI sceAppContentDownloadDataFormat() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb() {
|
int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb(OrbisAppContentMountPoint* mountPoint,
|
||||||
|
u64* availableSpaceKb) {
|
||||||
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
|
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
|
||||||
|
*availableSpaceKb = 1048576;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,9 +296,9 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataFormat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb(
|
int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb(
|
||||||
const OrbisAppContentMountPoint* mountPoint, size_t* availableSpaceKb) {
|
const OrbisAppContentMountPoint* mountPoint, u64* availableSpaceKb) {
|
||||||
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
|
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
|
||||||
*availableSpaceKb = 1073741824;
|
*availableSpaceKb = 1048576;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,8 @@ int PS4_SYSV_ABI sceAppContentDownload0Shrink();
|
|||||||
int PS4_SYSV_ABI sceAppContentDownload1Expand();
|
int PS4_SYSV_ABI sceAppContentDownload1Expand();
|
||||||
int PS4_SYSV_ABI sceAppContentDownload1Shrink();
|
int PS4_SYSV_ABI sceAppContentDownload1Shrink();
|
||||||
int PS4_SYSV_ABI sceAppContentDownloadDataFormat();
|
int PS4_SYSV_ABI sceAppContentDownloadDataFormat();
|
||||||
int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb();
|
int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb(OrbisAppContentMountPoint* mountPoint,
|
||||||
|
u64* availableSpaceKb);
|
||||||
int PS4_SYSV_ABI sceAppContentGetAddcontDownloadProgress();
|
int PS4_SYSV_ABI sceAppContentGetAddcontDownloadProgress();
|
||||||
int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label,
|
int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label,
|
||||||
const OrbisNpUnifiedEntitlementLabel* entitlementLabel,
|
const OrbisNpUnifiedEntitlementLabel* entitlementLabel,
|
||||||
@ -105,7 +106,7 @@ int PS4_SYSV_ABI sceAppContentSmallSharedDataMount();
|
|||||||
int PS4_SYSV_ABI sceAppContentSmallSharedDataUnmount();
|
int PS4_SYSV_ABI sceAppContentSmallSharedDataUnmount();
|
||||||
int PS4_SYSV_ABI sceAppContentTemporaryDataFormat();
|
int PS4_SYSV_ABI sceAppContentTemporaryDataFormat();
|
||||||
int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb(
|
int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb(
|
||||||
const OrbisAppContentMountPoint* mountPoint, size_t* availableSpaceKb);
|
const OrbisAppContentMountPoint* mountPoint, u64* availableSpaceKb);
|
||||||
int PS4_SYSV_ABI sceAppContentTemporaryDataMount();
|
int PS4_SYSV_ABI sceAppContentTemporaryDataMount();
|
||||||
int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option,
|
int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option,
|
||||||
OrbisAppContentMountPoint* mountPoint);
|
OrbisAppContentMountPoint* mountPoint);
|
||||||
|
@ -3,140 +3,48 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <shared_mutex>
|
#include <stop_token>
|
||||||
|
#include <thread>
|
||||||
#include <magic_enum/magic_enum.hpp>
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/config.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/thread.h"
|
||||||
#include "core/libraries/audio/audioout.h"
|
#include "core/libraries/audio/audioout.h"
|
||||||
|
#include "core/libraries/audio/audioout_backend.h"
|
||||||
#include "core/libraries/audio/audioout_error.h"
|
#include "core/libraries/audio/audioout_error.h"
|
||||||
#include "core/libraries/audio/sdl_audio.h"
|
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
namespace Libraries::AudioOut {
|
namespace Libraries::AudioOut {
|
||||||
|
|
||||||
struct PortOut {
|
std::mutex port_open_mutex{};
|
||||||
void* impl;
|
|
||||||
u32 samples_num;
|
|
||||||
u32 freq;
|
|
||||||
OrbisAudioOutParamFormat format;
|
|
||||||
OrbisAudioOutPort type;
|
|
||||||
int channels_num;
|
|
||||||
bool is_float;
|
|
||||||
std::array<int, 8> volume;
|
|
||||||
u8 sample_size;
|
|
||||||
bool is_open;
|
|
||||||
};
|
|
||||||
std::shared_mutex ports_mutex;
|
|
||||||
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
|
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
|
||||||
|
|
||||||
static std::unique_ptr<AudioOutBackend> audio;
|
static std::unique_ptr<AudioOutBackend> audio;
|
||||||
|
|
||||||
static std::string_view GetAudioOutPort(OrbisAudioOutPort port) {
|
static AudioFormatInfo GetFormatInfo(const OrbisAudioOutParamFormat format) {
|
||||||
switch (port) {
|
static constexpr std::array<AudioFormatInfo, 8> format_infos = {{
|
||||||
case OrbisAudioOutPort::Main:
|
// S16Mono
|
||||||
return "MAIN";
|
{false, 2, 1, {0}},
|
||||||
case OrbisAudioOutPort::Bgm:
|
// S16Stereo
|
||||||
return "BGM";
|
{false, 2, 2, {0, 1}},
|
||||||
case OrbisAudioOutPort::Voice:
|
// S16_8CH
|
||||||
return "VOICE";
|
{false, 2, 8, {0, 1, 2, 3, 4, 5, 6, 7}},
|
||||||
case OrbisAudioOutPort::Personal:
|
// FloatMono
|
||||||
return "PERSONAL";
|
{true, 4, 1, {0}},
|
||||||
case OrbisAudioOutPort::Padspk:
|
// FloatStereo
|
||||||
return "PADSPK";
|
{true, 4, 2, {0, 1}},
|
||||||
case OrbisAudioOutPort::Aux:
|
// Float_8CH
|
||||||
return "AUX";
|
{true, 4, 8, {0, 1, 2, 3, 4, 5, 6, 7}},
|
||||||
default:
|
// S16_8CH_Std
|
||||||
return "INVALID";
|
{false, 2, 8, {0, 1, 2, 3, 6, 7, 4, 5}},
|
||||||
}
|
// Float_8CH_Std
|
||||||
}
|
{true, 4, 8, {0, 1, 2, 3, 6, 7, 4, 5}},
|
||||||
|
}};
|
||||||
static std::string_view GetAudioOutParamFormat(OrbisAudioOutParamFormat param) {
|
const auto index = static_cast<u32>(format);
|
||||||
switch (param) {
|
ASSERT_MSG(index < format_infos.size(), "Unknown audio format {}", index);
|
||||||
case OrbisAudioOutParamFormat::S16Mono:
|
return format_infos[index];
|
||||||
return "S16_MONO";
|
|
||||||
case OrbisAudioOutParamFormat::S16Stereo:
|
|
||||||
return "S16_STEREO";
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH:
|
|
||||||
return "S16_8CH";
|
|
||||||
case OrbisAudioOutParamFormat::FloatMono:
|
|
||||||
return "FLOAT_MONO";
|
|
||||||
case OrbisAudioOutParamFormat::FloatStereo:
|
|
||||||
return "FLOAT_STEREO";
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH:
|
|
||||||
return "FLOAT_8CH";
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH_Std:
|
|
||||||
return "S16_8CH_STD";
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH_Std:
|
|
||||||
return "FLOAT_8CH_STD";
|
|
||||||
default:
|
|
||||||
return "INVALID";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string_view GetAudioOutParamAttr(OrbisAudioOutParamAttr attr) {
|
|
||||||
switch (attr) {
|
|
||||||
case OrbisAudioOutParamAttr::None:
|
|
||||||
return "NONE";
|
|
||||||
case OrbisAudioOutParamAttr::Restricted:
|
|
||||||
return "RESTRICTED";
|
|
||||||
case OrbisAudioOutParamAttr::MixToMain:
|
|
||||||
return "MIX_TO_MAIN";
|
|
||||||
default:
|
|
||||||
return "INVALID";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsFormatFloat(const OrbisAudioOutParamFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case OrbisAudioOutParamFormat::S16Mono:
|
|
||||||
case OrbisAudioOutParamFormat::S16Stereo:
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH:
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH_Std:
|
|
||||||
return false;
|
|
||||||
case OrbisAudioOutParamFormat::FloatMono:
|
|
||||||
case OrbisAudioOutParamFormat::FloatStereo:
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH:
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH_Std:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
UNREACHABLE_MSG("Unknown format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int GetFormatNumChannels(const OrbisAudioOutParamFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case OrbisAudioOutParamFormat::S16Mono:
|
|
||||||
case OrbisAudioOutParamFormat::FloatMono:
|
|
||||||
return 1;
|
|
||||||
case OrbisAudioOutParamFormat::S16Stereo:
|
|
||||||
case OrbisAudioOutParamFormat::FloatStereo:
|
|
||||||
return 2;
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH:
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH:
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH_Std:
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH_Std:
|
|
||||||
return 8;
|
|
||||||
default:
|
|
||||||
UNREACHABLE_MSG("Unknown format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static u8 GetFormatSampleSize(const OrbisAudioOutParamFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case OrbisAudioOutParamFormat::S16Mono:
|
|
||||||
case OrbisAudioOutParamFormat::S16Stereo:
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH:
|
|
||||||
case OrbisAudioOutParamFormat::S16_8CH_Std:
|
|
||||||
return 2;
|
|
||||||
case OrbisAudioOutParamFormat::FloatMono:
|
|
||||||
case OrbisAudioOutParamFormat::FloatStereo:
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH:
|
|
||||||
case OrbisAudioOutParamFormat::Float_8CH_Std:
|
|
||||||
return 4;
|
|
||||||
default:
|
|
||||||
UNREACHABLE_MSG("Unknown format");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen() {
|
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen() {
|
||||||
@ -185,15 +93,20 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
|
|||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock lock(ports_mutex);
|
std::unique_lock open_lock{port_open_mutex};
|
||||||
auto& port = ports_out.at(handle - 1);
|
auto& port = ports_out.at(handle - 1);
|
||||||
if (!port.is_open) {
|
{
|
||||||
|
std::unique_lock lock{port.mutex};
|
||||||
|
if (!port.IsOpen()) {
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
std::free(port.output_buffer);
|
||||||
audio->Close(port.impl);
|
port.output_buffer = nullptr;
|
||||||
|
port.output_ready = false;
|
||||||
port.impl = nullptr;
|
port.impl = nullptr;
|
||||||
port.is_open = false;
|
}
|
||||||
|
// Stop outside of port lock scope to prevent deadlocks.
|
||||||
|
port.output_thread.Stop();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,21 +175,18 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
|||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock lock(ports_mutex);
|
auto& port = ports_out.at(handle - 1);
|
||||||
const auto& port = ports_out.at(handle - 1);
|
{
|
||||||
if (!port.is_open) {
|
std::unique_lock lock{port.mutex};
|
||||||
|
if (!port.IsOpen()) {
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->rerouteCounter = 0;
|
|
||||||
state->volume = 127;
|
|
||||||
|
|
||||||
switch (port.type) {
|
switch (port.type) {
|
||||||
case OrbisAudioOutPort::Main:
|
case OrbisAudioOutPort::Main:
|
||||||
case OrbisAudioOutPort::Bgm:
|
case OrbisAudioOutPort::Bgm:
|
||||||
case OrbisAudioOutPort::Voice:
|
case OrbisAudioOutPort::Voice:
|
||||||
state->output = 1;
|
state->output = 1;
|
||||||
state->channel = port.channels_num > 2 ? 2 : port.channels_num;
|
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
|
||||||
break;
|
break;
|
||||||
case OrbisAudioOutPort::Personal:
|
case OrbisAudioOutPort::Personal:
|
||||||
case OrbisAudioOutPort::Padspk:
|
case OrbisAudioOutPort::Padspk:
|
||||||
@ -290,7 +200,9 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
|||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
state->rerouteCounter = 0;
|
||||||
|
state->volume = 127;
|
||||||
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +270,31 @@ int PS4_SYSV_ABI sceAudioOutMbusInit() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AudioOutputThread(PortOut* port, const std::stop_token& stop) {
|
||||||
|
{
|
||||||
|
const auto thread_name = fmt::format("shadPS4:AudioOutputThread:{}", fmt::ptr(port));
|
||||||
|
Common::SetCurrentThreadName(thread_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::AccurateTimer timer(
|
||||||
|
std::chrono::nanoseconds(1000000000ULL * port->buffer_frames / port->sample_rate));
|
||||||
|
while (true) {
|
||||||
|
timer.Start();
|
||||||
|
{
|
||||||
|
std::unique_lock lock{port->mutex};
|
||||||
|
if (port->output_cv.wait(lock, stop, [&] { return port->output_ready; })) {
|
||||||
|
port->impl->Output(port->output_buffer);
|
||||||
|
port->output_ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port->output_cv.notify_one();
|
||||||
|
if (stop.stop_requested()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
timer.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
||||||
OrbisAudioOutPort port_type, s32 index, u32 length,
|
OrbisAudioOutPort port_type, s32 index, u32 length,
|
||||||
u32 sample_rate,
|
u32 sample_rate,
|
||||||
@ -365,9 +302,9 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||||||
LOG_INFO(Lib_AudioOut,
|
LOG_INFO(Lib_AudioOut,
|
||||||
"id = {} port_type = {} index = {} length = {} sample_rate = {} "
|
"id = {} port_type = {} index = {} length = {} sample_rate = {} "
|
||||||
"param_type = {} attr = {}",
|
"param_type = {} attr = {}",
|
||||||
user_id, GetAudioOutPort(port_type), index, length, sample_rate,
|
user_id, magic_enum::enum_name(port_type), index, length, sample_rate,
|
||||||
GetAudioOutParamFormat(param_type.data_format),
|
magic_enum::enum_name(param_type.data_format.Value()),
|
||||||
GetAudioOutParamAttr(param_type.attributes));
|
magic_enum::enum_name(param_type.attributes.Value()));
|
||||||
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
|
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
|
||||||
(port_type != OrbisAudioOutPort::Aux)) {
|
(port_type != OrbisAudioOutPort::Aux)) {
|
||||||
LOG_ERROR(Lib_AudioOut, "Invalid port type");
|
LOG_ERROR(Lib_AudioOut, "Invalid port type");
|
||||||
@ -398,24 +335,30 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock lock{ports_mutex};
|
std::unique_lock open_lock{port_open_mutex};
|
||||||
const auto port = std::ranges::find(ports_out, false, &PortOut::is_open);
|
const auto port =
|
||||||
|
std::ranges::find_if(ports_out, [&](const PortOut& p) { return !p.IsOpen(); });
|
||||||
if (port == ports_out.end()) {
|
if (port == ports_out.end()) {
|
||||||
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
|
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
|
||||||
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
|
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
port->is_open = true;
|
{
|
||||||
|
std::unique_lock port_lock(port->mutex);
|
||||||
|
|
||||||
port->type = port_type;
|
port->type = port_type;
|
||||||
port->samples_num = length;
|
port->format_info = GetFormatInfo(format);
|
||||||
port->freq = sample_rate;
|
port->sample_rate = sample_rate;
|
||||||
port->format = format;
|
port->buffer_frames = length;
|
||||||
port->is_float = IsFormatFloat(format);
|
|
||||||
port->channels_num = GetFormatNumChannels(format);
|
|
||||||
port->sample_size = GetFormatSampleSize(format);
|
|
||||||
port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
|
port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
|
||||||
|
|
||||||
port->impl = audio->Open(port->is_float, port->channels_num, port->freq);
|
port->impl = audio->Open(*port);
|
||||||
|
|
||||||
|
port->output_buffer = std::malloc(port->BufferSize());
|
||||||
|
port->output_ready = false;
|
||||||
|
port->output_thread.Run(
|
||||||
|
[port](const std::stop_token& stop) { AudioOutputThread(&*port, stop); });
|
||||||
|
}
|
||||||
return std::distance(ports_out.begin(), port) + 1;
|
return std::distance(ports_out.begin(), port) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,29 +367,33 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
|
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
if (ptr == nullptr) {
|
|
||||||
// Nothing to output
|
|
||||||
return ORBIS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& port = ports_out.at(handle - 1);
|
auto& port = ports_out.at(handle - 1);
|
||||||
if (!port.is_open) {
|
{
|
||||||
|
std::unique_lock lock{port.mutex};
|
||||||
|
if (!port.IsOpen()) {
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
port.output_cv.wait(lock, [&] { return !port.output_ready; });
|
||||||
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
if (ptr != nullptr && port.IsOpen()) {
|
||||||
audio->Output(port.impl, ptr, data_size);
|
std::memcpy(port.output_buffer, ptr, port.BufferSize());
|
||||||
|
port.output_ready = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.output_cv.notify_one();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) {
|
int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) {
|
||||||
for (u32 i = 0; i < num; i++) {
|
for (u32 i = 0; i < num; i++) {
|
||||||
if (const auto err = sceAudioOutOutput(param[i].handle, param[i].ptr); err != 0)
|
const auto [handle, ptr] = param[i];
|
||||||
return err;
|
if (const auto ret = sceAudioOutOutput(handle, ptr); ret != ORBIS_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
@ -546,40 +493,19 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
|||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock lock(ports_mutex);
|
|
||||||
auto& port = ports_out.at(handle - 1);
|
auto& port = ports_out.at(handle - 1);
|
||||||
if (!port.is_open) {
|
{
|
||||||
|
std::unique_lock lock{port.mutex};
|
||||||
|
if (!port.IsOpen()) {
|
||||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < port.format_info.num_channels; i++, flag >>= 1u) {
|
||||||
for (int i = 0; i < port.channels_num; i++, flag >>= 1u) {
|
if (flag & 0x1u) {
|
||||||
auto bit = flag & 0x1u;
|
port.volume[i] = vol[i];
|
||||||
if (bit == 1) {
|
|
||||||
int src_index = i;
|
|
||||||
if (port.format == OrbisAudioOutParamFormat::Float_8CH_Std ||
|
|
||||||
port.format == OrbisAudioOutParamFormat::S16_8CH_Std) {
|
|
||||||
switch (i) {
|
|
||||||
case 4:
|
|
||||||
src_index = 6;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
src_index = 7;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
src_index = 4;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
src_index = 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
port.volume[i] = vol[src_index];
|
port.impl->SetVolume(port.volume);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
audio->SetVolume(port.impl, port.volume);
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,20 +3,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "common/bit_field.h"
|
||||||
|
#include "core/libraries/kernel/threads.h"
|
||||||
#include "core/libraries/system/userservice.h"
|
#include "core/libraries/system/userservice.h"
|
||||||
|
|
||||||
namespace Libraries::AudioOut {
|
namespace Libraries::AudioOut {
|
||||||
|
|
||||||
|
class PortBackend;
|
||||||
|
|
||||||
// Main up to 8 ports, BGM 1 port, voice up to 4 ports,
|
// Main up to 8 ports, BGM 1 port, voice up to 4 ports,
|
||||||
// personal up to 4 ports, padspk up to 5 ports, aux 1 port
|
// personal up to 4 ports, padspk up to 5 ports, aux 1 port
|
||||||
constexpr int SCE_AUDIO_OUT_NUM_PORTS = 22;
|
constexpr s32 SCE_AUDIO_OUT_NUM_PORTS = 22;
|
||||||
constexpr int SCE_AUDIO_OUT_VOLUME_0DB = 32768; // max volume value
|
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, Aux = 127 };
|
||||||
|
|
||||||
enum class OrbisAudioOutParamFormat {
|
enum class OrbisAudioOutParamFormat : u32 {
|
||||||
S16Mono = 0,
|
S16Mono = 0,
|
||||||
S16Stereo = 1,
|
S16Stereo = 1,
|
||||||
S16_8CH = 2,
|
S16_8CH = 2,
|
||||||
@ -27,7 +33,7 @@ enum class OrbisAudioOutParamFormat {
|
|||||||
Float_8CH_Std = 7
|
Float_8CH_Std = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OrbisAudioOutParamAttr {
|
enum class OrbisAudioOutParamAttr : u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Restricted = 1,
|
Restricted = 1,
|
||||||
MixToMain = 2,
|
MixToMain = 2,
|
||||||
@ -43,7 +49,7 @@ union OrbisAudioOutParamExtendedInformation {
|
|||||||
|
|
||||||
struct OrbisAudioOutOutputParam {
|
struct OrbisAudioOutOutputParam {
|
||||||
s32 handle;
|
s32 handle;
|
||||||
const void* ptr;
|
void* ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisAudioOutPortState {
|
struct OrbisAudioOutPortState {
|
||||||
@ -56,6 +62,43 @@ struct OrbisAudioOutPortState {
|
|||||||
u64 reserved64[2];
|
u64 reserved64[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AudioFormatInfo {
|
||||||
|
bool is_float;
|
||||||
|
u8 sample_size;
|
||||||
|
u8 num_channels;
|
||||||
|
/// Layout array remapping channel indices, specified in this order:
|
||||||
|
/// FL, FR, FC, LFE, BL, BR, SL, SR
|
||||||
|
std::array<int, 8> channel_layout;
|
||||||
|
|
||||||
|
[[nodiscard]] u16 FrameSize() const {
|
||||||
|
return sample_size * num_channels;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortOut {
|
||||||
|
std::mutex mutex;
|
||||||
|
std::unique_ptr<PortBackend> impl{};
|
||||||
|
|
||||||
|
void* output_buffer;
|
||||||
|
std::condition_variable_any output_cv;
|
||||||
|
bool output_ready;
|
||||||
|
Kernel::Thread output_thread{};
|
||||||
|
|
||||||
|
OrbisAudioOutPort type;
|
||||||
|
AudioFormatInfo format_info;
|
||||||
|
u32 sample_rate;
|
||||||
|
u32 buffer_frames;
|
||||||
|
std::array<s32, 8> volume;
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsOpen() const {
|
||||||
|
return impl != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] u32 BufferSize() const {
|
||||||
|
return buffer_frames * format_info.FrameSize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
|
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
|
||||||
int PS4_SYSV_ABI sceAudioDeviceControlGet();
|
int PS4_SYSV_ABI sceAudioDeviceControlGet();
|
||||||
int PS4_SYSV_ABI sceAudioDeviceControlSet();
|
int PS4_SYSV_ABI sceAudioDeviceControlSet();
|
||||||
@ -94,7 +137,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||||||
OrbisAudioOutPort port_type, s32 index, u32 length,
|
OrbisAudioOutPort port_type, s32 index, u32 length,
|
||||||
u32 sample_rate, OrbisAudioOutParamExtendedInformation param_type);
|
u32 sample_rate, OrbisAudioOutParamExtendedInformation param_type);
|
||||||
int PS4_SYSV_ABI sceAudioOutOpenEx();
|
int PS4_SYSV_ABI sceAudioOutOpenEx();
|
||||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr);
|
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr);
|
||||||
s32 PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num);
|
s32 PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num);
|
||||||
int PS4_SYSV_ABI sceAudioOutPtClose();
|
int PS4_SYSV_ABI sceAudioOutPtClose();
|
||||||
int PS4_SYSV_ABI sceAudioOutPtGetLastOutputTime();
|
int PS4_SYSV_ABI sceAudioOutPtGetLastOutputTime();
|
||||||
|
@ -5,15 +5,30 @@
|
|||||||
|
|
||||||
namespace Libraries::AudioOut {
|
namespace Libraries::AudioOut {
|
||||||
|
|
||||||
|
struct PortOut;
|
||||||
|
|
||||||
|
class PortBackend {
|
||||||
|
public:
|
||||||
|
virtual ~PortBackend() = default;
|
||||||
|
|
||||||
|
/// Guaranteed to be called in intervals of at least port buffer time,
|
||||||
|
/// with size equal to port buffer size.
|
||||||
|
virtual void Output(void* ptr) = 0;
|
||||||
|
|
||||||
|
virtual void SetVolume(const std::array<int, 8>& ch_volumes) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class AudioOutBackend {
|
class AudioOutBackend {
|
||||||
public:
|
public:
|
||||||
AudioOutBackend() = default;
|
AudioOutBackend() = default;
|
||||||
virtual ~AudioOutBackend() = default;
|
virtual ~AudioOutBackend() = default;
|
||||||
|
|
||||||
virtual void* Open(bool is_float, int num_channels, u32 sample_rate) = 0;
|
virtual std::unique_ptr<PortBackend> Open(PortOut& port) = 0;
|
||||||
virtual void Close(void* impl) = 0;
|
};
|
||||||
virtual void Output(void* impl, const void* ptr, size_t size) = 0;
|
|
||||||
virtual void SetVolume(void* impl, std::array<int, 8> ch_volumes) = 0;
|
class SDLAudioOut final : public AudioOutBackend {
|
||||||
|
public:
|
||||||
|
std::unique_ptr<PortBackend> Open(PortOut& port) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Libraries::AudioOut
|
} // namespace Libraries::AudioOut
|
||||||
|
@ -1,44 +1,118 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
#include <SDL3/SDL_audio.h>
|
#include <SDL3/SDL_audio.h>
|
||||||
#include <SDL3/SDL_init.h>
|
#include <SDL3/SDL_hints.h>
|
||||||
#include <SDL3/SDL_timer.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/audio/sdl_audio.h"
|
#include "core/libraries/audio/audioout.h"
|
||||||
|
#include "core/libraries/audio/audioout_backend.h"
|
||||||
|
|
||||||
namespace Libraries::AudioOut {
|
namespace Libraries::AudioOut {
|
||||||
|
|
||||||
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
|
class SDLPortBackend : public PortBackend {
|
||||||
|
public:
|
||||||
void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) {
|
explicit SDLPortBackend(const PortOut& port)
|
||||||
SDL_AudioSpec fmt;
|
: frame_size(port.format_info.FrameSize()), guest_buffer_size(port.BufferSize()) {
|
||||||
SDL_zero(fmt);
|
const SDL_AudioSpec fmt = {
|
||||||
fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16;
|
.format = port.format_info.is_float ? SDL_AUDIO_F32LE : SDL_AUDIO_S16LE,
|
||||||
fmt.channels = num_channels;
|
.channels = port.format_info.num_channels,
|
||||||
fmt.freq = sample_rate;
|
.freq = static_cast<int>(port.sample_rate),
|
||||||
|
};
|
||||||
auto* stream =
|
stream =
|
||||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
|
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
|
||||||
SDL_ResumeAudioStreamDevice(stream);
|
if (stream == nullptr) {
|
||||||
return stream;
|
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
void SDLAudioOut::Close(void* impl) {
|
CalculateQueueThreshold();
|
||||||
SDL_DestroyAudioStream(static_cast<SDL_AudioStream*>(impl));
|
if (!SDL_SetAudioStreamInputChannelMap(stream, port.format_info.channel_layout.data(),
|
||||||
}
|
port.format_info.num_channels)) {
|
||||||
|
LOG_ERROR(Lib_AudioOut, "Failed to configure SDL audio stream channel map: {}",
|
||||||
void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) {
|
SDL_GetError());
|
||||||
auto* stream = static_cast<SDL_AudioStream*>(impl);
|
SDL_DestroyAudioStream(stream);
|
||||||
SDL_PutAudioStreamData(stream, ptr, size);
|
stream = nullptr;
|
||||||
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
return;
|
||||||
SDL_Delay(0);
|
}
|
||||||
|
if (!SDL_ResumeAudioStreamDevice(stream)) {
|
||||||
|
LOG_ERROR(Lib_AudioOut, "Failed to resume SDL audio stream: {}", SDL_GetError());
|
||||||
|
SDL_DestroyAudioStream(stream);
|
||||||
|
stream = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void SDLAudioOut::SetVolume(void* impl, std::array<int, 8> ch_volumes) {
|
~SDLPortBackend() override {
|
||||||
// Not yet implemented
|
if (!stream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDL_DestroyAudioStream(stream);
|
||||||
|
stream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Output(void* ptr) override {
|
||||||
|
if (!stream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// AudioOut library manages timing, but we still need to guard against the SDL
|
||||||
|
// audio queue stalling, which may happen during device changes, for example.
|
||||||
|
// Otherwise, latency may grow over time unbounded.
|
||||||
|
if (const auto queued = SDL_GetAudioStreamQueued(stream); queued >= queue_threshold) {
|
||||||
|
LOG_WARNING(Lib_AudioOut,
|
||||||
|
"SDL audio queue backed up ({} queued, {} threshold), clearing.", queued,
|
||||||
|
queue_threshold);
|
||||||
|
SDL_ClearAudioStream(stream);
|
||||||
|
// Recalculate the threshold in case this happened because of a device change.
|
||||||
|
CalculateQueueThreshold();
|
||||||
|
}
|
||||||
|
if (!SDL_PutAudioStreamData(stream, ptr, static_cast<int>(guest_buffer_size))) {
|
||||||
|
LOG_ERROR(Lib_AudioOut, "Failed to output to SDL audio stream: {}", SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVolume(const std::array<int, 8>& ch_volumes) override {
|
||||||
|
if (!stream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// SDL does not have per-channel volumes, for now just take the maximum of the channels.
|
||||||
|
const auto vol = *std::ranges::max_element(ch_volumes);
|
||||||
|
if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) {
|
||||||
|
LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}",
|
||||||
|
SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CalculateQueueThreshold() {
|
||||||
|
SDL_AudioSpec discard;
|
||||||
|
int sdl_buffer_frames;
|
||||||
|
if (!SDL_GetAudioDeviceFormat(SDL_GetAudioStreamDevice(stream), &discard,
|
||||||
|
&sdl_buffer_frames)) {
|
||||||
|
LOG_WARNING(Lib_AudioOut, "Failed to get SDL audio stream buffer size: {}",
|
||||||
|
SDL_GetError());
|
||||||
|
sdl_buffer_frames = 0;
|
||||||
|
}
|
||||||
|
const auto sdl_buffer_size = sdl_buffer_frames * frame_size;
|
||||||
|
const auto new_threshold = std::max(guest_buffer_size, sdl_buffer_size) * 4;
|
||||||
|
if (host_buffer_size != sdl_buffer_size || queue_threshold != new_threshold) {
|
||||||
|
host_buffer_size = sdl_buffer_size;
|
||||||
|
queue_threshold = new_threshold;
|
||||||
|
LOG_INFO(Lib_AudioOut,
|
||||||
|
"SDL audio buffers: guest = {} bytes, host = {} bytes, threshold = {} bytes",
|
||||||
|
guest_buffer_size, host_buffer_size, queue_threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 frame_size;
|
||||||
|
u32 guest_buffer_size;
|
||||||
|
u32 host_buffer_size{};
|
||||||
|
u32 queue_threshold{};
|
||||||
|
SDL_AudioStream* stream{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<PortBackend> SDLAudioOut::Open(PortOut& port) {
|
||||||
|
return std::make_unique<SDLPortBackend>(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::AudioOut
|
} // namespace Libraries::AudioOut
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/libraries/audio/audioout_backend.h"
|
|
||||||
|
|
||||||
namespace Libraries::AudioOut {
|
|
||||||
|
|
||||||
class SDLAudioOut final : public AudioOutBackend {
|
|
||||||
public:
|
|
||||||
void* Open(bool is_float, int num_channels, u32 sample_rate) override;
|
|
||||||
void Close(void* impl) override;
|
|
||||||
void Output(void* impl, const void* ptr, size_t size) override;
|
|
||||||
void SetVolume(void* impl, std::array<int, 8> ch_volumes) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Libraries::AudioOut
|
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "fiber.h"
|
#include "fiber.h"
|
||||||
|
|
||||||
|
#include "common/elf_info.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/fiber/fiber_error.h"
|
#include "core/libraries/fiber/fiber_error.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
@ -41,6 +42,41 @@ void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI _sceFiberAttachContext(OrbisFiber* fiber, void* addr_context, u64 size_context) {
|
||||||
|
if (size_context && size_context < ORBIS_FIBER_CONTEXT_MINIMUM_SIZE) {
|
||||||
|
return ORBIS_FIBER_ERROR_RANGE;
|
||||||
|
}
|
||||||
|
if (size_context & 15) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (!addr_context || !size_context) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (fiber->addr_context) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiber->addr_context = addr_context;
|
||||||
|
fiber->size_context = size_context;
|
||||||
|
fiber->context_start = addr_context;
|
||||||
|
fiber->context_end = reinterpret_cast<u8*>(addr_context) + size_context;
|
||||||
|
|
||||||
|
/* Apply signature to start of stack */
|
||||||
|
*(u64*)addr_context = kFiberStackSignature;
|
||||||
|
|
||||||
|
if (fiber->flags & FiberFlags::ContextSizeCheck) {
|
||||||
|
u64* stack_start = reinterpret_cast<u64*>(fiber->context_start);
|
||||||
|
u64* stack_end = reinterpret_cast<u64*>(fiber->context_end);
|
||||||
|
|
||||||
|
u64* stack_ptr = stack_start + 1;
|
||||||
|
while (stack_ptr < stack_end) {
|
||||||
|
*stack_ptr++ = kFiberStackSizeCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to,
|
void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to,
|
||||||
OrbisFiberContext* ctx) {
|
OrbisFiberContext* ctx) {
|
||||||
OrbisFiberContext* fiber_ctx = fiber->context;
|
OrbisFiberContext* fiber_ctx = fiber->context;
|
||||||
@ -62,8 +98,7 @@ void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to,
|
|||||||
data.entry = fiber->entry;
|
data.entry = fiber->entry;
|
||||||
data.arg_on_initialize = fiber->arg_on_initialize;
|
data.arg_on_initialize = fiber->arg_on_initialize;
|
||||||
data.arg_on_run_to = arg_on_run_to;
|
data.arg_on_run_to = arg_on_run_to;
|
||||||
data.stack_addr =
|
data.stack_addr = reinterpret_cast<u8*>(fiber->addr_context) + fiber->size_context;
|
||||||
reinterpret_cast<void*>(reinterpret_cast<u64>(fiber->addr_context) + fiber->size_context);
|
|
||||||
if (fiber->flags & FiberFlags::SetFpuRegs) {
|
if (fiber->flags & FiberFlags::SetFpuRegs) {
|
||||||
data.fpucw = 0x037f;
|
data.fpucw = 0x037f;
|
||||||
data.mxcsr = 0x9fc0;
|
data.mxcsr = 0x9fc0;
|
||||||
@ -111,9 +146,10 @@ void PS4_SYSV_ABI _sceFiberTerminate(OrbisFiber* fiber, u64 arg_on_return, Orbis
|
|||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFiberEntry entry,
|
s32 PS4_SYSV_ABI sceFiberInitializeImpl(OrbisFiber* fiber, const char* name, OrbisFiberEntry entry,
|
||||||
u64 arg_on_initialize, void* addr_context, u64 size_context,
|
u64 arg_on_initialize, void* addr_context, u64 size_context,
|
||||||
const OrbisFiberOptParam* opt_param, u32 build_ver) {
|
const OrbisFiberOptParam* opt_param, u32 flags,
|
||||||
|
u32 build_ver) {
|
||||||
if (!fiber || !name || !entry) {
|
if (!fiber || !name || !entry) {
|
||||||
return ORBIS_FIBER_ERROR_NULL;
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
}
|
}
|
||||||
@ -139,12 +175,12 @@ s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFi
|
|||||||
return ORBIS_FIBER_ERROR_INVALID;
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 flags = FiberFlags::None;
|
u32 user_flags = flags;
|
||||||
if (build_ver >= 0x3500000) {
|
if (build_ver >= Common::ElfInfo::FW_35) {
|
||||||
flags |= FiberFlags::SetFpuRegs;
|
user_flags |= FiberFlags::SetFpuRegs;
|
||||||
}
|
}
|
||||||
if (context_size_check) {
|
if (context_size_check) {
|
||||||
flags |= FiberFlags::ContextSizeCheck;
|
user_flags |= FiberFlags::ContextSizeCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||||
@ -154,7 +190,7 @@ s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFi
|
|||||||
fiber->addr_context = addr_context;
|
fiber->addr_context = addr_context;
|
||||||
fiber->size_context = size_context;
|
fiber->size_context = size_context;
|
||||||
fiber->context = nullptr;
|
fiber->context = nullptr;
|
||||||
fiber->flags = flags;
|
fiber->flags = user_flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A low stack area is problematic, as we can easily
|
A low stack area is problematic, as we can easily
|
||||||
@ -169,8 +205,7 @@ s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFi
|
|||||||
|
|
||||||
if (addr_context != nullptr) {
|
if (addr_context != nullptr) {
|
||||||
fiber->context_start = addr_context;
|
fiber->context_start = addr_context;
|
||||||
fiber->context_end =
|
fiber->context_end = reinterpret_cast<u8*>(addr_context) + size_context;
|
||||||
reinterpret_cast<void*>(reinterpret_cast<u64>(addr_context) + size_context);
|
|
||||||
|
|
||||||
/* Apply signature to start of stack */
|
/* Apply signature to start of stack */
|
||||||
*(u64*)addr_context = kFiberStackSignature;
|
*(u64*)addr_context = kFiberStackSignature;
|
||||||
@ -221,11 +256,12 @@ s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber) {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return) {
|
s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size_context,
|
||||||
|
u64 arg_on_run_to, u64* arg_on_return) {
|
||||||
if (!fiber) {
|
if (!fiber) {
|
||||||
return ORBIS_FIBER_ERROR_NULL;
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
}
|
}
|
||||||
if ((u64)fiber & 7) {
|
if ((u64)fiber & 7 || (u64)addr_context & 15) {
|
||||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
}
|
}
|
||||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||||
@ -237,6 +273,14 @@ s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_r
|
|||||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Caller wants to attach context and run. */
|
||||||
|
if (addr_context != nullptr || size_context != 0) {
|
||||||
|
s32 res = _sceFiberAttachContext(fiber, addr_context, size_context);
|
||||||
|
if (res < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FiberState expected = FiberState::Idle;
|
FiberState expected = FiberState::Idle;
|
||||||
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
|
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
|
||||||
return ORBIS_FIBER_ERROR_STATE;
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
@ -288,11 +332,12 @@ s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_r
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run) {
|
s32 PS4_SYSV_ABI sceFiberSwitchImpl(OrbisFiber* fiber, void* addr_context, u64 size_context,
|
||||||
|
u64 arg_on_run_to, u64* arg_on_run) {
|
||||||
if (!fiber) {
|
if (!fiber) {
|
||||||
return ORBIS_FIBER_ERROR_NULL;
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
}
|
}
|
||||||
if ((u64)fiber & 7) {
|
if ((u64)fiber & 7 || (u64)addr_context & 15) {
|
||||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
}
|
}
|
||||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||||
@ -304,6 +349,14 @@ s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_o
|
|||||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Caller wants to attach context and switch. */
|
||||||
|
if (addr_context != nullptr || size_context != 0) {
|
||||||
|
s32 res = _sceFiberAttachContext(fiber, addr_context, size_context);
|
||||||
|
if (res < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FiberState expected = FiberState::Idle;
|
FiberState expected = FiberState::Idle;
|
||||||
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
|
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
|
||||||
return ORBIS_FIBER_ERROR_STATE;
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
@ -462,9 +515,39 @@ s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name) {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer) {
|
||||||
|
if (!addr_frame_pointer) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbisFiberContext* g_ctx = GetFiberContext();
|
||||||
|
if (!g_ctx) {
|
||||||
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
*addr_frame_pointer = g_ctx->rbp;
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFiberEntry entry,
|
||||||
|
u64 arg_on_initialize, void* addr_context, u64 size_context,
|
||||||
|
const OrbisFiberOptParam* opt_param, u32 build_ver) {
|
||||||
|
return sceFiberInitializeImpl(fiber, name, entry, arg_on_initialize, addr_context, size_context,
|
||||||
|
opt_param, 0, build_ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return) {
|
||||||
|
return sceFiberRunImpl(fiber, nullptr, 0, arg_on_run_to, arg_on_return);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run) {
|
||||||
|
return sceFiberSwitchImpl(fiber, nullptr, 0, arg_on_run_to, arg_on_run);
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||||
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberInitializeImpl); // _sceFiberInitializeWithInternalOptionImpl
|
||||||
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
||||||
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
||||||
|
|
||||||
@ -473,12 +556,20 @@ void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
|||||||
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
|
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
|
||||||
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
|
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
|
||||||
|
|
||||||
|
LIB_FUNCTION("avfGJ94g36Q", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberRunImpl); // _sceFiberAttachContextAndRun
|
||||||
|
LIB_FUNCTION("ZqhZFuzKT6U", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberSwitchImpl); // _sceFiberAttachContextAndSwitch
|
||||||
|
|
||||||
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
|
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
|
||||||
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1,
|
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
sceFiberStartContextSizeCheck);
|
sceFiberStartContextSizeCheck);
|
||||||
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1,
|
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
sceFiberStopContextSizeCheck);
|
sceFiberStopContextSizeCheck);
|
||||||
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
|
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
|
||||||
|
|
||||||
|
LIB_FUNCTION("0dy4JtMUcMQ", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberGetThreadFramePointerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::Fiber
|
} // namespace Libraries::Fiber
|
||||||
|
@ -114,5 +114,7 @@ s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void);
|
|||||||
|
|
||||||
s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name);
|
s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer);
|
||||||
|
|
||||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
|
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
|
||||||
} // namespace Libraries::Fiber
|
} // namespace Libraries::Fiber
|
@ -12,6 +12,7 @@
|
|||||||
#include "core/address_space.h"
|
#include "core/address_space.h"
|
||||||
#include "core/debug_state.h"
|
#include "core/debug_state.h"
|
||||||
#include "core/libraries/gnmdriver/gnm_error.h"
|
#include "core/libraries/gnmdriver/gnm_error.h"
|
||||||
|
#include "core/libraries/gnmdriver/gnmdriver_init.h"
|
||||||
#include "core/libraries/kernel/orbis_error.h"
|
#include "core/libraries/kernel/orbis_error.h"
|
||||||
#include "core/libraries/kernel/process.h"
|
#include "core/libraries/kernel/process.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
@ -29,7 +30,7 @@ namespace Libraries::GnmDriver {
|
|||||||
|
|
||||||
using namespace AmdGpu;
|
using namespace AmdGpu;
|
||||||
|
|
||||||
enum GnmEventIdents : u64 {
|
enum GnmEventType : u64 {
|
||||||
Compute0RelMem = 0x00,
|
Compute0RelMem = 0x00,
|
||||||
Compute1RelMem = 0x01,
|
Compute1RelMem = 0x01,
|
||||||
Compute2RelMem = 0x02,
|
Compute2RelMem = 0x02,
|
||||||
@ -54,244 +55,11 @@ enum ShaderStages : u32 {
|
|||||||
|
|
||||||
static constexpr std::array indirect_sgpr_offsets{0u, 0u, 0x4cu, 0u, 0xccu, 0u, 0x14cu};
|
static constexpr std::array indirect_sgpr_offsets{0u, 0u, 0x4cu, 0u, 0xccu, 0u, 0x14cu};
|
||||||
|
|
||||||
static constexpr auto HwInitPacketSize = 0x100u;
|
// Gates use of what appear to be the neo-mode init sequences but with the older
|
||||||
|
// IA_MULTI_VGT_PARAM register address. No idea what this is for as the ioctl
|
||||||
// clang-format off
|
// that controls it is still a mystery, but leaving the sequences in gated behind
|
||||||
static constexpr std::array InitSequence{
|
// this flag in case we need it in the future.
|
||||||
// A fake preamble to mimic context reset sent by FW
|
static constexpr bool UseNeoCompatSequences = false;
|
||||||
0xc0001200u, 0u, // IT_CLEAR_STATE
|
|
||||||
|
|
||||||
// Actual init state sequence
|
|
||||||
0xc0017600u, 0x216u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x217u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x215u, 0u,
|
|
||||||
0xc0016900u, 0x2f9u, 0x2du,
|
|
||||||
0xc0016900u, 0x282u, 8u,
|
|
||||||
0xc0016900u, 0x280u, 0x80008u,
|
|
||||||
0xc0016900u, 0x281u, 0xffff0000u,
|
|
||||||
0xc0016900u, 0x204u, 0u,
|
|
||||||
0xc0016900u, 0x206u, 0x43fu,
|
|
||||||
0xc0016900u, 0x83u, 0xffffu,
|
|
||||||
0xc0016900u, 0x317u, 0x10u,
|
|
||||||
0xc0016900u, 0x2fau, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fcu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fbu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fdu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x202u, 0xcc0010u,
|
|
||||||
0xc0016900u, 0x30eu, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x30fu, 0xffffffffu,
|
|
||||||
0xc0002f00u, 1u,
|
|
||||||
0xc0017600u, 7u, 0x1ffu,
|
|
||||||
0xc0017600u, 0x46u, 0x1ffu,
|
|
||||||
0xc0017600u, 0x87u, 0x1ffu,
|
|
||||||
0xc0017600u, 0xc7u, 0x1ffu,
|
|
||||||
0xc0017600u, 0x107u, 0u,
|
|
||||||
0xc0017600u, 0x147u, 0x1ffu,
|
|
||||||
0xc0016900u, 0x1b1u, 2u,
|
|
||||||
0xc0016900u, 0x101u, 0u,
|
|
||||||
0xc0016900u, 0x100u, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x103u, 0u,
|
|
||||||
0xc0016900u, 0x284u, 0u,
|
|
||||||
0xc0016900u, 0x290u, 0u,
|
|
||||||
0xc0016900u, 0x2aeu, 0u,
|
|
||||||
0xc0016900u, 0x292u, 0u,
|
|
||||||
0xc0016900u, 0x293u, 0x6000000u,
|
|
||||||
0xc0016900u, 0x2f8u, 0u,
|
|
||||||
0xc0016900u, 0x2deu, 0x1e9u,
|
|
||||||
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
|
||||||
0xc0017900u, 0x200u, 0xe0000000u,
|
|
||||||
};
|
|
||||||
static_assert(InitSequence.size() == 0x73 + 2);
|
|
||||||
|
|
||||||
static constexpr std::array InitSequence175{
|
|
||||||
// A fake preamble to mimic context reset sent by FW
|
|
||||||
0xc0001200u, 0u, // IT_CLEAR_STATE
|
|
||||||
|
|
||||||
// Actual init state sequence
|
|
||||||
0xc0017600u, 0x216u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x217u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x215u, 0u,
|
|
||||||
0xc0016900u, 0x2f9u, 0x2du,
|
|
||||||
0xc0016900u, 0x282u, 8u,
|
|
||||||
0xc0016900u, 0x280u, 0x80008u,
|
|
||||||
0xc0016900u, 0x281u, 0xffff0000u,
|
|
||||||
0xc0016900u, 0x204u, 0u,
|
|
||||||
0xc0016900u, 0x206u, 0x43fu,
|
|
||||||
0xc0016900u, 0x83u, 0xffffu,
|
|
||||||
0xc0016900u, 0x317u, 0x10u,
|
|
||||||
0xc0016900u, 0x2fau, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fcu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fbu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fdu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x202u, 0xcc0010u,
|
|
||||||
0xc0016900u, 0x30eu, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x30fu, 0xffffffffu,
|
|
||||||
0xc0002f00u, 1u,
|
|
||||||
0xc0017600u, 7u, 0x1ffu,
|
|
||||||
0xc0017600u, 0x46u, 0x1ffu,
|
|
||||||
0xc0017600u, 0x87u, 0x1ffu,
|
|
||||||
0xc0017600u, 0xc7u, 0x1ffu,
|
|
||||||
0xc0017600u, 0x107u, 0u,
|
|
||||||
0xc0017600u, 0x147u, 0x1ffu,
|
|
||||||
0xc0016900u, 0x1b1u, 2u,
|
|
||||||
0xc0016900u, 0x101u, 0u,
|
|
||||||
0xc0016900u, 0x100u, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x103u, 0u,
|
|
||||||
0xc0016900u, 0x284u, 0u,
|
|
||||||
0xc0016900u, 0x290u, 0u,
|
|
||||||
0xc0016900u, 0x2aeu, 0u,
|
|
||||||
0xc0016900u, 0x292u, 0u,
|
|
||||||
0xc0016900u, 0x293u, 0x6020000u,
|
|
||||||
0xc0016900u, 0x2f8u, 0u,
|
|
||||||
0xc0016900u, 0x2deu, 0x1e9u,
|
|
||||||
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
|
||||||
0xc0017900u, 0x200u, 0xe0000000u,
|
|
||||||
};
|
|
||||||
static_assert(InitSequence175.size() == 0x73 + 2);
|
|
||||||
|
|
||||||
static constexpr std::array InitSequence200{
|
|
||||||
// A fake preamble to mimic context reset sent by FW
|
|
||||||
0xc0001200u, 0u, // IT_CLEAR_STATE
|
|
||||||
|
|
||||||
// Actual init state sequence
|
|
||||||
0xc0017600u, 0x216u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x217u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x215u, 0u,
|
|
||||||
0xc0016900u, 0x2f9u, 0x2du,
|
|
||||||
0xc0016900u, 0x282u, 8u,
|
|
||||||
0xc0016900u, 0x280u, 0x80008u,
|
|
||||||
0xc0016900u, 0x281u, 0xffff0000u,
|
|
||||||
0xc0016900u, 0x204u, 0u,
|
|
||||||
0xc0016900u, 0x206u, 0x43fu,
|
|
||||||
0xc0016900u, 0x83u, 0xffffu,
|
|
||||||
0xc0016900u, 0x317u, 0x10u,
|
|
||||||
0xc0016900u, 0x2fau, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fcu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fbu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fdu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x202u, 0xcc0010u,
|
|
||||||
0xc0016900u, 0x30eu, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x30fu, 0xffffffffu,
|
|
||||||
0xc0002f00u, 1u,
|
|
||||||
0xc0017600u, 7u, 0x1701ffu,
|
|
||||||
0xc0017600u, 0x46u, 0x1701fdu,
|
|
||||||
0xc0017600u, 0x87u, 0x1701ffu,
|
|
||||||
0xc0017600u, 0xc7u, 0x1701fdu,
|
|
||||||
0xc0017600u, 0x107u, 0x17u,
|
|
||||||
0xc0017600u, 0x147u, 0x1701fdu,
|
|
||||||
0xc0017600u, 0x47u, 0x1cu,
|
|
||||||
0xc0016900u, 0x1b1u, 2u,
|
|
||||||
0xc0016900u, 0x101u, 0u,
|
|
||||||
0xc0016900u, 0x100u, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x103u, 0u,
|
|
||||||
0xc0016900u, 0x284u, 0u,
|
|
||||||
0xc0016900u, 0x290u, 0u,
|
|
||||||
0xc0016900u, 0x2aeu, 0u,
|
|
||||||
0xc0016900u, 0x292u, 0u,
|
|
||||||
0xc0016900u, 0x293u, 0x6020000u,
|
|
||||||
0xc0016900u, 0x2f8u, 0u,
|
|
||||||
0xc0016900u, 0x2deu, 0x1e9u,
|
|
||||||
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
|
||||||
0xc0017900u, 0x200u, 0xe0000000u,
|
|
||||||
};
|
|
||||||
static_assert(InitSequence200.size() == 0x76 + 2);
|
|
||||||
|
|
||||||
static constexpr std::array InitSequence350{
|
|
||||||
// A fake preamble to mimic context reset sent by FW
|
|
||||||
0xc0001200u, 0u, // IT_CLEAR_STATE
|
|
||||||
|
|
||||||
// Actual init state sequence
|
|
||||||
0xc0017600u, 0x216u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x217u, 0xffffffffu,
|
|
||||||
0xc0017600u, 0x215u, 0u,
|
|
||||||
0xc0016900u, 0x2f9u, 0x2du,
|
|
||||||
0xc0016900u, 0x282u, 8u,
|
|
||||||
0xc0016900u, 0x280u, 0x80008u,
|
|
||||||
0xc0016900u, 0x281u, 0xffff0000u,
|
|
||||||
0xc0016900u, 0x204u, 0u,
|
|
||||||
0xc0016900u, 0x206u, 0x43fu,
|
|
||||||
0xc0016900u, 0x83u, 0xffffu,
|
|
||||||
0xc0016900u, 0x317u, 0x10u,
|
|
||||||
0xc0016900u, 0x2fau, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fcu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fbu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fdu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x202u, 0xcc0010u,
|
|
||||||
0xc0016900u, 0x30eu, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x30fu, 0xffffffffu,
|
|
||||||
0xc0002f00u, 1u,
|
|
||||||
0xc0017600u, 7u, 0x1701ffu,
|
|
||||||
0xc0017600u, 0x46u, 0x1701fdu,
|
|
||||||
0xc0017600u, 0x87u, 0x1701ffu,
|
|
||||||
0xc0017600u, 0xc7u, 0x1701fdu,
|
|
||||||
0xc0017600u, 0x107u, 0x17u,
|
|
||||||
0xc0017600u, 0x147u, 0x1701fdu,
|
|
||||||
0xc0017600u, 0x47u, 0x1cu,
|
|
||||||
0xc0016900u, 0x1b1u, 2u,
|
|
||||||
0xc0016900u, 0x101u, 0u,
|
|
||||||
0xc0016900u, 0x100u, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x103u, 0u,
|
|
||||||
0xc0016900u, 0x284u, 0u,
|
|
||||||
0xc0016900u, 0x290u, 0u,
|
|
||||||
0xc0016900u, 0x2aeu, 0u,
|
|
||||||
0xc0016900u, 0x102u, 0u,
|
|
||||||
0xc0016900u, 0x292u, 0u,
|
|
||||||
0xc0016900u, 0x293u, 0x6020000u,
|
|
||||||
0xc0016900u, 0x2f8u, 0u,
|
|
||||||
0xc0016900u, 0x2deu, 0x1e9u,
|
|
||||||
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
|
||||||
0xc0017900u, 0x200u, 0xe0000000u,
|
|
||||||
0xc0016900u, 0x2aau, 0xffu,
|
|
||||||
};
|
|
||||||
static_assert(InitSequence350.size() == 0x7c + 2);
|
|
||||||
|
|
||||||
static constexpr std::array CtxInitSequence{
|
|
||||||
0xc0012800u, 0x80000000u, 0x80000000u,
|
|
||||||
0xc0001200u, 0u,
|
|
||||||
0xc0002f00u, 1u,
|
|
||||||
0xc0016900u, 0x102u, 0u,
|
|
||||||
0xc0016900u, 0x202u, 0xcc0010u,
|
|
||||||
0xc0111000u, 0u
|
|
||||||
};
|
|
||||||
static_assert(CtxInitSequence.size() == 0x0f);
|
|
||||||
|
|
||||||
static constexpr std::array CtxInitSequence400{
|
|
||||||
0xc0012800u, 0x80000000u, 0x80000000u,
|
|
||||||
0xc0001200u, 0u,
|
|
||||||
0xc0016900u, 0x2f9u, 0x2du,
|
|
||||||
0xc0016900u, 0x282u, 8u,
|
|
||||||
0xc0016900u, 0x280u, 0x80008u,
|
|
||||||
0xc0016900u, 0x281u, 0xffff0000u,
|
|
||||||
0xc0016900u, 0x204u, 0u,
|
|
||||||
0xc0016900u, 0x206u, 0x43fu,
|
|
||||||
0xc0016900u, 0x83u, 0xffffu,
|
|
||||||
0xc0016900u, 0x317u, 0x10u,
|
|
||||||
0xc0016900u, 0x2fau, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fcu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fbu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x2fdu, 0x3f800000u,
|
|
||||||
0xc0016900u, 0x202u, 0xcc0010u,
|
|
||||||
0xc0016900u, 0x30eu, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x30fu, 0xffffffffu,
|
|
||||||
0xc0002f00u, 1u,
|
|
||||||
0xc0016900u, 0x1b1u, 2u,
|
|
||||||
0xc0016900u, 0x101u, 0u,
|
|
||||||
0xc0016900u, 0x100u, 0xffffffffu,
|
|
||||||
0xc0016900u, 0x103u, 0u,
|
|
||||||
0xc0016900u, 0x284u, 0u,
|
|
||||||
0xc0016900u, 0x290u, 0u,
|
|
||||||
0xc0016900u, 0x2aeu, 0u,
|
|
||||||
0xc0016900u, 0x102u, 0u,
|
|
||||||
0xc0016900u, 0x292u, 0u,
|
|
||||||
0xc0016900u, 0x293u, 0x6020000u,
|
|
||||||
0xc0016900u, 0x2f8u, 0u,
|
|
||||||
0xc0016900u, 0x2deu, 0x1e9u,
|
|
||||||
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
|
||||||
0xc0016900u, 0x2aau, 0xffu,
|
|
||||||
0xc09e1000u,
|
|
||||||
};
|
|
||||||
static_assert(CtxInitSequence400.size() == 0x61);
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
// In case if `submitDone` is issued we need to block submissions until GPU idle
|
// In case if `submitDone` is issued we need to block submissions until GPU idle
|
||||||
static u32 submission_lock{};
|
static u32 submission_lock{};
|
||||||
@ -317,6 +85,14 @@ static void WaitGpuIdle() {
|
|||||||
cv_lock.wait(lock, [] { return submission_lock == 0; });
|
cv_lock.wait(lock, [] { return submission_lock == 0; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write a special ending NOP packet with N DWs data block
|
||||||
|
static inline u32* WriteTrailingNop(u32* cmdbuf, u32 data_block_size) {
|
||||||
|
auto* nop = reinterpret_cast<PM4CmdNop*>(cmdbuf);
|
||||||
|
nop->header = PM4Type3Header{PM4ItOpcode::Nop, data_block_size - 1};
|
||||||
|
nop->data_block[0] = 0u; // only one out of `data_block_size` is initialized
|
||||||
|
return cmdbuf + data_block_size + 1 /* header */;
|
||||||
|
}
|
||||||
|
|
||||||
// Write a special ending NOP packet with N DWs data block
|
// Write a special ending NOP packet with N DWs data block
|
||||||
template <u32 data_block_size>
|
template <u32 data_block_size>
|
||||||
static inline u32* WriteTrailingNop(u32* cmdbuf) {
|
static inline u32* WriteTrailingNop(u32* cmdbuf) {
|
||||||
@ -337,6 +113,12 @@ static inline u32* ClearContextState(u32* cmdbuf) {
|
|||||||
return cmdbuf + ClearStateSequence.size();
|
return cmdbuf + ClearStateSequence.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool IsValidEventType(Platform::InterruptId id) {
|
||||||
|
return (static_cast<u32>(id) >= static_cast<u32>(Platform::InterruptId::Compute0RelMem) &&
|
||||||
|
static_cast<u32>(id) <= static_cast<u32>(Platform::InterruptId::Compute6RelMem)) ||
|
||||||
|
static_cast<u32>(id) == static_cast<u32>(Platform::InterruptId::GfxEop);
|
||||||
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
|
s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
|
||||||
LOG_TRACE(Lib_GnmDriver, "called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
@ -347,8 +129,7 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
|
|||||||
EqueueEvent kernel_event{};
|
EqueueEvent kernel_event{};
|
||||||
kernel_event.event.ident = id;
|
kernel_event.event.ident = id;
|
||||||
kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore;
|
kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore;
|
||||||
// The library only sets EV_ADD but it is suspected the kernel driver forces EV_CLEAR
|
kernel_event.event.flags = SceKernelEvent::Flags::Add;
|
||||||
kernel_event.event.flags = SceKernelEvent::Flags::Clear;
|
|
||||||
kernel_event.event.fflags = 0;
|
kernel_event.event.fflags = 0;
|
||||||
kernel_event.event.data = id;
|
kernel_event.event.data = id;
|
||||||
kernel_event.event.udata = udata;
|
kernel_event.event.udata = udata;
|
||||||
@ -357,11 +138,15 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
|
|||||||
Platform::IrqC::Instance()->Register(
|
Platform::IrqC::Instance()->Register(
|
||||||
static_cast<Platform::InterruptId>(id),
|
static_cast<Platform::InterruptId>(id),
|
||||||
[=](Platform::InterruptId irq) {
|
[=](Platform::InterruptId irq) {
|
||||||
ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id),
|
ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id), "An unexpected IRQ occured");
|
||||||
"An unexpected IRQ occured"); // We need to convert IRQ# to event id and do
|
|
||||||
// proper filtering in trigger function
|
// We need to convert IRQ# to event id
|
||||||
eq->TriggerEvent(static_cast<GnmEventIdents>(id), SceKernelEvent::Filter::GraphicsCore,
|
if (!IsValidEventType(irq))
|
||||||
nullptr);
|
return;
|
||||||
|
|
||||||
|
// Event data is expected to be an event type as per sceGnmGetEqEventType.
|
||||||
|
eq->TriggerEvent(static_cast<GnmEventType>(id), SceKernelEvent::Filter::GraphicsCore,
|
||||||
|
reinterpret_cast<void*>(id));
|
||||||
},
|
},
|
||||||
eq);
|
eq);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -476,7 +261,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) {
|
|||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
eq->RemoveEvent(id);
|
eq->RemoveEvent(id, SceKernelEvent::Filter::GraphicsCore);
|
||||||
|
|
||||||
Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), eq);
|
Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), eq);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -504,10 +289,14 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
auto vqid = gnm_vqid - 1;
|
auto vqid = gnm_vqid - 1;
|
||||||
auto& asc_queue = liverpool->asc_queues[{vqid}];
|
auto& asc_queue = liverpool->asc_queues[{vqid}];
|
||||||
|
|
||||||
const auto& offs_dw = asc_next_offs_dw[vqid];
|
auto& offs_dw = asc_next_offs_dw[vqid];
|
||||||
|
|
||||||
if (next_offs_dw < offs_dw) {
|
if (next_offs_dw < offs_dw && next_offs_dw != 0) {
|
||||||
ASSERT_MSG(next_offs_dw == 0, "ACB submission is split at the end of ring buffer");
|
// For cases if a submission is split at the end of the ring buffer, we need to submit it in
|
||||||
|
// two parts to handle the wrap
|
||||||
|
liverpool->SubmitAsc(gnm_vqid, {reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw,
|
||||||
|
asc_queue.ring_size_dw - offs_dw});
|
||||||
|
offs_dw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* acb_ptr = reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw;
|
const auto* acb_ptr = reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw;
|
||||||
@ -594,9 +383,16 @@ s32 PS4_SYSV_ABI sceGnmDispatchIndirect(u32* cmdbuf, u32 size, u32 data_offset,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmDispatchIndirectOnMec() {
|
s32 PS4_SYSV_ABI sceGnmDispatchIndirectOnMec(u32* cmdbuf, u32 size, VAddr args, u32 modifier) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
if (cmdbuf != nullptr && size == 8 && args != 0 && ((args & 3u) == 0)) {
|
||||||
|
cmdbuf[0] = 0xc0021602 | (modifier & 1u);
|
||||||
|
*(VAddr*)(&cmdbuf[1]) = args;
|
||||||
|
cmdbuf[3] = (modifier & 0x18) | 1u;
|
||||||
|
cmdbuf[4] = 0xc0021000;
|
||||||
|
cmdbuf[5] = 0;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
return ORBIS_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PS4_SYSV_ABI sceGnmDispatchInitDefaultHardwareState(u32* cmdbuf, u32 size) {
|
u32 PS4_SYSV_ABI sceGnmDispatchInitDefaultHardwareState(u32* cmdbuf, u32 size) {
|
||||||
@ -606,17 +402,30 @@ u32 PS4_SYSV_ABI sceGnmDispatchInitDefaultHardwareState(u32* cmdbuf, u32 size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x216u,
|
cmdbuf = PM4CmdSetData::SetShReg<PM4ShaderType::ShaderCompute>(
|
||||||
|
cmdbuf, 0x216u,
|
||||||
0xffffffffu); // COMPUTE_STATIC_THREAD_MGMT_SE0
|
0xffffffffu); // COMPUTE_STATIC_THREAD_MGMT_SE0
|
||||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x217u,
|
cmdbuf = PM4CmdSetData::SetShReg<PM4ShaderType::ShaderCompute>(
|
||||||
|
cmdbuf, 0x217u,
|
||||||
0xffffffffu); // COMPUTE_STATIC_THREAD_MGMT_SE1
|
0xffffffffu); // COMPUTE_STATIC_THREAD_MGMT_SE1
|
||||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x215u, 0x170u); // COMPUTE_RESOURCE_LIMITS
|
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
cmdbuf = PM4CmdSetData::SetShReg<PM4ShaderType::ShaderCompute>(
|
||||||
|
cmdbuf, 0x219u,
|
||||||
|
0xffffffffu); // COMPUTE_STATIC_THREAD_MGMT_SE2
|
||||||
|
cmdbuf = PM4CmdSetData::SetShReg<PM4ShaderType::ShaderCompute>(
|
||||||
|
cmdbuf, 0x21au,
|
||||||
|
0xffffffffu); // COMPUTE_STATIC_THREAD_MGMT_SE3
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdbuf = PM4CmdSetData::SetShReg<PM4ShaderType::ShaderCompute>(
|
||||||
|
cmdbuf, 0x215u, 0x170u); // COMPUTE_RESOURCE_LIMITS
|
||||||
|
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::AcquireMem>(cmdbuf, 6);
|
cmdbuf = WriteHeader<PM4ItOpcode::AcquireMem>(cmdbuf, 6);
|
||||||
cmdbuf = WriteBody(cmdbuf, 0x28000000u, 0u, 0u, 0u, 0u, 0u);
|
cmdbuf = WriteBody(cmdbuf, 0x28000000u, 0u, 0u, 0u, 0u, 0xau);
|
||||||
|
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 0xef);
|
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, sceKernelIsNeoMode() ? 0xe9 : 0xef);
|
||||||
cmdbuf = WriteBody(cmdbuf, 0xau, 0u);
|
cmdbuf = WriteBody(cmdbuf, 0u);
|
||||||
return HwInitPacketSize;
|
return HwInitPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,7 +442,7 @@ s32 PS4_SYSV_ABI sceGnmDrawIndex(u32* cmdbuf, u32 size, u32 index_count, uintptr
|
|||||||
draw_index->index_base_lo = u32(index_addr);
|
draw_index->index_base_lo = u32(index_addr);
|
||||||
draw_index->index_base_hi = u32(index_addr >> 32);
|
draw_index->index_base_hi = u32(index_addr >> 32);
|
||||||
draw_index->index_count = index_count;
|
draw_index->index_count = index_count;
|
||||||
draw_index->draw_initiator = 0;
|
draw_index->draw_initiator = sceKernelIsNeoMode() ? flags & 0xe0000000u : 0;
|
||||||
|
|
||||||
WriteTrailingNop<3>(cmdbuf + 6);
|
WriteTrailingNop<3>(cmdbuf + 6);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -646,8 +455,9 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexAuto(u32* cmdbuf, u32 size, u32 index_count, u32
|
|||||||
|
|
||||||
if (cmdbuf && (size == 7) &&
|
if (cmdbuf && (size == 7) &&
|
||||||
(flags & 0x1ffffffe) == 0) { // no predication will be set in the packet
|
(flags & 0x1ffffffe) == 0) { // no predication will be set in the packet
|
||||||
cmdbuf = WritePacket<PM4ItOpcode::DrawIndexAuto>(cmdbuf, PM4ShaderType::ShaderGraphics,
|
cmdbuf = WritePacket<PM4ItOpcode::DrawIndexAuto>(
|
||||||
index_count, 2u);
|
cmdbuf, PM4ShaderType::ShaderGraphics, index_count,
|
||||||
|
sceKernelIsNeoMode() ? flags & 0xe0000000u | 2u : 2u);
|
||||||
WriteTrailingNop<3>(cmdbuf);
|
WriteTrailingNop<3>(cmdbuf);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
@ -671,7 +481,7 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirect(u32* cmdbuf, u32 size, u32 data_offset,
|
|||||||
cmdbuf[0] = data_offset;
|
cmdbuf[0] = data_offset;
|
||||||
cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
|
cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
|
||||||
cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
|
cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
|
||||||
cmdbuf[3] = 0;
|
cmdbuf[3] = sceKernelIsNeoMode() ? flags & 0xe0000000u : 0u;
|
||||||
|
|
||||||
cmdbuf += 4;
|
cmdbuf += 4;
|
||||||
WriteTrailingNop<3>(cmdbuf);
|
WriteTrailingNop<3>(cmdbuf);
|
||||||
@ -686,8 +496,9 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
|
|||||||
u32 flags) {
|
u32 flags) {
|
||||||
LOG_TRACE(Lib_GnmDriver, "called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
if (cmdbuf && (size == 16) && (shader_stage < ShaderStages::Max) &&
|
if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && !cmdbuf && (size == 16) &&
|
||||||
(vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u)) {
|
(shader_stage < ShaderStages::Max) && (vertex_sgpr_offset < 0x10u) &&
|
||||||
|
(instance_sgpr_offset < 0x10u)) {
|
||||||
|
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 2);
|
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 2);
|
||||||
cmdbuf = WriteBody(cmdbuf, 0u);
|
cmdbuf = WriteBody(cmdbuf, 0u);
|
||||||
@ -706,7 +517,7 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
|
|||||||
cmdbuf[4] = max_count;
|
cmdbuf[4] = max_count;
|
||||||
*(u64*)(&cmdbuf[5]) = count_addr;
|
*(u64*)(&cmdbuf[5]) = count_addr;
|
||||||
cmdbuf[7] = sizeof(DrawIndexedIndirectArgs);
|
cmdbuf[7] = sizeof(DrawIndexedIndirectArgs);
|
||||||
cmdbuf[8] = 0;
|
cmdbuf[8] = sceKernelIsNeoMode() ? flags & 0xe0000000u : 0;
|
||||||
|
|
||||||
cmdbuf += 9;
|
cmdbuf += 9;
|
||||||
WriteTrailingNop<2>(cmdbuf);
|
WriteTrailingNop<2>(cmdbuf);
|
||||||
@ -735,7 +546,8 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset,
|
|||||||
const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable;
|
const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable;
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::DrawIndexOffset2>(
|
cmdbuf = WriteHeader<PM4ItOpcode::DrawIndexOffset2>(
|
||||||
cmdbuf, 4, PM4ShaderType::ShaderGraphics, predicate);
|
cmdbuf, 4, PM4ShaderType::ShaderGraphics, predicate);
|
||||||
cmdbuf = WriteBody(cmdbuf, index_count, index_offset, index_count, 0u);
|
cmdbuf = WriteBody(cmdbuf, index_count, index_offset, index_count,
|
||||||
|
sceKernelIsNeoMode() ? flags & 0xe0000000u : 0u);
|
||||||
|
|
||||||
WriteTrailingNop<3>(cmdbuf);
|
WriteTrailingNop<3>(cmdbuf);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -759,7 +571,7 @@ s32 PS4_SYSV_ABI sceGnmDrawIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32
|
|||||||
cmdbuf[0] = data_offset;
|
cmdbuf[0] = data_offset;
|
||||||
cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
|
cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
|
||||||
cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
|
cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
|
||||||
cmdbuf[3] = 2; // auto index
|
cmdbuf[3] = sceKernelIsNeoMode() ? flags & 0xe0000000u | 2u : 2u; // auto index
|
||||||
|
|
||||||
cmdbuf += 4;
|
cmdbuf += 4;
|
||||||
WriteTrailingNop<3>(cmdbuf);
|
WriteTrailingNop<3>(cmdbuf);
|
||||||
@ -788,6 +600,7 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState(u32* cmdbuf, u32 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& SetupContext = [](u32* cmdbuf, u32 size, bool clear_state) {
|
const auto& SetupContext = [](u32* cmdbuf, u32 size, bool clear_state) {
|
||||||
|
const auto* cmdbuf_end = cmdbuf + HwInitPacketSize;
|
||||||
if (clear_state) {
|
if (clear_state) {
|
||||||
cmdbuf = ClearContextState(cmdbuf);
|
cmdbuf = ClearContextState(cmdbuf);
|
||||||
}
|
}
|
||||||
@ -795,10 +608,8 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState(u32* cmdbuf, u32 size) {
|
|||||||
std::memcpy(cmdbuf, &InitSequence[2], (InitSequence.size() - 2) * 4);
|
std::memcpy(cmdbuf, &InitSequence[2], (InitSequence.size() - 2) * 4);
|
||||||
cmdbuf += InitSequence.size() - 2;
|
cmdbuf += InitSequence.size() - 2;
|
||||||
|
|
||||||
const auto cmdbuf_left =
|
const auto cmdbuf_left = cmdbuf_end - cmdbuf - 1;
|
||||||
HwInitPacketSize - (InitSequence.size() - 2) - (clear_state ? 0xc : 0) - 1;
|
WriteTrailingNop(cmdbuf, cmdbuf_left);
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, cmdbuf_left);
|
|
||||||
cmdbuf = WriteBody(cmdbuf, 0u);
|
|
||||||
|
|
||||||
return HwInitPacketSize;
|
return HwInitPacketSize;
|
||||||
};
|
};
|
||||||
@ -813,12 +624,13 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState175(u32* cmdbuf, u32 size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto* cmdbuf_end = cmdbuf + HwInitPacketSize;
|
||||||
cmdbuf = ClearContextState(cmdbuf);
|
cmdbuf = ClearContextState(cmdbuf);
|
||||||
std::memcpy(cmdbuf, &InitSequence175[2], (InitSequence175.size() - 2) * 4);
|
std::memcpy(cmdbuf, &InitSequence175[2], (InitSequence175.size() - 2) * 4);
|
||||||
cmdbuf += InitSequence175.size() - 2;
|
cmdbuf += InitSequence175.size() - 2;
|
||||||
|
|
||||||
constexpr auto cmdbuf_left = HwInitPacketSize - (InitSequence175.size() - 2) - 0xc - 1;
|
const auto cmdbuf_left = cmdbuf_end - cmdbuf - 1;
|
||||||
WriteTrailingNop<cmdbuf_left>(cmdbuf);
|
WriteTrailingNop(cmdbuf, cmdbuf_left);
|
||||||
|
|
||||||
return HwInitPacketSize;
|
return HwInitPacketSize;
|
||||||
}
|
}
|
||||||
@ -831,17 +643,27 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState200(u32* cmdbuf, u32 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& SetupContext200 = [](u32* cmdbuf, u32 size, bool clear_state) {
|
const auto& SetupContext200 = [](u32* cmdbuf, u32 size, bool clear_state) {
|
||||||
|
const auto* cmdbuf_end = cmdbuf + HwInitPacketSize;
|
||||||
if (clear_state) {
|
if (clear_state) {
|
||||||
cmdbuf = ClearContextState(cmdbuf);
|
cmdbuf = ClearContextState(cmdbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
std::memcpy(cmdbuf, &InitSequence200Neo[2], (InitSequence200Neo.size() - 2) * 4);
|
||||||
|
cmdbuf += InitSequence200Neo.size() - 2;
|
||||||
|
} else {
|
||||||
|
std::memcpy(cmdbuf, &InitSequence200NeoCompat[2],
|
||||||
|
(InitSequence200NeoCompat.size() - 2) * 4);
|
||||||
|
cmdbuf += InitSequence200NeoCompat.size() - 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
std::memcpy(cmdbuf, &InitSequence200[2], (InitSequence200.size() - 2) * 4);
|
std::memcpy(cmdbuf, &InitSequence200[2], (InitSequence200.size() - 2) * 4);
|
||||||
cmdbuf += InitSequence200.size() - 2;
|
cmdbuf += InitSequence200.size() - 2;
|
||||||
|
}
|
||||||
|
|
||||||
const auto cmdbuf_left =
|
const auto cmdbuf_left = cmdbuf_end - cmdbuf - 1;
|
||||||
HwInitPacketSize - (InitSequence200.size() - 2) - (clear_state ? 0xc : 0) - 1;
|
WriteTrailingNop(cmdbuf, cmdbuf_left);
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, cmdbuf_left);
|
|
||||||
cmdbuf = WriteBody(cmdbuf, 0u);
|
|
||||||
|
|
||||||
return HwInitPacketSize;
|
return HwInitPacketSize;
|
||||||
};
|
};
|
||||||
@ -857,17 +679,27 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState350(u32* cmdbuf, u32 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& SetupContext350 = [](u32* cmdbuf, u32 size, bool clear_state) {
|
const auto& SetupContext350 = [](u32* cmdbuf, u32 size, bool clear_state) {
|
||||||
|
const auto* cmdbuf_end = cmdbuf + HwInitPacketSize;
|
||||||
if (clear_state) {
|
if (clear_state) {
|
||||||
cmdbuf = ClearContextState(cmdbuf);
|
cmdbuf = ClearContextState(cmdbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
std::memcpy(cmdbuf, &InitSequence350Neo[2], (InitSequence350Neo.size() - 2) * 4);
|
||||||
|
cmdbuf += InitSequence350Neo.size() - 2;
|
||||||
|
} else {
|
||||||
|
std::memcpy(cmdbuf, &InitSequence350NeoCompat[2],
|
||||||
|
(InitSequence350NeoCompat.size() - 2) * 4);
|
||||||
|
cmdbuf += InitSequence350NeoCompat.size() - 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
std::memcpy(cmdbuf, &InitSequence350[2], (InitSequence350.size() - 2) * 4);
|
std::memcpy(cmdbuf, &InitSequence350[2], (InitSequence350.size() - 2) * 4);
|
||||||
cmdbuf += InitSequence350.size() - 2;
|
cmdbuf += InitSequence350.size() - 2;
|
||||||
|
}
|
||||||
|
|
||||||
const auto cmdbuf_left =
|
const auto cmdbuf_left = cmdbuf_end - cmdbuf - 1;
|
||||||
HwInitPacketSize - (InitSequence350.size() - 2) - (clear_state ? 0xc : 0) - 1;
|
WriteTrailingNop(cmdbuf, cmdbuf_left);
|
||||||
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, cmdbuf_left);
|
|
||||||
cmdbuf = WriteBody(cmdbuf, 0u);
|
|
||||||
|
|
||||||
return HwInitPacketSize;
|
return HwInitPacketSize;
|
||||||
};
|
};
|
||||||
@ -883,7 +715,11 @@ u32 PS4_SYSV_ABI sceGnmDrawInitToDefaultContextState(u32* cmdbuf, u32 size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
std::memcpy(cmdbuf, CtxInitSequenceNeo.data(), CtxInitSequenceNeo.size() * 4);
|
||||||
|
} else {
|
||||||
std::memcpy(cmdbuf, CtxInitSequence.data(), CtxInitSequence.size() * 4);
|
std::memcpy(cmdbuf, CtxInitSequence.data(), CtxInitSequence.size() * 4);
|
||||||
|
}
|
||||||
return CtxInitPacketSize;
|
return CtxInitPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,7 +731,16 @@ u32 PS4_SYSV_ABI sceGnmDrawInitToDefaultContextState400(u32* cmdbuf, u32 size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
std::memcpy(cmdbuf, CtxInitSequence400Neo.data(), CtxInitSequence400Neo.size() * 4);
|
||||||
|
} else {
|
||||||
|
std::memcpy(cmdbuf, CtxInitSequence400NeoCompat.data(),
|
||||||
|
CtxInitSequence400NeoCompat.size() * 4);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
std::memcpy(cmdbuf, CtxInitSequence400.data(), CtxInitSequence400.size() * 4);
|
std::memcpy(cmdbuf, CtxInitSequence400.data(), CtxInitSequence400.size() * 4);
|
||||||
|
}
|
||||||
return CtxInitPacketSize;
|
return CtxInitPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,9 +845,9 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmGetEqEventType() {
|
int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
return ORBIS_OK;
|
return sceKernelGetEventData(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmGetEqTimeStamp() {
|
int PS4_SYSV_ABI sceGnmGetEqTimeStamp() {
|
||||||
@ -1017,7 +862,8 @@ int PS4_SYSV_ABI sceGnmGetGpuBlockStatus() {
|
|||||||
|
|
||||||
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency() {
|
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency() {
|
||||||
LOG_TRACE(Lib_GnmDriver, "called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
return Config::isNeoMode() ? 911'000'000 : 800'000'000;
|
// On console this uses an ioctl check, but we assume it is equal to just checking for neo mode.
|
||||||
|
return sceKernelIsNeoMode() ? 911'000'000 : 800'000'000;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmGetGpuInfoStatus() {
|
int PS4_SYSV_ABI sceGnmGetGpuInfoStatus() {
|
||||||
@ -1356,7 +1202,15 @@ s32 PS4_SYSV_ABI sceGnmResetVgtControl(u32* cmdbuf, u32 size) {
|
|||||||
if (cmdbuf == nullptr || size != 3) {
|
if (cmdbuf == nullptr || size != 3) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
PM4CmdSetData::SetUconfigReg(cmdbuf, 0x40000258u, 0x6d007fu); // IA_MULTI_VGT_PARAM
|
||||||
|
} else {
|
||||||
|
PM4CmdSetData::SetContextReg(cmdbuf, 0x100002aau, 0xd00ffu); // IA_MULTI_VGT_PARAM
|
||||||
|
}
|
||||||
|
} else {
|
||||||
PM4CmdSetData::SetContextReg(cmdbuf, 0x2aau, 0xffu); // IA_MULTI_VGT_PARAM
|
PM4CmdSetData::SetContextReg(cmdbuf, 0x2aau, 0xffu); // IA_MULTI_VGT_PARAM
|
||||||
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1817,9 +1671,25 @@ s32 PS4_SYSV_ABI sceGnmSetVgtControl(u32* cmdbuf, u32 size, u32 prim_group_sz_mi
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
const u32 wd_switch_on_eop = u32(wd_switch_only_on_eop_mode != 0) << 0x14;
|
||||||
|
const u32 switch_on_eoi = u32(wd_switch_only_on_eop_mode == 0) << 0x13;
|
||||||
|
const u32 reg_value =
|
||||||
|
wd_switch_only_on_eop_mode != 0
|
||||||
|
? (partial_vs_wave_mode & 1) << 0x10 | prim_group_sz_minus_one | wd_switch_on_eop |
|
||||||
|
switch_on_eoi | 0x40000u
|
||||||
|
: prim_group_sz_minus_one & 0x1cffffu | wd_switch_on_eop | switch_on_eoi | 0x50000u;
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
PM4CmdSetData::SetUconfigReg(cmdbuf, 0x40000258u,
|
||||||
|
reg_value | 0x600000u); // IA_MULTI_VGT_PARAM
|
||||||
|
} else {
|
||||||
|
PM4CmdSetData::SetContextReg(cmdbuf, 0x100002aau, reg_value); // IA_MULTI_VGT_PARAM
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const u32 reg_value =
|
const u32 reg_value =
|
||||||
((partial_vs_wave_mode & 1) << 0x10) | (prim_group_sz_minus_one & 0xffffu);
|
((partial_vs_wave_mode & 1) << 0x10) | (prim_group_sz_minus_one & 0xffffu);
|
||||||
PM4CmdSetData::SetContextReg(cmdbuf, 0x2aau, reg_value); // IA_MULTI_VGT_PARAM
|
PM4CmdSetData::SetContextReg(cmdbuf, 0x2aau, reg_value); // IA_MULTI_VGT_PARAM
|
||||||
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2202,10 +2072,26 @@ int PS4_SYSV_ABI sceGnmSubmitCommandBuffersForWorkload(u32 workload, u32 count,
|
|||||||
if (sdk_version <= 0x1ffffffu) {
|
if (sdk_version <= 0x1ffffffu) {
|
||||||
liverpool->SubmitGfx(InitSequence, {});
|
liverpool->SubmitGfx(InitSequence, {});
|
||||||
} else if (sdk_version <= 0x3ffffffu) {
|
} else if (sdk_version <= 0x3ffffffu) {
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
liverpool->SubmitGfx(InitSequence200Neo, {});
|
||||||
|
} else {
|
||||||
|
liverpool->SubmitGfx(InitSequence200NeoCompat, {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
liverpool->SubmitGfx(InitSequence200, {});
|
liverpool->SubmitGfx(InitSequence200, {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sceKernelIsNeoMode()) {
|
||||||
|
if (!UseNeoCompatSequences) {
|
||||||
|
liverpool->SubmitGfx(InitSequence350Neo, {});
|
||||||
|
} else {
|
||||||
|
liverpool->SubmitGfx(InitSequence350NeoCompat, {});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
liverpool->SubmitGfx(InitSequence350, {});
|
liverpool->SubmitGfx(InitSequence350, {});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
send_init_packet = false;
|
send_init_packet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ int PS4_SYSV_ABI sceGnmDisableMipStatsReport();
|
|||||||
s32 PS4_SYSV_ABI sceGnmDispatchDirect(u32* cmdbuf, u32 size, u32 threads_x, u32 threads_y,
|
s32 PS4_SYSV_ABI sceGnmDispatchDirect(u32* cmdbuf, u32 size, u32 threads_x, u32 threads_y,
|
||||||
u32 threads_z, u32 flags);
|
u32 threads_z, u32 flags);
|
||||||
s32 PS4_SYSV_ABI sceGnmDispatchIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32 flags);
|
s32 PS4_SYSV_ABI sceGnmDispatchIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32 flags);
|
||||||
int PS4_SYSV_ABI sceGnmDispatchIndirectOnMec();
|
s32 PS4_SYSV_ABI sceGnmDispatchIndirectOnMec(u32* cmdbuf, u32 size, VAddr args, u32 modifier);
|
||||||
u32 PS4_SYSV_ABI sceGnmDispatchInitDefaultHardwareState(u32* cmdbuf, u32 size);
|
u32 PS4_SYSV_ABI sceGnmDispatchInitDefaultHardwareState(u32* cmdbuf, u32 size);
|
||||||
s32 PS4_SYSV_ABI sceGnmDrawIndex(u32* cmdbuf, u32 size, u32 index_count, uintptr_t index_addr,
|
s32 PS4_SYSV_ABI sceGnmDrawIndex(u32* cmdbuf, u32 size, u32 index_count, uintptr_t index_addr,
|
||||||
u32 flags, u32 type);
|
u32 flags, u32 type);
|
||||||
@ -85,7 +85,7 @@ int PS4_SYSV_ABI sceGnmGetCoredumpMode();
|
|||||||
int PS4_SYSV_ABI sceGnmGetCoredumpProtectionFaultTimestamp();
|
int PS4_SYSV_ABI sceGnmGetCoredumpProtectionFaultTimestamp();
|
||||||
int PS4_SYSV_ABI sceGnmGetDbgGcHandle();
|
int PS4_SYSV_ABI sceGnmGetDbgGcHandle();
|
||||||
int PS4_SYSV_ABI sceGnmGetDebugTimestamp();
|
int PS4_SYSV_ABI sceGnmGetDebugTimestamp();
|
||||||
int PS4_SYSV_ABI sceGnmGetEqEventType();
|
int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev);
|
||||||
int PS4_SYSV_ABI sceGnmGetEqTimeStamp();
|
int PS4_SYSV_ABI sceGnmGetEqTimeStamp();
|
||||||
int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
|
int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
|
||||||
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
|
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
|
||||||
|
542
src/core/libraries/gnmdriver/gnmdriver_init.h
Normal file
542
src/core/libraries/gnmdriver/gnmdriver_init.h
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace Libraries::GnmDriver {
|
||||||
|
|
||||||
|
constexpr auto HwInitPacketSize = 0x100u;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
constexpr std::array InitSequence{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1ffu,
|
||||||
|
0xc0017600u, 0x87u, 0x1ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1ffu,
|
||||||
|
0xc0017600u, 0x107u, 0u,
|
||||||
|
0xc0017600u, 0x147u, 0x1ffu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6000000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence.size() == 0x73 + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence175{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1ffu,
|
||||||
|
0xc0017600u, 0x87u, 0x1ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1ffu,
|
||||||
|
0xc0017600u, 0x107u, 0u,
|
||||||
|
0xc0017600u, 0x147u, 0x1ffu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence175.size() == 0x73 + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence200{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x87u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x107u, 0x17u,
|
||||||
|
0xc0017600u, 0x147u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x47u, 0x1cu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence200.size() == 0x76 + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence200Neo{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x219u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x21au, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x87u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x107u, 0x17u,
|
||||||
|
0xc0017600u, 0x147u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x47u, 0x1cu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
0xc0017900u, 0x40000258u, 0x6d007fu,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence200Neo.size() == 0x83 + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence200NeoCompat{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x219u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x21au, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x87u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x107u, 0x17u,
|
||||||
|
0xc0017600u, 0x147u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x47u, 0x1cu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
0xc0016900u, 0x100002aau, 0xd00ffu,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence200NeoCompat.size() == 0x83 + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence350{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x87u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x107u, 0x17u,
|
||||||
|
0xc0017600u, 0x147u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x47u, 0x1cu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
0xc0016900u, 0x2aau, 0xffu,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence350.size() == 0x7c + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence350Neo{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x219u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x21au, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x87u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x107u, 0x17u,
|
||||||
|
0xc0017600u, 0x147u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x47u, 0x1cu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
0xc0017900u, 0x40000258u, 0x6d007fu,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence350Neo.size() == 0x86 + 2);
|
||||||
|
|
||||||
|
constexpr std::array InitSequence350NeoCompat{
|
||||||
|
// A fake preamble to mimic context reset sent by FW
|
||||||
|
0xc0001200u, 0u, // IT_CLEAR_STATE
|
||||||
|
|
||||||
|
// Actual init state sequence
|
||||||
|
0xc0017600u, 0x216u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x217u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x219u, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x21au, 0xffffffffu,
|
||||||
|
0xc0017600u, 0x215u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0017600u, 7u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0x46u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x87u, 0x1701ffu,
|
||||||
|
0xc0017600u, 0xc7u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x107u, 0x17u,
|
||||||
|
0xc0017600u, 0x147u, 0x1701fdu,
|
||||||
|
0xc0017600u, 0x47u, 0x1cu,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x200u, 0xe0000000u,
|
||||||
|
0xc0016900u, 0x100002aau, 0xd00ffu,
|
||||||
|
};
|
||||||
|
static_assert(InitSequence350NeoCompat.size() == 0x86 + 2);
|
||||||
|
|
||||||
|
constexpr std::array CtxInitSequence{
|
||||||
|
0xc0012800u, 0x80000000u, 0x80000000u,
|
||||||
|
0xc0001200u, 0u,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0111000u, 0u
|
||||||
|
};
|
||||||
|
static_assert(CtxInitSequence.size() == 0x0f);
|
||||||
|
|
||||||
|
constexpr std::array CtxInitSequenceNeo{
|
||||||
|
0xc0012800u, 0x80000000u, 0x80000000u,
|
||||||
|
0xc0001200u, 0u,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc00d1000, 0u
|
||||||
|
};
|
||||||
|
static_assert(CtxInitSequenceNeo.size() == 0x13);
|
||||||
|
|
||||||
|
constexpr std::array CtxInitSequence400{
|
||||||
|
0xc0012800u, 0x80000000u, 0x80000000u,
|
||||||
|
0xc0001200u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0016900u, 0x2aau, 0xffu,
|
||||||
|
0xc09e1000u,
|
||||||
|
};
|
||||||
|
static_assert(CtxInitSequence400.size() == 0x61);
|
||||||
|
|
||||||
|
constexpr std::array CtxInitSequence400Neo{
|
||||||
|
0xc0012800u, 0x80000000u, 0x80000000u,
|
||||||
|
0xc0001200u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0017900u, 0x40000258u, 0x6d007fu,
|
||||||
|
0xc09a1000u,
|
||||||
|
};
|
||||||
|
static_assert(CtxInitSequence400Neo.size() == 0x65);
|
||||||
|
|
||||||
|
constexpr std::array CtxInitSequence400NeoCompat{
|
||||||
|
0xc0012800u, 0x80000000u, 0x80000000u,
|
||||||
|
0xc0001200u, 0u,
|
||||||
|
0xc0016900u, 0x2f9u, 0x2du,
|
||||||
|
0xc0016900u, 0x282u, 8u,
|
||||||
|
0xc0016900u, 0x280u, 0x80008u,
|
||||||
|
0xc0016900u, 0x281u, 0xffff0000u,
|
||||||
|
0xc0016900u, 0x204u, 0u,
|
||||||
|
0xc0016900u, 0x206u, 0x43fu,
|
||||||
|
0xc0016900u, 0x83u, 0xffffu,
|
||||||
|
0xc0016900u, 0x317u, 0x10u,
|
||||||
|
0xc0016900u, 0x2fau, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fcu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fbu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x2fdu, 0x3f800000u,
|
||||||
|
0xc0016900u, 0x202u, 0xcc0010u,
|
||||||
|
0xc0016900u, 0x30eu, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x30fu, 0xffffffffu,
|
||||||
|
0xc0002f00u, 1u,
|
||||||
|
0xc0016900u, 0x1b1u, 2u,
|
||||||
|
0xc0016900u, 0x101u, 0u,
|
||||||
|
0xc0016900u, 0x100u, 0xffffffffu,
|
||||||
|
0xc0016900u, 0x103u, 0u,
|
||||||
|
0xc0016900u, 0x284u, 0u,
|
||||||
|
0xc0016900u, 0x290u, 0u,
|
||||||
|
0xc0016900u, 0x2aeu, 0u,
|
||||||
|
0xc0016900u, 0x102u, 0u,
|
||||||
|
0xc0016900u, 0x292u, 0u,
|
||||||
|
0xc0016900u, 0x293u, 0x6020000u,
|
||||||
|
0xc0016900u, 0x2f8u, 0u,
|
||||||
|
0xc0016900u, 0x2deu, 0x1e9u,
|
||||||
|
0xc0026900u, 0xebu, 0xff00ff00u, 0xff00u,
|
||||||
|
0xc0036900u, 0x295u, 0x100u, 0x100u, 4u,
|
||||||
|
0xc0016900u, 0x100002aau, 0xd00ffu,
|
||||||
|
0xc09a1000u,
|
||||||
|
};
|
||||||
|
static_assert(CtxInitSequence400Neo.size() == 0x65);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
} // namespace Libraries::GnmDriver
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
|
// Events are uniquely identified by id and filter.
|
||||||
|
|
||||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
@ -27,12 +29,13 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EqueueInternal::RemoveEvent(u64 id) {
|
bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
|
||||||
bool has_found = false;
|
bool has_found = false;
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
const auto& it =
|
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||||
std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; });
|
return ev.event.ident == id && ev.event.filter == filter;
|
||||||
|
});
|
||||||
if (it != m_events.cend()) {
|
if (it != m_events.cend()) {
|
||||||
m_events.erase(it);
|
m_events.erase(it);
|
||||||
has_found = true;
|
has_found = true;
|
||||||
@ -68,7 +71,7 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
|
|||||||
|
|
||||||
if (ev->flags & SceKernelEvent::Flags::OneShot) {
|
if (ev->flags & SceKernelEvent::Flags::OneShot) {
|
||||||
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
|
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
|
||||||
RemoveEvent(ev->ident);
|
RemoveEvent(ev->ident, ev->filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +97,11 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (auto& event : m_events) {
|
for (auto& event : m_events) {
|
||||||
if (event.IsTriggered()) {
|
if (event.IsTriggered()) {
|
||||||
|
// Event should not trigger again
|
||||||
|
event.ResetTriggerState();
|
||||||
|
|
||||||
if (event.event.flags & SceKernelEvent::Flags::Clear) {
|
if (event.event.flags & SceKernelEvent::Flags::Clear) {
|
||||||
event.Reset();
|
event.Clear();
|
||||||
}
|
}
|
||||||
ev[count++] = event.event;
|
ev[count++] = event.event;
|
||||||
if (count == num) {
|
if (count == num) {
|
||||||
@ -277,6 +283,19 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) {
|
||||||
|
if (eq == nullptr) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eq->HasSmallTimer()) {
|
||||||
|
return eq->RemoveSmallTimer(id) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
|
} else {
|
||||||
|
return eq->RemoveEvent(id, SceKernelEvent::Filter::HrTimer) ? ORBIS_OK
|
||||||
|
: ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
||||||
if (eq == nullptr) {
|
if (eq == nullptr) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
@ -334,16 +353,20 @@ int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) {
|
|||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eq->RemoveEvent(id)) {
|
if (!eq->RemoveEvent(id, SceKernelEvent::Filter::User)) {
|
||||||
return ORBIS_KERNEL_ERROR_ENOENT;
|
return ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s16 PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) {
|
int PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) {
|
||||||
return ev->filter;
|
return ev->filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev) {
|
||||||
|
return ev->data;
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue);
|
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue);
|
||||||
LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue);
|
LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue);
|
||||||
@ -352,10 +375,12 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
|||||||
LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
|
LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
|
||||||
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
|
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
|
||||||
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
|
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
|
||||||
|
LIB_FUNCTION("J+LF6LwObXU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteHRTimerEvent);
|
||||||
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
|
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
|
||||||
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
||||||
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
|
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
|
||||||
LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter);
|
LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter);
|
||||||
|
LIB_FUNCTION("kwGyyjohI50", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventData);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
@ -66,8 +66,11 @@ struct EqueueEvent {
|
|||||||
std::chrono::steady_clock::time_point time_added;
|
std::chrono::steady_clock::time_point time_added;
|
||||||
std::unique_ptr<boost::asio::steady_timer> timer;
|
std::unique_ptr<boost::asio::steady_timer> timer;
|
||||||
|
|
||||||
void Reset() {
|
void ResetTriggerState() {
|
||||||
is_triggered = false;
|
is_triggered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() {
|
||||||
event.fflags = 0;
|
event.fflags = 0;
|
||||||
event.data = 0;
|
event.data = 0;
|
||||||
}
|
}
|
||||||
@ -83,7 +86,7 @@ struct EqueueEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const EqueueEvent& ev) const {
|
bool operator==(const EqueueEvent& ev) const {
|
||||||
return ev.event.ident == event.ident;
|
return ev.event.ident == event.ident && ev.event.filter == event.filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -99,7 +102,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AddEvent(EqueueEvent& event);
|
bool AddEvent(EqueueEvent& event);
|
||||||
bool RemoveEvent(u64 id);
|
bool RemoveEvent(u64 id, s16 filter);
|
||||||
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||||
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
|
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||||
int GetTriggeredEvents(SceKernelEvent* ev, int num);
|
int GetTriggeredEvents(SceKernelEvent* ev, int num);
|
||||||
@ -108,6 +111,13 @@ public:
|
|||||||
bool HasSmallTimer() const {
|
bool HasSmallTimer() const {
|
||||||
return small_timer_event.event.data != 0;
|
return small_timer_event.event.data != 0;
|
||||||
}
|
}
|
||||||
|
bool RemoveSmallTimer(u64 id) {
|
||||||
|
if (HasSmallTimer() && small_timer_event.event.ident == id) {
|
||||||
|
small_timer_event = {};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
|
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
|
||||||
|
|
||||||
@ -122,6 +132,8 @@ private:
|
|||||||
using SceKernelUseconds = u32;
|
using SceKernelUseconds = u32;
|
||||||
using SceKernelEqueue = EqueueInternal*;
|
using SceKernelEqueue = EqueueInternal*;
|
||||||
|
|
||||||
|
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
|
||||||
|
|
||||||
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
@ -46,17 +46,6 @@ static std::map<std::string, FactoryDevice> available_device = {
|
|||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
auto GetDirectoryEntries(const std::filesystem::path& path) {
|
|
||||||
std::vector<Core::FileSys::DirEntry> files;
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(path)) {
|
|
||||||
auto& dir_entry = files.emplace_back();
|
|
||||||
dir_entry.name = entry.path().filename().string();
|
|
||||||
dir_entry.isFile = !std::filesystem::is_directory(entry.path().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
|
int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
|
||||||
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", raw_path, flags, mode);
|
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", raw_path, flags, mode);
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
@ -115,7 +104,12 @@ int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
|
|||||||
if (create) {
|
if (create) {
|
||||||
return handle; // dir already exists
|
return handle; // dir already exists
|
||||||
} else {
|
} else {
|
||||||
file->dirents = GetDirectoryEntries(file->m_host_name);
|
mnt->IterateDirectory(file->m_guest_name,
|
||||||
|
[&file](const auto& ent_path, const auto ent_is_file) {
|
||||||
|
auto& dir_entry = file->dirents.emplace_back();
|
||||||
|
dir_entry.name = ent_path.filename().string();
|
||||||
|
dir_entry.isFile = ent_is_file;
|
||||||
|
});
|
||||||
file->dirents_index = 0;
|
file->dirents_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -695,66 +689,12 @@ static int GetDents(int fd, char* buf, int nbytes, s64* basep) {
|
|||||||
return sizeof(OrbisKernelDirent);
|
return sizeof(OrbisKernelDirent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int HandleSeparateUpdateDents(int fd, char* buf, int nbytes, s64* basep) {
|
|
||||||
int dir_entries = 0;
|
|
||||||
|
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
|
||||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
|
||||||
auto* file = h->GetFile(fd);
|
|
||||||
auto update_dir_name = std::string{fmt::UTF(file->m_host_name.u8string()).data};
|
|
||||||
auto mount = mnt->GetMountFromHostPath(update_dir_name);
|
|
||||||
auto suffix = std::string{fmt::UTF(mount->host_path.u8string()).data};
|
|
||||||
|
|
||||||
size_t pos = update_dir_name.find("-UPDATE");
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
update_dir_name.erase(pos, 7);
|
|
||||||
auto guest_name = mount->mount + "/" + update_dir_name.substr(suffix.size() + 1);
|
|
||||||
int descriptor;
|
|
||||||
|
|
||||||
auto existent_folder = h->GetFile(update_dir_name);
|
|
||||||
if (!existent_folder) {
|
|
||||||
u32 handle = h->CreateHandle();
|
|
||||||
auto* new_file = h->GetFile(handle);
|
|
||||||
new_file->type = Core::FileSys::FileType::Directory;
|
|
||||||
new_file->m_guest_name = guest_name;
|
|
||||||
new_file->m_host_name = update_dir_name;
|
|
||||||
if (!std::filesystem::is_directory(new_file->m_host_name)) {
|
|
||||||
h->DeleteHandle(handle);
|
|
||||||
return dir_entries;
|
|
||||||
} else {
|
|
||||||
new_file->dirents = GetDirectoryEntries(new_file->m_host_name);
|
|
||||||
new_file->dirents_index = 0;
|
|
||||||
}
|
|
||||||
new_file->is_opened = true;
|
|
||||||
descriptor = h->GetFileDescriptor(new_file);
|
|
||||||
} else {
|
|
||||||
descriptor = h->GetFileDescriptor(existent_folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
dir_entries = GetDents(descriptor, buf, nbytes, basep);
|
|
||||||
if (dir_entries == ORBIS_OK && existent_folder) {
|
|
||||||
existent_folder->dirents_index = 0;
|
|
||||||
file->dirents_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) {
|
int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) {
|
||||||
int a = GetDents(fd, buf, nbytes, nullptr);
|
return GetDents(fd, buf, nbytes, nullptr);
|
||||||
if (a == ORBIS_OK) {
|
|
||||||
return HandleSeparateUpdateDents(fd, buf, nbytes, nullptr);
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelGetdirentries(int fd, char* buf, int nbytes, s64* basep) {
|
int PS4_SYSV_ABI sceKernelGetdirentries(int fd, char* buf, int nbytes, s64* basep) {
|
||||||
int a = GetDents(fd, buf, nbytes, basep);
|
return GetDents(fd, buf, nbytes, basep);
|
||||||
if (a == ORBIS_OK) {
|
|
||||||
return HandleSeparateUpdateDents(fd, buf, nbytes, basep);
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) {
|
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) {
|
||||||
|
@ -505,6 +505,41 @@ int PS4_SYSV_ABI posix_munmap(void* addr, size_t len) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int MAX_PRT_APERTURES = 3;
|
||||||
|
static constexpr VAddr PRT_AREA_START_ADDR = 0x1000000000;
|
||||||
|
static constexpr size_t PRT_AREA_SIZE = 0xec00000000;
|
||||||
|
static std::array<std::pair<VAddr, size_t>, MAX_PRT_APERTURES> PrtApertures{};
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelSetPrtAperture(int id, VAddr address, size_t size) {
|
||||||
|
if (id < 0 || id >= MAX_PRT_APERTURES) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address < PRT_AREA_START_ADDR || address + size > PRT_AREA_START_ADDR + PRT_AREA_SIZE) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address % 4096 != 0) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARNING(Kernel_Vmm,
|
||||||
|
"PRT aperture id = {}, address = {:#x}, size = {:#x} is set but not used", id,
|
||||||
|
address, size);
|
||||||
|
|
||||||
|
PrtApertures[id] = {address, size};
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelGetPrtAperture(int id, VAddr* address, size_t* size) {
|
||||||
|
if (id < 0 || id >= MAX_PRT_APERTURES) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tie(*address, *size) = PrtApertures[id];
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
|
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
|
||||||
LIB_FUNCTION("B+vc2AO2Zrc", "libkernel", 1, "libkernel", 1, 1,
|
LIB_FUNCTION("B+vc2AO2Zrc", "libkernel", 1, "libkernel", 1, 1,
|
||||||
@ -551,6 +586,10 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
|||||||
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);
|
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);
|
||||||
LIB_FUNCTION("UqDGjXA5yUM", "libkernel", 1, "libkernel", 1, 1, posix_munmap);
|
LIB_FUNCTION("UqDGjXA5yUM", "libkernel", 1, "libkernel", 1, 1, posix_munmap);
|
||||||
LIB_FUNCTION("UqDGjXA5yUM", "libScePosix", 1, "libkernel", 1, 1, posix_munmap);
|
LIB_FUNCTION("UqDGjXA5yUM", "libScePosix", 1, "libkernel", 1, 1, posix_munmap);
|
||||||
|
|
||||||
|
// PRT memory management
|
||||||
|
LIB_FUNCTION("BohYr-F7-is", "libkernel", 1, "libkernel", 1, 1, sceKernelSetPrtAperture);
|
||||||
|
LIB_FUNCTION("L0v2Go5jOuM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetPrtAperture);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5056_MB; // ~ 5GB
|
constexpr u64 SCE_KERNEL_TOTAL_MEM = 5248_MB;
|
||||||
// TODO: Confirm this value on hardware.
|
constexpr u64 SCE_KERNEL_TOTAL_MEM_PRO = 5888_MB;
|
||||||
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE_PRO = 5568_MB; // ~ 5.5GB
|
|
||||||
|
constexpr u64 SCE_FLEXIBLE_MEMORY_BASE = 64_MB;
|
||||||
|
constexpr u64 SCE_FLEXIBLE_MEMORY_SIZE = 512_MB;
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
@ -129,10 +131,6 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
|
|||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
|
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
|
||||||
|
|
||||||
void* Malloc(size_t size);
|
|
||||||
|
|
||||||
void Free(void* ptr);
|
|
||||||
|
|
||||||
void RegisterMemory(Core::Loader::SymbolsResolver* sym);
|
void RegisterMemory(Core::Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
@ -14,7 +14,8 @@ namespace Libraries::Kernel {
|
|||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelIsNeoMode() {
|
int PS4_SYSV_ABI sceKernelIsNeoMode() {
|
||||||
LOG_DEBUG(Kernel_Sce, "called");
|
LOG_DEBUG(Kernel_Sce, "called");
|
||||||
return Config::isNeoMode();
|
return Config::isNeoModeConsole() &&
|
||||||
|
Common::ElfInfo::Instance().GetPSFAttributes().support_neo_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver) {
|
int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver) {
|
||||||
|
@ -55,6 +55,9 @@ public:
|
|||||||
stop.request_stop();
|
stop.request_stop();
|
||||||
Join();
|
Join();
|
||||||
}
|
}
|
||||||
|
thread = nullptr;
|
||||||
|
func = nullptr;
|
||||||
|
stop = std::stop_source{};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* PS4_SYSV_ABI RunWrapper(void* arg) {
|
static void* PS4_SYSV_ABI RunWrapper(void* arg) {
|
||||||
|
@ -244,10 +244,9 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||||||
new_thread->tid = ++TidCounter;
|
new_thread->tid = ++TidCounter;
|
||||||
|
|
||||||
if (new_thread->attr.stackaddr_attr == 0) {
|
if (new_thread->attr.stackaddr_attr == 0) {
|
||||||
/* Enforce minimum stack size of 64 KB */
|
/* Add additional stack space for HLE */
|
||||||
static constexpr size_t MinimumStack = 64_KB;
|
static constexpr size_t AdditionalStack = 128_KB;
|
||||||
auto& stacksize = new_thread->attr.stacksize_attr;
|
new_thread->attr.stacksize_attr += AdditionalStack;
|
||||||
stacksize = std::max(stacksize, MinimumStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread_state->CreateStack(&new_thread->attr) != 0) {
|
if (thread_state->CreateStack(&new_thread->attr) != 0) {
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libpng/pngdec.h"
|
#include "core/libraries/libpng/pngdec.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/libraries/mouse/mouse.h"
|
||||||
|
#include "core/libraries/move/move.h"
|
||||||
#include "core/libraries/network/http.h"
|
#include "core/libraries/network/http.h"
|
||||||
#include "core/libraries/network/net.h"
|
#include "core/libraries/network/net.h"
|
||||||
#include "core/libraries/network/netctl.h"
|
#include "core/libraries/network/netctl.h"
|
||||||
@ -46,6 +48,8 @@
|
|||||||
#include "core/libraries/videodec/videodec.h"
|
#include "core/libraries/videodec/videodec.h"
|
||||||
#include "core/libraries/videodec/videodec2.h"
|
#include "core/libraries/videodec/videodec2.h"
|
||||||
#include "core/libraries/videoout/video_out.h"
|
#include "core/libraries/videoout/video_out.h"
|
||||||
|
#include "fiber/fiber.h"
|
||||||
|
#include "jpeg/jpegenc.h"
|
||||||
|
|
||||||
namespace Libraries {
|
namespace Libraries {
|
||||||
|
|
||||||
@ -91,6 +95,10 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||||||
Libraries::Remoteplay::RegisterlibSceRemoteplay(sym);
|
Libraries::Remoteplay::RegisterlibSceRemoteplay(sym);
|
||||||
Libraries::Videodec::RegisterlibSceVideodec(sym);
|
Libraries::Videodec::RegisterlibSceVideodec(sym);
|
||||||
Libraries::RazorCpu::RegisterlibSceRazorCpu(sym);
|
Libraries::RazorCpu::RegisterlibSceRazorCpu(sym);
|
||||||
|
Libraries::Move::RegisterlibSceMove(sym);
|
||||||
|
Libraries::Fiber::RegisterlibSceFiber(sym);
|
||||||
|
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
|
||||||
|
Libraries::Mouse::RegisterlibSceMouse(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries
|
} // namespace Libraries
|
||||||
|
99
src/core/libraries/mouse/mouse.cpp
Normal file
99
src/core/libraries/mouse/mouse.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
// Generated By moduleGenerator
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
#include "mouse.h"
|
||||||
|
|
||||||
|
namespace Libraries::Mouse {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseClose() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseConnectPort() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseDebugGetDeviceId() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseDeviceOpen() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseDisconnectDevice() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseDisconnectPort() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseGetDeviceInfo() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseInit() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseMbusInit() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseOpen() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseRead() {
|
||||||
|
LOG_DEBUG(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseSetHandType() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseSetPointerSpeed() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseSetProcessPrivilege() {
|
||||||
|
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceMouse(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("cAnT0Rw-IwU", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseClose);
|
||||||
|
LIB_FUNCTION("Ymyy1HSSJLQ", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseConnectPort);
|
||||||
|
LIB_FUNCTION("BRXOoXQtb+k", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDebugGetDeviceId);
|
||||||
|
LIB_FUNCTION("WiGKINCZWkc", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDeviceOpen);
|
||||||
|
LIB_FUNCTION("eDQTFHbgeTU", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDisconnectDevice);
|
||||||
|
LIB_FUNCTION("jJP1vYMEPd4", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseDisconnectPort);
|
||||||
|
LIB_FUNCTION("QA9Qupz3Zjw", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseGetDeviceInfo);
|
||||||
|
LIB_FUNCTION("Qs0wWulgl7U", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseInit);
|
||||||
|
LIB_FUNCTION("1FeceR5YhAo", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseMbusInit);
|
||||||
|
LIB_FUNCTION("RaqxZIf6DvE", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseOpen);
|
||||||
|
LIB_FUNCTION("x8qnXqh-tiM", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseRead);
|
||||||
|
LIB_FUNCTION("crkFfp-cmFo", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseSetHandType);
|
||||||
|
LIB_FUNCTION("ghLUU2Z5Lcg", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseSetPointerSpeed);
|
||||||
|
LIB_FUNCTION("6aANndpS0Wo", "libSceMouse", 1, "libSceMouse", 1, 1, sceMouseSetProcessPrivilege);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Mouse
|
29
src/core/libraries/mouse/mouse.h
Normal file
29
src/core/libraries/mouse/mouse.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
namespace Core::Loader {
|
||||||
|
class SymbolsResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Mouse {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMouseClose();
|
||||||
|
int PS4_SYSV_ABI sceMouseConnectPort();
|
||||||
|
int PS4_SYSV_ABI sceMouseDebugGetDeviceId();
|
||||||
|
int PS4_SYSV_ABI sceMouseDeviceOpen();
|
||||||
|
int PS4_SYSV_ABI sceMouseDisconnectDevice();
|
||||||
|
int PS4_SYSV_ABI sceMouseDisconnectPort();
|
||||||
|
int PS4_SYSV_ABI sceMouseGetDeviceInfo();
|
||||||
|
int PS4_SYSV_ABI sceMouseInit();
|
||||||
|
int PS4_SYSV_ABI sceMouseMbusInit();
|
||||||
|
int PS4_SYSV_ABI sceMouseOpen();
|
||||||
|
int PS4_SYSV_ABI sceMouseRead();
|
||||||
|
int PS4_SYSV_ABI sceMouseSetHandType();
|
||||||
|
int PS4_SYSV_ABI sceMouseSetPointerSpeed();
|
||||||
|
int PS4_SYSV_ABI sceMouseSetProcessPrivilege();
|
||||||
|
|
||||||
|
void RegisterlibSceMouse(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Mouse
|
44
src/core/libraries/move/move.cpp
Normal file
44
src/core/libraries/move/move.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
#include "move.h"
|
||||||
|
|
||||||
|
namespace Libraries::Move {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMoveOpen() {
|
||||||
|
LOG_ERROR(Lib_Move, "(STUBBED) called");
|
||||||
|
return ORBIS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMoveGetDeviceInfo() {
|
||||||
|
LOG_ERROR(Lib_Move, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMoveReadStateRecent() {
|
||||||
|
LOG_TRACE(Lib_Move, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMoveTerm() {
|
||||||
|
LOG_ERROR(Lib_Move, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMoveInit() {
|
||||||
|
LOG_ERROR(Lib_Move, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("HzC60MfjJxU", "libSceMove", 1, "libSceMove", 1, 1, sceMoveOpen);
|
||||||
|
LIB_FUNCTION("GWXTyxs4QbE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveGetDeviceInfo);
|
||||||
|
LIB_FUNCTION("f2bcpK6kJfg", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateRecent);
|
||||||
|
LIB_FUNCTION("tsZi60H4ypY", "libSceMove", 1, "libSceMove", 1, 1, sceMoveTerm);
|
||||||
|
LIB_FUNCTION("j1ITE-EoJmE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveInit);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Move
|
21
src/core/libraries/move/move.h
Normal file
21
src/core/libraries/move/move.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
namespace Core::Loader {
|
||||||
|
class SymbolsResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Move {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceMoveOpen();
|
||||||
|
int PS4_SYSV_ABI sceMoveGetDeviceInfo();
|
||||||
|
int PS4_SYSV_ABI sceMoveReadStateRecent();
|
||||||
|
int PS4_SYSV_ABI sceMoveTerm();
|
||||||
|
int PS4_SYSV_ABI sceMoveInit();
|
||||||
|
|
||||||
|
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Move
|
@ -972,11 +972,8 @@ int PS4_SYSV_ABI sceNpGetGamePresenceStatusA() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id) {
|
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id) {
|
||||||
LOG_INFO(Lib_NpManager, "user_id {}", user_id);
|
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||||
const auto name = Config::getUserName();
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
std::memset(np_id, 0, sizeof(OrbisNpId));
|
|
||||||
name.copy(np_id->handle.data, sizeof(np_id->handle.data));
|
|
||||||
return ORBIS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
||||||
@ -986,10 +983,7 @@ int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
|||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetOnlineId(s32 user_id, OrbisNpOnlineId* online_id) {
|
int PS4_SYSV_ABI sceNpGetOnlineId(s32 user_id, OrbisNpOnlineId* online_id) {
|
||||||
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||||
const auto name = Config::getUserName();
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
std::memset(online_id, 0, sizeof(OrbisNpOnlineId));
|
|
||||||
name.copy(online_id->data, sizeof(online_id->data));
|
|
||||||
return ORBIS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
||||||
|
@ -498,7 +498,7 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(OrbisNpTrophyContext context, OrbisNpT
|
|||||||
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
|
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
|
||||||
OrbisNpTrophyHandle handle,
|
OrbisNpTrophyHandle handle,
|
||||||
OrbisNpTrophyFlagArray* flags, u32* count) {
|
OrbisNpTrophyFlagArray* flags, u32* count) {
|
||||||
LOG_INFO(Lib_NpTrophy, "GetTrophyUnlockState called");
|
LOG_INFO(Lib_NpTrophy, "called");
|
||||||
|
|
||||||
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
|
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
|
||||||
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
|
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
|
||||||
@ -519,8 +519,9 @@ s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
|
|||||||
pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str());
|
pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str());
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy xml : {}", result.description());
|
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy XML: {}", result.description());
|
||||||
return -1;
|
*count = 0;
|
||||||
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_trophies = 0;
|
int num_trophies = 0;
|
||||||
|
@ -286,6 +286,7 @@ int PS4_SYSV_ABI scePadOutputReport() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
||||||
|
LOG_TRACE(Lib_Pad, "called");
|
||||||
int connected_count = 0;
|
int connected_count = 0;
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
Input::State states[64];
|
Input::State states[64];
|
||||||
@ -304,16 +305,15 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||||||
pData[i].rightStick.y = states[i].axes[static_cast<int>(Input::Axis::RightY)];
|
pData[i].rightStick.y = states[i].axes[static_cast<int>(Input::Axis::RightY)];
|
||||||
pData[i].analogButtons.l2 = states[i].axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
pData[i].analogButtons.l2 = states[i].axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||||
pData[i].analogButtons.r2 = states[i].axes[static_cast<int>(Input::Axis::TriggerRight)];
|
pData[i].analogButtons.r2 = states[i].axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||||
pData[i].orientation.x = 0.0f;
|
pData[i].acceleration.x = states[i].acceleration.x;
|
||||||
pData[i].orientation.y = 0.0f;
|
pData[i].acceleration.y = states[i].acceleration.y;
|
||||||
pData[i].orientation.z = 0.0f;
|
pData[i].acceleration.z = states[i].acceleration.z;
|
||||||
pData[i].orientation.w = 1.0f;
|
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||||
pData[i].acceleration.x = 0.0f;
|
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||||
pData[i].acceleration.y = 0.0f;
|
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||||
pData[i].acceleration.z = 0.0f;
|
Input::GameController::CalculateOrientation(pData[i].acceleration, pData[i].angularVelocity,
|
||||||
pData[i].angularVelocity.x = 0.0f;
|
1.0f / controller->accel_poll_rate,
|
||||||
pData[i].angularVelocity.y = 0.0f;
|
pData[i].orientation);
|
||||||
pData[i].angularVelocity.z = 0.0f;
|
|
||||||
pData[i].touchData.touchNum =
|
pData[i].touchData.touchNum =
|
||||||
(states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0);
|
(states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0);
|
||||||
pData[i].touchData.touch[0].x = states[i].touchpad[0].x;
|
pData[i].touchData.touch[0].x = states[i].touchpad[0].x;
|
||||||
@ -352,6 +352,7 @@ int PS4_SYSV_ABI scePadReadHistory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
||||||
|
LOG_TRACE(Lib_Pad, "called");
|
||||||
if (handle == ORBIS_PAD_ERROR_DEVICE_NO_HANDLE) {
|
if (handle == ORBIS_PAD_ERROR_DEVICE_NO_HANDLE) {
|
||||||
return ORBIS_PAD_ERROR_INVALID_HANDLE;
|
return ORBIS_PAD_ERROR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
@ -367,16 +368,15 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||||||
pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)];
|
pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)];
|
||||||
pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||||
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
|
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||||
pData->orientation.x = 0;
|
pData->acceleration.x = state.acceleration.x;
|
||||||
pData->orientation.y = 0;
|
pData->acceleration.y = state.acceleration.y;
|
||||||
pData->orientation.z = 0;
|
pData->acceleration.z = state.acceleration.z;
|
||||||
pData->orientation.w = 1;
|
pData->angularVelocity.x = state.angularVelocity.x;
|
||||||
pData->acceleration.x = 0.0f;
|
pData->angularVelocity.y = state.angularVelocity.y;
|
||||||
pData->acceleration.y = 0.0f;
|
pData->angularVelocity.z = state.angularVelocity.z;
|
||||||
pData->acceleration.z = 0.0f;
|
Input::GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||||
pData->angularVelocity.x = 0.0f;
|
1.0f / controller->accel_poll_rate,
|
||||||
pData->angularVelocity.y = 0.0f;
|
pData->orientation);
|
||||||
pData->angularVelocity.z = 0.0f;
|
|
||||||
pData->touchData.touchNum =
|
pData->touchData.touchNum =
|
||||||
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
||||||
pData->touchData.touch[0].x = state.touchpad[0].x;
|
pData->touchData.touch[0].x = state.touchpad[0].x;
|
||||||
@ -498,6 +498,8 @@ int PS4_SYSV_ABI scePadSetLoginUserNumber() {
|
|||||||
int PS4_SYSV_ABI scePadSetMotionSensorState(s32 handle, bool bEnable) {
|
int PS4_SYSV_ABI scePadSetMotionSensorState(s32 handle, bool bEnable) {
|
||||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
|
// it's already handled by the SDL backend and will be on no matter what
|
||||||
|
// (assuming the controller supports it)
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadSetProcessFocus() {
|
int PS4_SYSV_ABI scePadSetProcessFocus() {
|
||||||
|
@ -157,7 +157,7 @@ s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < numberOfEntries; i++) {
|
for (int i = 0; i < numberOfEntries; i++) {
|
||||||
if (chunkIds[i] <= playgo->chunks.size()) {
|
if (chunkIds[i] < playgo->chunks.size()) {
|
||||||
outLoci[i] = OrbisPlayGoLocus::LocalFast;
|
outLoci[i] = OrbisPlayGoLocus::LocalFast;
|
||||||
} else {
|
} else {
|
||||||
outLoci[i] = OrbisPlayGoLocus::NotDownloaded;
|
outLoci[i] = OrbisPlayGoLocus::NotDownloaded;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <core/libraries/system/msgdialog_ui.h>
|
#include <core/libraries/system/msgdialog_ui.h>
|
||||||
@ -1139,10 +1140,6 @@ Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getPar
|
|||||||
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
||||||
return Error::MEMORY_NOT_READY;
|
return Error::MEMORY_NOT_READY;
|
||||||
}
|
}
|
||||||
if (SaveMemory::IsSaving()) {
|
|
||||||
LOG_TRACE(Lib_SaveData, "called while saving");
|
|
||||||
return Error::BUSY_FOR_SAVING;
|
|
||||||
}
|
|
||||||
LOG_DEBUG(Lib_SaveData, "called");
|
LOG_DEBUG(Lib_SaveData, "called");
|
||||||
auto data = getParam->data;
|
auto data = getParam->data;
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
@ -1501,10 +1498,16 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
|
|||||||
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
||||||
return Error::MEMORY_NOT_READY;
|
return Error::MEMORY_NOT_READY;
|
||||||
}
|
}
|
||||||
|
if (SaveMemory::IsSaving()) {
|
||||||
|
int count = 0;
|
||||||
|
while (++count < 100 && SaveMemory::IsSaving()) { // try for more 10 seconds
|
||||||
|
std::this_thread::sleep_for(chrono::milliseconds(100));
|
||||||
|
}
|
||||||
if (SaveMemory::IsSaving()) {
|
if (SaveMemory::IsSaving()) {
|
||||||
LOG_TRACE(Lib_SaveData, "called while saving");
|
LOG_TRACE(Lib_SaveData, "called while saving");
|
||||||
return Error::BUSY_FOR_SAVING;
|
return Error::BUSY_FOR_SAVING;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
LOG_DEBUG(Lib_SaveData, "called");
|
LOG_DEBUG(Lib_SaveData, "called");
|
||||||
auto data = setParam->data;
|
auto data = setParam->data;
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
@ -1584,8 +1587,8 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
|||||||
} else {
|
} else {
|
||||||
SaveMemory::SetIcon(nullptr, 0);
|
SaveMemory::SetIcon(nullptr, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
SaveMemory::TriggerSaveWithoutEvent();
|
SaveMemory::TriggerSaveWithoutEvent();
|
||||||
|
}
|
||||||
if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
|
if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
|
||||||
result->existedMemorySize = existed_size;
|
result->existedMemorySize = existed_size;
|
||||||
}
|
}
|
||||||
|
@ -10,327 +10,327 @@
|
|||||||
namespace Libraries::Usbd {
|
namespace Libraries::Usbd {
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdAllocTransfer() {
|
int PS4_SYSV_ABI sceUsbdAllocTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdAttachKernelDriver() {
|
int PS4_SYSV_ABI sceUsbdAttachKernelDriver() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdBulkTransfer() {
|
int PS4_SYSV_ABI sceUsbdBulkTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdCancelTransfer() {
|
int PS4_SYSV_ABI sceUsbdCancelTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdCheckConnected() {
|
int PS4_SYSV_ABI sceUsbdCheckConnected() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdClaimInterface() {
|
int PS4_SYSV_ABI sceUsbdClaimInterface() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdClearHalt() {
|
int PS4_SYSV_ABI sceUsbdClearHalt() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdClose() {
|
int PS4_SYSV_ABI sceUsbdClose() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdControlTransfer() {
|
int PS4_SYSV_ABI sceUsbdControlTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdControlTransferGetData() {
|
int PS4_SYSV_ABI sceUsbdControlTransferGetData() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdControlTransferGetSetup() {
|
int PS4_SYSV_ABI sceUsbdControlTransferGetSetup() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdDetachKernelDriver() {
|
int PS4_SYSV_ABI sceUsbdDetachKernelDriver() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdEventHandlerActive() {
|
int PS4_SYSV_ABI sceUsbdEventHandlerActive() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdEventHandlingOk() {
|
int PS4_SYSV_ABI sceUsbdEventHandlingOk() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdExit() {
|
int PS4_SYSV_ABI sceUsbdExit() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFillBulkTransfer() {
|
int PS4_SYSV_ABI sceUsbdFillBulkTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFillControlSetup() {
|
int PS4_SYSV_ABI sceUsbdFillControlSetup() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFillControlTransfer() {
|
int PS4_SYSV_ABI sceUsbdFillControlTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFillInterruptTransfer() {
|
int PS4_SYSV_ABI sceUsbdFillInterruptTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFillIsoTransfer() {
|
int PS4_SYSV_ABI sceUsbdFillIsoTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor() {
|
int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFreeDeviceList() {
|
int PS4_SYSV_ABI sceUsbdFreeDeviceList() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdFreeTransfer() {
|
int PS4_SYSV_ABI sceUsbdFreeTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor() {
|
int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetBusNumber() {
|
int PS4_SYSV_ABI sceUsbdGetBusNumber() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetConfigDescriptor() {
|
int PS4_SYSV_ABI sceUsbdGetConfigDescriptor() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue() {
|
int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetConfiguration() {
|
int PS4_SYSV_ABI sceUsbdGetConfiguration() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetDescriptor() {
|
int PS4_SYSV_ABI sceUsbdGetDescriptor() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetDevice() {
|
int PS4_SYSV_ABI sceUsbdGetDevice() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetDeviceAddress() {
|
int PS4_SYSV_ABI sceUsbdGetDeviceAddress() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor() {
|
int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetDeviceList() {
|
int PS4_SYSV_ABI sceUsbdGetDeviceList() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetDeviceSpeed() {
|
int PS4_SYSV_ABI sceUsbdGetDeviceSpeed() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer() {
|
int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize() {
|
int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetMaxPacketSize() {
|
int PS4_SYSV_ABI sceUsbdGetMaxPacketSize() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetStringDescriptor() {
|
int PS4_SYSV_ABI sceUsbdGetStringDescriptor() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii() {
|
int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdHandleEvents() {
|
int PS4_SYSV_ABI sceUsbdHandleEvents() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdHandleEventsLocked() {
|
int PS4_SYSV_ABI sceUsbdHandleEventsLocked() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdHandleEventsTimeout() {
|
int PS4_SYSV_ABI sceUsbdHandleEventsTimeout() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_DEBUG(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdInit() {
|
int PS4_SYSV_ABI sceUsbdInit() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return 0x80240005; // Skip
|
return 0x80240005; // Skip
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdInterruptTransfer() {
|
int PS4_SYSV_ABI sceUsbdInterruptTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdKernelDriverActive() {
|
int PS4_SYSV_ABI sceUsbdKernelDriverActive() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdLockEvents() {
|
int PS4_SYSV_ABI sceUsbdLockEvents() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdLockEventWaiters() {
|
int PS4_SYSV_ABI sceUsbdLockEventWaiters() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdOpen() {
|
int PS4_SYSV_ABI sceUsbdOpen() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid() {
|
int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdRefDevice() {
|
int PS4_SYSV_ABI sceUsbdRefDevice() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdReleaseInterface() {
|
int PS4_SYSV_ABI sceUsbdReleaseInterface() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdResetDevice() {
|
int PS4_SYSV_ABI sceUsbdResetDevice() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdSetConfiguration() {
|
int PS4_SYSV_ABI sceUsbdSetConfiguration() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting() {
|
int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths() {
|
int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdSubmitTransfer() {
|
int PS4_SYSV_ABI sceUsbdSubmitTransfer() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdTryLockEvents() {
|
int PS4_SYSV_ABI sceUsbdTryLockEvents() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdUnlockEvents() {
|
int PS4_SYSV_ABI sceUsbdUnlockEvents() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdUnlockEventWaiters() {
|
int PS4_SYSV_ABI sceUsbdUnlockEventWaiters() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdUnrefDevice() {
|
int PS4_SYSV_ABI sceUsbdUnrefDevice() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceUsbdWaitForEvent() {
|
int PS4_SYSV_ABI sceUsbdWaitForEvent() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI Func_65F6EF33E38FFF50() {
|
int PS4_SYSV_ABI Func_65F6EF33E38FFF50() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI Func_97F056BAD90AADE7() {
|
int PS4_SYSV_ABI Func_97F056BAD90AADE7() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI Func_C55104A33B35B264() {
|
int PS4_SYSV_ABI Func_C55104A33B35B264() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI Func_D56B43060720B1E0() {
|
int PS4_SYSV_ABI Func_D56B43060720B1E0() {
|
||||||
LOG_ERROR(Lib_Usbd, "(STUBBED)called");
|
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +52,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
|
|||||||
Kernel::EqueueEvent event{};
|
Kernel::EqueueEvent event{};
|
||||||
event.event.ident = u64(OrbisVideoOutEventId::Flip);
|
event.event.ident = u64(OrbisVideoOutEventId::Flip);
|
||||||
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
||||||
// The library only sets EV_ADD but kernel driver forces EV_CLEAR
|
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
||||||
event.event.flags = Kernel::SceKernelEvent::Flags::Clear;
|
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = 0;
|
event.event.data = 0;
|
||||||
@ -79,8 +78,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
|
|||||||
Kernel::EqueueEvent event{};
|
Kernel::EqueueEvent event{};
|
||||||
event.event.ident = u64(OrbisVideoOutEventId::Vblank);
|
event.event.ident = u64(OrbisVideoOutEventId::Vblank);
|
||||||
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
||||||
// The library only sets EV_ADD but kernel driver forces EV_CLEAR
|
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
||||||
event.event.flags = Kernel::SceKernelEvent::Flags::Clear;
|
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = 0;
|
event.event.data = 0;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "common/arch.h"
|
#include "common/arch.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
#include "common/elf_info.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
@ -65,20 +66,40 @@ void Linker::Execute() {
|
|||||||
Relocate(m.get());
|
Relocate(m.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure used flexible memory size.
|
// Configure the direct and flexible memory regions.
|
||||||
if (const auto* proc_param = GetProcParam()) {
|
u64 fmem_size = SCE_FLEXIBLE_MEMORY_SIZE;
|
||||||
if (proc_param->size >=
|
bool use_extended_mem1 = true, use_extended_mem2 = true;
|
||||||
offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
|
|
||||||
if (const auto* mem_param = proc_param->mem_param) {
|
const auto* proc_param = GetProcParam();
|
||||||
if (mem_param->size >=
|
ASSERT(proc_param);
|
||||||
|
|
||||||
|
Core::OrbisKernelMemParam mem_param{};
|
||||||
|
if (proc_param->size >= offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
|
||||||
|
if (proc_param->mem_param) {
|
||||||
|
mem_param = *proc_param->mem_param;
|
||||||
|
if (mem_param.size >=
|
||||||
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
|
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
|
||||||
if (const auto* flexible_size = mem_param->flexible_memory_size) {
|
if (const auto* flexible_size = mem_param.flexible_memory_size) {
|
||||||
memory->SetupMemoryRegions(*flexible_size);
|
fmem_size = *flexible_size + SCE_FLEXIBLE_MEMORY_BASE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_1) + sizeof(u64*)) {
|
||||||
|
mem_param.extended_memory_1 = nullptr;
|
||||||
}
|
}
|
||||||
|
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_2) + sizeof(u64*)) {
|
||||||
|
mem_param.extended_memory_2 = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u64 sdk_ver = proc_param->sdk_version;
|
||||||
|
if (sdk_ver < Common::ElfInfo::FW_50) {
|
||||||
|
use_extended_mem1 = mem_param.extended_memory_1 ? *mem_param.extended_memory_1 : false;
|
||||||
|
use_extended_mem2 = mem_param.extended_memory_2 ? *mem_param.extended_memory_2 : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
|
||||||
|
|
||||||
main_thread.Run([this, module](std::stop_token) {
|
main_thread.Run([this, module](std::stop_token) {
|
||||||
Common::SetCurrentThreadName("GAME_MainThread");
|
Common::SetCurrentThreadName("GAME_MainThread");
|
||||||
|
@ -22,8 +22,9 @@ struct OrbisKernelMemParam {
|
|||||||
u8* extended_memory_1;
|
u8* extended_memory_1;
|
||||||
u64* extended_gpu_page_table;
|
u64* extended_gpu_page_table;
|
||||||
u8* extended_memory_2;
|
u8* extended_memory_2;
|
||||||
u64* exnteded_cpu_page_table;
|
u64* extended_cpu_page_table;
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(OrbisKernelMemParam) == 0x38);
|
||||||
|
|
||||||
struct OrbisProcParam {
|
struct OrbisProcParam {
|
||||||
u64 size;
|
u64 size;
|
||||||
|
@ -7,17 +7,13 @@
|
|||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "core/libraries/kernel/memory.h"
|
#include "core/libraries/kernel/memory.h"
|
||||||
#include "core/libraries/kernel/orbis_error.h"
|
#include "core/libraries/kernel/orbis_error.h"
|
||||||
|
#include "core/libraries/kernel/process.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
constexpr u64 SCE_DEFAULT_FLEXIBLE_MEMORY_SIZE = 448_MB;
|
|
||||||
|
|
||||||
MemoryManager::MemoryManager() {
|
MemoryManager::MemoryManager() {
|
||||||
// Set up the direct and flexible memory regions.
|
|
||||||
SetupMemoryRegions(SCE_DEFAULT_FLEXIBLE_MEMORY_SIZE);
|
|
||||||
|
|
||||||
// Insert a virtual memory area that covers the entire area we manage.
|
// Insert a virtual memory area that covers the entire area we manage.
|
||||||
const VAddr system_managed_base = impl.SystemManagedVirtualBase();
|
const VAddr system_managed_base = impl.SystemManagedVirtualBase();
|
||||||
const size_t system_managed_size = impl.SystemManagedVirtualSize();
|
const size_t system_managed_size = impl.SystemManagedVirtualSize();
|
||||||
@ -38,10 +34,17 @@ MemoryManager::MemoryManager() {
|
|||||||
|
|
||||||
MemoryManager::~MemoryManager() = default;
|
MemoryManager::~MemoryManager() = default;
|
||||||
|
|
||||||
void MemoryManager::SetupMemoryRegions(u64 flexible_size) {
|
void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1,
|
||||||
const auto total_size =
|
bool use_extended_mem2) {
|
||||||
Config::isNeoMode() ? SCE_KERNEL_MAIN_DMEM_SIZE_PRO : SCE_KERNEL_MAIN_DMEM_SIZE;
|
const bool is_neo = ::Libraries::Kernel::sceKernelIsNeoMode();
|
||||||
total_flexible_size = flexible_size;
|
auto total_size = is_neo ? SCE_KERNEL_TOTAL_MEM_PRO : SCE_KERNEL_TOTAL_MEM;
|
||||||
|
if (!use_extended_mem1 && is_neo) {
|
||||||
|
total_size -= 256_MB;
|
||||||
|
}
|
||||||
|
if (!use_extended_mem2 && !is_neo) {
|
||||||
|
total_size -= 128_MB;
|
||||||
|
}
|
||||||
|
total_flexible_size = flexible_size - SCE_FLEXIBLE_MEMORY_BASE;
|
||||||
total_direct_size = total_size - flexible_size;
|
total_direct_size = total_size - flexible_size;
|
||||||
|
|
||||||
// Insert an area that covers direct memory physical block.
|
// Insert an area that covers direct memory physical block.
|
||||||
@ -101,13 +104,17 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
|
|||||||
auto dmem_area = FindDmemArea(search_start);
|
auto dmem_area = FindDmemArea(search_start);
|
||||||
|
|
||||||
const auto is_suitable = [&] {
|
const auto is_suitable = [&] {
|
||||||
|
if (dmem_area == dmem_map.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const auto aligned_base = Common::AlignUp(dmem_area->second.base, alignment);
|
const auto aligned_base = Common::AlignUp(dmem_area->second.base, alignment);
|
||||||
const auto alignment_size = aligned_base - dmem_area->second.base;
|
const auto alignment_size = aligned_base - dmem_area->second.base;
|
||||||
const auto remaining_size =
|
const auto remaining_size =
|
||||||
dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0;
|
dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0;
|
||||||
return dmem_area->second.is_free && remaining_size >= size;
|
return dmem_area->second.is_free && remaining_size >= size;
|
||||||
};
|
};
|
||||||
while (!is_suitable() && dmem_area->second.GetEnd() <= search_end) {
|
while (dmem_area != dmem_map.end() && !is_suitable() &&
|
||||||
|
dmem_area->second.GetEnd() <= search_end) {
|
||||||
++dmem_area;
|
++dmem_area;
|
||||||
}
|
}
|
||||||
ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size);
|
ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size);
|
||||||
@ -164,10 +171,11 @@ int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size,
|
|||||||
|
|
||||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||||
const auto& vma = FindVMA(mapped_addr)->second;
|
auto& vma = FindVMA(mapped_addr)->second;
|
||||||
// If the VMA is mapped, unmap the region first.
|
// If the VMA is mapped, unmap the region first.
|
||||||
if (vma.IsMapped()) {
|
if (vma.IsMapped()) {
|
||||||
UnmapMemoryImpl(mapped_addr, size);
|
UnmapMemoryImpl(mapped_addr, size);
|
||||||
|
vma = FindVMA(mapped_addr)->second;
|
||||||
}
|
}
|
||||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||||
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size);
|
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size);
|
||||||
@ -201,10 +209,11 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||||||
|
|
||||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||||
const auto& vma = FindVMA(mapped_addr)->second;
|
auto& vma = FindVMA(mapped_addr)->second;
|
||||||
// If the VMA is mapped, unmap the region first.
|
// If the VMA is mapped, unmap the region first.
|
||||||
if (vma.IsMapped()) {
|
if (vma.IsMapped()) {
|
||||||
UnmapMemoryImpl(mapped_addr, size);
|
UnmapMemoryImpl(mapped_addr, size);
|
||||||
|
vma = FindVMA(mapped_addr)->second;
|
||||||
}
|
}
|
||||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||||
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size);
|
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size);
|
||||||
@ -386,14 +395,18 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
|
|||||||
ASSERT_MSG(vma_base.Contains(virtual_addr, size),
|
ASSERT_MSG(vma_base.Contains(virtual_addr, size),
|
||||||
"Existing mapping does not contain requested unmap range");
|
"Existing mapping does not contain requested unmap range");
|
||||||
|
|
||||||
|
const auto type = vma_base.type;
|
||||||
|
if (type == VMAType::Free) {
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
const auto vma_base_addr = vma_base.base;
|
const auto vma_base_addr = vma_base.base;
|
||||||
const auto vma_base_size = vma_base.size;
|
const auto vma_base_size = vma_base.size;
|
||||||
const auto phys_base = vma_base.phys_base;
|
const auto phys_base = vma_base.phys_base;
|
||||||
const bool is_exec = vma_base.is_exec;
|
const bool is_exec = vma_base.is_exec;
|
||||||
const auto start_in_vma = virtual_addr - vma_base_addr;
|
const auto start_in_vma = virtual_addr - vma_base_addr;
|
||||||
const auto type = vma_base.type;
|
|
||||||
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
||||||
if (type == VMAType::Direct) {
|
if (type == VMAType::Direct || type == VMAType::Pooled) {
|
||||||
rasterizer->UnmapMemory(virtual_addr, size);
|
rasterizer->UnmapMemory(virtual_addr, size);
|
||||||
}
|
}
|
||||||
if (type == VMAType::Flexible) {
|
if (type == VMAType::Flexible) {
|
||||||
@ -411,10 +424,12 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
|
|||||||
MergeAdjacent(vma_map, new_it);
|
MergeAdjacent(vma_map, new_it);
|
||||||
bool readonly_file = vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
bool readonly_file = vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
||||||
|
|
||||||
|
if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
|
||||||
// Unmap the memory region.
|
// Unmap the memory region.
|
||||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base, is_exec,
|
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
|
||||||
has_backing, readonly_file);
|
is_exec, has_backing, readonly_file);
|
||||||
TRACK_FREE(virtual_addr, "VMEM");
|
TRACK_FREE(virtual_addr, "VMEM");
|
||||||
|
}
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ public:
|
|||||||
|
|
||||||
bool TryWriteBacking(void* address, const void* data, u32 num_bytes);
|
bool TryWriteBacking(void* address, const void* data, u32 num_bytes);
|
||||||
|
|
||||||
void SetupMemoryRegions(u64 flexible_size);
|
void SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2);
|
||||||
|
|
||||||
PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment);
|
PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment);
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@
|
|||||||
#include "core/file_format/trp.h"
|
#include "core/file_format/trp.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
#include "core/libraries/fiber/fiber.h"
|
|
||||||
#include "core/libraries/jpeg/jpegenc.h"
|
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "core/libraries/ngs2/ngs2.h"
|
#include "core/libraries/ngs2/ngs2.h"
|
||||||
@ -45,10 +43,6 @@ Frontend::WindowSDL* g_window = nullptr;
|
|||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
Emulator::Emulator() {
|
Emulator::Emulator() {
|
||||||
// Read configuration file.
|
|
||||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
||||||
Config::load(config_dir / "config.toml");
|
|
||||||
|
|
||||||
// Initialize NT API functions and set high priority
|
// Initialize NT API functions and set high priority
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Common::NtApi::Initialize();
|
Common::NtApi::Initialize();
|
||||||
@ -63,8 +57,8 @@ Emulator::Emulator() {
|
|||||||
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
||||||
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
||||||
|
|
||||||
LOG_INFO(Config, "General Logtype: {}", Config::getLogType());
|
LOG_INFO(Config, "General LogType: {}", Config::getLogType());
|
||||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole());
|
||||||
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
||||||
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
||||||
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
||||||
@ -105,19 +99,12 @@ Emulator::~Emulator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::Run(const std::filesystem::path& file) {
|
void Emulator::Run(const std::filesystem::path& file) {
|
||||||
|
|
||||||
// Use the eboot from the separated updates folder if it's there
|
|
||||||
std::filesystem::path game_patch_folder = file.parent_path();
|
|
||||||
game_patch_folder += "-UPDATE";
|
|
||||||
std::filesystem::path eboot_path = std::filesystem::exists(game_patch_folder / file.filename())
|
|
||||||
? game_patch_folder / file.filename()
|
|
||||||
: file;
|
|
||||||
|
|
||||||
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
||||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
mnt->Mount(file.parent_path(), "/app0");
|
const auto game_folder = file.parent_path();
|
||||||
|
mnt->Mount(game_folder, "/app0");
|
||||||
// Certain games may use /hostapp as well such as CUSA001100
|
// Certain games may use /hostapp as well such as CUSA001100
|
||||||
mnt->Mount(file.parent_path(), "/hostapp");
|
mnt->Mount(game_folder, "/hostapp");
|
||||||
|
|
||||||
auto& game_info = Common::ElfInfo::Instance();
|
auto& game_info = Common::ElfInfo::Instance();
|
||||||
|
|
||||||
@ -126,13 +113,12 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
std::string title;
|
std::string title;
|
||||||
std::string app_version;
|
std::string app_version;
|
||||||
u32 fw_version;
|
u32 fw_version;
|
||||||
|
Common::PSFAttributes psf_attributes{};
|
||||||
|
|
||||||
std::filesystem::path sce_sys_folder = eboot_path.parent_path() / "sce_sys";
|
const auto param_sfo_path = mnt->GetHostPath("/app0/sce_sys/param.sfo");
|
||||||
if (std::filesystem::is_directory(sce_sys_folder)) {
|
if (std::filesystem::exists(param_sfo_path)) {
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(sce_sys_folder)) {
|
|
||||||
if (entry.path().filename() == "param.sfo") {
|
|
||||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||||
const bool success = param_sfo->Open(sce_sys_folder / "param.sfo");
|
const bool success = param_sfo->Open(param_sfo_path);
|
||||||
ASSERT_MSG(success, "Failed to open param.sfo");
|
ASSERT_MSG(success, "Failed to open param.sfo");
|
||||||
const auto content_id = param_sfo->GetString("CONTENT_ID");
|
const auto content_id = param_sfo->GetString("CONTENT_ID");
|
||||||
ASSERT_MSG(content_id.has_value(), "Failed to get CONTENT_ID");
|
ASSERT_MSG(content_id.has_value(), "Failed to get CONTENT_ID");
|
||||||
@ -142,7 +128,7 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles";
|
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles";
|
||||||
if (!std::filesystem::exists(trophyDir)) {
|
if (!std::filesystem::exists(trophyDir)) {
|
||||||
TRP trp;
|
TRP trp;
|
||||||
if (!trp.Extract(eboot_path.parent_path(), id)) {
|
if (!trp.Extract(game_folder, id)) {
|
||||||
LOG_ERROR(Loader, "Couldn't extract trophies");
|
LOG_ERROR(Loader, "Couldn't extract trophies");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,17 +148,20 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
fw_version = param_sfo->GetInteger("SYSTEM_VER").value_or(0x4700000);
|
fw_version = param_sfo->GetInteger("SYSTEM_VER").value_or(0x4700000);
|
||||||
app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
||||||
LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version);
|
LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version);
|
||||||
} else if (entry.path().filename() == "pic1.png") {
|
if (const auto raw_attributes = param_sfo->GetInteger("ATTRIBUTE")) {
|
||||||
|
psf_attributes.raw = *raw_attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
|
||||||
|
if (std::filesystem::exists(pic1_path)) {
|
||||||
auto* splash = Common::Singleton<Splash>::Instance();
|
auto* splash = Common::Singleton<Splash>::Instance();
|
||||||
if (splash->IsLoaded()) {
|
if (!splash->IsLoaded()) {
|
||||||
continue;
|
if (!splash->Open(pic1_path)) {
|
||||||
}
|
|
||||||
if (!splash->Open(entry.path())) {
|
|
||||||
LOG_ERROR(Loader, "Game splash: unable to open file");
|
LOG_ERROR(Loader, "Game splash: unable to open file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
game_info.initialized = true;
|
game_info.initialized = true;
|
||||||
game_info.game_serial = id;
|
game_info.game_serial = id;
|
||||||
@ -180,6 +169,7 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
game_info.app_ver = app_version;
|
game_info.app_ver = app_version;
|
||||||
game_info.firmware_ver = fw_version & 0xFFF00000;
|
game_info.firmware_ver = fw_version & 0xFFF00000;
|
||||||
game_info.raw_firmware_ver = fw_version;
|
game_info.raw_firmware_ver = fw_version;
|
||||||
|
game_info.psf_attributes = psf_attributes;
|
||||||
|
|
||||||
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
|
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
|
||||||
std::string window_title = "";
|
std::string window_title = "";
|
||||||
@ -223,42 +213,19 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
Libraries::InitHLELibs(&linker->GetHLESymbols());
|
Libraries::InitHLELibs(&linker->GetHLESymbols());
|
||||||
|
|
||||||
// Load the module with the linker
|
// Load the module with the linker
|
||||||
|
const auto eboot_path = mnt->GetHostPath("/app0/" + file.filename().string());
|
||||||
linker->LoadModule(eboot_path);
|
linker->LoadModule(eboot_path);
|
||||||
|
|
||||||
// check if we have system modules to load
|
// check if we have system modules to load
|
||||||
LoadSystemModules(eboot_path, game_info.game_serial);
|
LoadSystemModules(game_info.game_serial);
|
||||||
|
|
||||||
// Load all prx from game's sce_module folder
|
// Load all prx from game's sce_module folder
|
||||||
std::vector<std::filesystem::path> modules_to_load;
|
mnt->IterateDirectory("/app0/sce_module", [this](const auto& path, const auto is_file) {
|
||||||
std::filesystem::path game_module_folder = file.parent_path() / "sce_module";
|
if (is_file) {
|
||||||
if (std::filesystem::is_directory(game_module_folder)) {
|
LOG_INFO(Loader, "Loading {}", fmt::UTF(path.u8string()));
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(game_module_folder)) {
|
linker->LoadModule(path);
|
||||||
if (entry.is_regular_file()) {
|
|
||||||
modules_to_load.push_back(entry.path());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load all prx from separate update's sce_module folder
|
|
||||||
std::filesystem::path update_module_folder = game_patch_folder / "sce_module";
|
|
||||||
if (std::filesystem::is_directory(update_module_folder)) {
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(update_module_folder)) {
|
|
||||||
auto it = std::find_if(modules_to_load.begin(), modules_to_load.end(),
|
|
||||||
[&entry](const std::filesystem::path& p) {
|
|
||||||
return p.filename() == entry.path().filename();
|
|
||||||
});
|
});
|
||||||
if (it != modules_to_load.end()) {
|
|
||||||
*it = entry.path();
|
|
||||||
} else {
|
|
||||||
modules_to_load.push_back(entry.path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& module_path : modules_to_load) {
|
|
||||||
LOG_INFO(Loader, "Loading {}", fmt::UTF(module_path.u8string()));
|
|
||||||
linker->LoadModule(module_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_DISCORD_RPC
|
#ifdef ENABLE_DISCORD_RPC
|
||||||
// Discord RPC
|
// Discord RPC
|
||||||
@ -285,17 +252,15 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string game_serial) {
|
void Emulator::LoadSystemModules(const std::string& game_serial) {
|
||||||
constexpr std::array<SysModules, 13> ModulesToLoad{
|
constexpr std::array<SysModules, 11> ModulesToLoad{
|
||||||
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
||||||
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
|
|
||||||
{"libSceUlt.sprx", nullptr},
|
{"libSceUlt.sprx", nullptr},
|
||||||
{"libSceJson.sprx", nullptr},
|
{"libSceJson.sprx", nullptr},
|
||||||
{"libSceJson2.sprx", nullptr},
|
{"libSceJson2.sprx", nullptr},
|
||||||
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
|
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
|
||||||
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
|
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
|
||||||
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
|
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
|
||||||
{"libSceJpegEnc.sprx", &Libraries::JpegEnc::RegisterlibSceJpegEnc},
|
|
||||||
{"libSceCesCs.sprx", nullptr},
|
{"libSceCesCs.sprx", nullptr},
|
||||||
{"libSceFont.sprx", nullptr},
|
{"libSceFont.sprx", nullptr},
|
||||||
{"libSceFontFt.sprx", nullptr},
|
{"libSceFontFt.sprx", nullptr},
|
||||||
@ -311,9 +276,10 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string
|
|||||||
found_modules, [&](const auto& path) { return path.filename() == module_name; });
|
found_modules, [&](const auto& path) { return path.filename() == module_name; });
|
||||||
if (it != found_modules.end()) {
|
if (it != found_modules.end()) {
|
||||||
LOG_INFO(Loader, "Loading {}", it->string());
|
LOG_INFO(Loader, "Loading {}", it->string());
|
||||||
linker->LoadModule(*it);
|
if (linker->LoadModule(*it) != -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (init_func) {
|
if (init_func) {
|
||||||
LOG_INFO(Loader, "Can't Load {} switching to HLE", module_name);
|
LOG_INFO(Loader, "Can't Load {} switching to HLE", module_name);
|
||||||
init_func(&linker->GetHLESymbols());
|
init_func(&linker->GetHLESymbols());
|
||||||
@ -321,7 +287,7 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string
|
|||||||
LOG_INFO(Loader, "No HLE available for {} module", module_name);
|
LOG_INFO(Loader, "No HLE available for {} module", module_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (std::filesystem::exists(sys_module_path / game_serial)) {
|
if (!game_serial.empty() && std::filesystem::exists(sys_module_path / game_serial)) {
|
||||||
for (const auto& entry :
|
for (const auto& entry :
|
||||||
std::filesystem::directory_iterator(sys_module_path / game_serial)) {
|
std::filesystem::directory_iterator(sys_module_path / game_serial)) {
|
||||||
LOG_INFO(Loader, "Loading {} from game serial file {}", entry.path().string(),
|
LOG_INFO(Loader, "Loading {} from game serial file {}", entry.path().string(),
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
void UpdatePlayTime(const std::string& serial);
|
void UpdatePlayTime(const std::string& serial);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadSystemModules(const std::filesystem::path& file, std::string game_serial);
|
void LoadSystemModules(const std::string& game_serial);
|
||||||
|
|
||||||
Core::MemoryManager* memory;
|
Core::MemoryManager* memory;
|
||||||
Input::GameController* controller;
|
Input::GameController* controller;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#include "common/config.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/kernel/time.h"
|
#include "core/libraries/kernel/time.h"
|
||||||
#include "core/libraries/pad/pad.h"
|
#include "core/libraries/pad/pad.h"
|
||||||
#include "input/controller.h"
|
#include "input/controller.h"
|
||||||
@ -116,6 +118,98 @@ void GameController::Axis(int id, Input::Axis axis, int value) {
|
|||||||
AddState(state);
|
AddState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameController::Gyro(int id, const float gyro[3]) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
auto state = GetLastState();
|
||||||
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
|
|
||||||
|
// Update the angular velocity (gyro data)
|
||||||
|
state.angularVelocity.x = gyro[0]; // X-axis
|
||||||
|
state.angularVelocity.y = gyro[1]; // Y-axis
|
||||||
|
state.angularVelocity.z = gyro[2]; // Z-axis
|
||||||
|
|
||||||
|
AddState(state);
|
||||||
|
}
|
||||||
|
void GameController::Acceleration(int id, const float acceleration[3]) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
auto state = GetLastState();
|
||||||
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
|
|
||||||
|
// Update the acceleration values
|
||||||
|
state.acceleration.x = acceleration[0]; // X-axis
|
||||||
|
state.acceleration.y = acceleration[1]; // Y-axis
|
||||||
|
state.acceleration.z = acceleration[2]; // Z-axis
|
||||||
|
|
||||||
|
AddState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stolen from
|
||||||
|
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
|
||||||
|
float eInt[3] = {0.0f, 0.0f, 0.0f}; // Integral error terms
|
||||||
|
const float Kp = 50.0f; // Proportional gain
|
||||||
|
const float Ki = 1.0f; // Integral gain
|
||||||
|
Libraries::Pad::OrbisFQuaternion o = {1, 0, 0, 0};
|
||||||
|
void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||||
|
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||||
|
float deltaTime,
|
||||||
|
Libraries::Pad::OrbisFQuaternion& orientation) {
|
||||||
|
float ax = acceleration.x, ay = acceleration.y, az = acceleration.z;
|
||||||
|
float gx = angularVelocity.x, gy = angularVelocity.y, gz = angularVelocity.z;
|
||||||
|
|
||||||
|
float q1 = o.w, q2 = o.x, q3 = o.y, q4 = o.z;
|
||||||
|
|
||||||
|
// Normalize accelerometer measurement
|
||||||
|
float norm = std::sqrt(ax * ax + ay * ay + az * az);
|
||||||
|
if (norm == 0.0f)
|
||||||
|
return; // Handle NaN
|
||||||
|
norm = 1.0f / norm;
|
||||||
|
ax *= norm;
|
||||||
|
ay *= norm;
|
||||||
|
az *= norm;
|
||||||
|
|
||||||
|
// Estimated direction of gravity
|
||||||
|
float vx = 2.0f * (q2 * q4 - q1 * q3);
|
||||||
|
float vy = 2.0f * (q1 * q2 + q3 * q4);
|
||||||
|
float vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
|
||||||
|
|
||||||
|
// Error is cross product between estimated direction and measured direction of gravity
|
||||||
|
float ex = (ay * vz - az * vy);
|
||||||
|
float ey = (az * vx - ax * vz);
|
||||||
|
float ez = (ax * vy - ay * vx);
|
||||||
|
if (Ki > 0.0f) {
|
||||||
|
eInt[0] += ex * deltaTime; // Accumulate integral error
|
||||||
|
eInt[1] += ey * deltaTime;
|
||||||
|
eInt[2] += ez * deltaTime;
|
||||||
|
} else {
|
||||||
|
eInt[0] = eInt[1] = eInt[2] = 0.0f; // Prevent integral wind-up
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply feedback terms
|
||||||
|
gx += Kp * ex + Ki * eInt[0];
|
||||||
|
gy += Kp * ey + Ki * eInt[1];
|
||||||
|
gz += Kp * ez + Ki * eInt[2];
|
||||||
|
|
||||||
|
//// Integrate rate of change of quaternion
|
||||||
|
q1 += (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltaTime);
|
||||||
|
q2 += (q1 * gx + q3 * gz - q4 * gy) * (0.5f * deltaTime);
|
||||||
|
q3 += (q1 * gy - q2 * gz + q4 * gx) * (0.5f * deltaTime);
|
||||||
|
q4 += (q1 * gz + q2 * gy - q3 * gx) * (0.5f * deltaTime);
|
||||||
|
|
||||||
|
// Normalize quaternion
|
||||||
|
norm = std::sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
|
||||||
|
norm = 1.0f / norm;
|
||||||
|
orientation.w = q1 * norm;
|
||||||
|
orientation.x = q2 * norm;
|
||||||
|
orientation.y = q3 * norm;
|
||||||
|
orientation.z = q4 * norm;
|
||||||
|
o.w = q1 * norm;
|
||||||
|
o.x = q2 * norm;
|
||||||
|
o.y = q3 * norm;
|
||||||
|
o.z = q4 * norm;
|
||||||
|
LOG_DEBUG(Lib_Pad, "Calculated orientation: {:.2f} {:.2f} {:.2f} {:.2f}", orientation.x,
|
||||||
|
orientation.y, orientation.z, orientation.w);
|
||||||
|
}
|
||||||
|
|
||||||
void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) {
|
void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) {
|
||||||
if (m_sdl_gamepad != nullptr) {
|
if (m_sdl_gamepad != nullptr) {
|
||||||
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
|
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
|
||||||
@ -149,6 +243,21 @@ void GameController::TryOpenSDLController() {
|
|||||||
int gamepad_count;
|
int gamepad_count;
|
||||||
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
|
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
|
||||||
m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr;
|
m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr;
|
||||||
|
if (Config::getIsMotionControlsEnabled()) {
|
||||||
|
if (SDL_SetGamepadSensorEnabled(m_sdl_gamepad, SDL_SENSOR_GYRO, true)) {
|
||||||
|
gyro_poll_rate = SDL_GetGamepadSensorDataRate(m_sdl_gamepad, SDL_SENSOR_GYRO);
|
||||||
|
LOG_INFO(Input, "Gyro initialized, poll rate: {}", gyro_poll_rate);
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad");
|
||||||
|
}
|
||||||
|
if (SDL_SetGamepadSensorEnabled(m_sdl_gamepad, SDL_SENSOR_ACCEL, true)) {
|
||||||
|
accel_poll_rate = SDL_GetGamepadSensorDataRate(m_sdl_gamepad, SDL_SENSOR_ACCEL);
|
||||||
|
LOG_INFO(Input, "Accel initialized, poll rate: {}", accel_poll_rate);
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDL_free(gamepads);
|
SDL_free(gamepads);
|
||||||
|
|
||||||
SetLightBarRGB(0, 0, 255);
|
SetLightBarRGB(0, 0, 255);
|
||||||
@ -156,6 +265,7 @@ void GameController::TryOpenSDLController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 GameController::Poll() {
|
u32 GameController::Poll() {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
if (m_connected) {
|
if (m_connected) {
|
||||||
auto time = Libraries::Kernel::sceKernelGetProcessTime();
|
auto time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
if (m_states_num == 0) {
|
if (m_states_num == 0) {
|
||||||
|
@ -33,6 +33,9 @@ struct State {
|
|||||||
u64 time = 0;
|
u64 time = 0;
|
||||||
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0};
|
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0};
|
||||||
TouchpadEntry touchpad[2] = {{false, 0, 0}, {false, 0, 0}};
|
TouchpadEntry touchpad[2] = {{false, 0, 0}, {false, 0, 0}};
|
||||||
|
Libraries::Pad::OrbisFVector3 acceleration = {0.0f, 0.0f, 0.0f};
|
||||||
|
Libraries::Pad::OrbisFVector3 angularVelocity = {0.0f, 0.0f, 0.0f};
|
||||||
|
Libraries::Pad::OrbisFQuaternion orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int GetAxis(int min, int max, int value) {
|
inline int GetAxis(int min, int max, int value) {
|
||||||
@ -53,12 +56,21 @@ public:
|
|||||||
void CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button, bool isPressed);
|
void CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button, bool isPressed);
|
||||||
void AddState(const State& state);
|
void AddState(const State& state);
|
||||||
void Axis(int id, Input::Axis axis, int value);
|
void Axis(int id, Input::Axis axis, int value);
|
||||||
|
void Gyro(int id, const float gyro[3]);
|
||||||
|
void Acceleration(int id, const float acceleration[3]);
|
||||||
void SetLightBarRGB(u8 r, u8 g, u8 b);
|
void SetLightBarRGB(u8 r, u8 g, u8 b);
|
||||||
bool SetVibration(u8 smallMotor, u8 largeMotor);
|
bool SetVibration(u8 smallMotor, u8 largeMotor);
|
||||||
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
|
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
|
||||||
void TryOpenSDLController();
|
void TryOpenSDLController();
|
||||||
u32 Poll();
|
u32 Poll();
|
||||||
|
|
||||||
|
float gyro_poll_rate;
|
||||||
|
float accel_poll_rate;
|
||||||
|
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||||
|
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||||
|
float deltaTime,
|
||||||
|
Libraries::Pad::OrbisFQuaternion& orientation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct StateInternal {
|
struct StateInternal {
|
||||||
bool obtained = false;
|
bool obtained = false;
|
||||||
|
60
src/main.cpp
60
src/main.cpp
@ -4,11 +4,14 @@
|
|||||||
#include "functional"
|
#include "functional"
|
||||||
#include "iostream"
|
#include "iostream"
|
||||||
#include "string"
|
#include "string"
|
||||||
|
#include "system_error"
|
||||||
#include "unordered_map"
|
#include "unordered_map"
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/memory_patcher.h"
|
#include "common/memory_patcher.h"
|
||||||
|
#include "common/path_util.h"
|
||||||
|
#include "core/file_sys/fs.h"
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -20,6 +23,10 @@ int main(int argc, char* argv[]) {
|
|||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Load configurations
|
||||||
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
Config::load(user_dir / "config.toml");
|
||||||
|
|
||||||
bool has_game_argument = false;
|
bool has_game_argument = false;
|
||||||
std::string game_path;
|
std::string game_path;
|
||||||
|
|
||||||
@ -33,6 +40,7 @@ int main(int argc, char* argv[]) {
|
|||||||
" -p, --patch <patch_file> Apply specified patch file\n"
|
" -p, --patch <patch_file> Apply specified patch file\n"
|
||||||
" -f, --fullscreen <true|false> Specify window initial fullscreen "
|
" -f, --fullscreen <true|false> Specify window initial fullscreen "
|
||||||
"state. Does not overwrite the config file.\n"
|
"state. Does not overwrite the config file.\n"
|
||||||
|
" --add-game-folder <folder> Adds a new game folder to the config.\n"
|
||||||
" -h, --help Display this help message\n";
|
" -h, --help Display this help message\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
}},
|
}},
|
||||||
@ -78,9 +86,28 @@ int main(int argc, char* argv[]) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
// Set fullscreen mode without saving it to config file
|
// Set fullscreen mode without saving it to config file
|
||||||
Config::setFullscreenMode(is_fullscreen);
|
Config::setIsFullscreen(is_fullscreen);
|
||||||
}},
|
}},
|
||||||
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
|
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
|
||||||
|
{"--add-game-folder",
|
||||||
|
[&](int& i) {
|
||||||
|
if (++i >= argc) {
|
||||||
|
std::cerr << "Error: Missing argument for --add-game-folder\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::string config_dir(argv[i]);
|
||||||
|
std::filesystem::path config_path = std::filesystem::path(config_dir);
|
||||||
|
std::error_code discard;
|
||||||
|
if (!std::filesystem::exists(config_path, discard)) {
|
||||||
|
std::cerr << "Error: File does not exist: " << config_path << "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::addGameInstallDir(config_path);
|
||||||
|
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
|
||||||
|
std::cout << "Game folder successfully saved.\n";
|
||||||
|
exit(0);
|
||||||
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
@ -105,20 +132,41 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no game directory is set and no command line argument, prompt for it
|
||||||
|
if (Config::getGameInstallDirs().empty()) {
|
||||||
|
std::cout << "Warning: No game folder set, please set it by calling shadps4"
|
||||||
|
" with the --add-game-folder <folder_name> argument";
|
||||||
|
}
|
||||||
|
|
||||||
if (!has_game_argument) {
|
if (!has_game_argument) {
|
||||||
std::cerr << "Error: Please provide a game path or ID.\n";
|
std::cerr << "Error: Please provide a game path or ID.\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the game path or ID exists
|
// Check if the game path or ID exists
|
||||||
if (!std::filesystem::exists(game_path)) {
|
std::filesystem::path eboot_path(game_path);
|
||||||
std::cerr << "Error: Game file not found\n";
|
|
||||||
return -1;
|
// Check if the provided path is a valid file
|
||||||
|
if (!std::filesystem::exists(eboot_path)) {
|
||||||
|
// If not a file, treat it as a game ID and search in install directories
|
||||||
|
bool game_found = false;
|
||||||
|
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
||||||
|
const auto candidate_path = install_dir / game_path / "eboot.bin";
|
||||||
|
if (std::filesystem::exists(candidate_path)) {
|
||||||
|
eboot_path = candidate_path;
|
||||||
|
game_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!game_found) {
|
||||||
|
std::cerr << "Error: Game ID or file path not found: " << game_path << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the emulator with the specified game
|
// Run the emulator with the resolved eboot path
|
||||||
Core::Emulator emulator;
|
Core::Emulator emulator;
|
||||||
emulator.Run(game_path);
|
emulator.Run(eboot_path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QProgressBar>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -24,11 +25,9 @@
|
|||||||
#include <common/path_util.h>
|
#include <common/path_util.h>
|
||||||
#include <common/scm_rev.h>
|
#include <common/scm_rev.h>
|
||||||
#include <common/version.h>
|
#include <common/version.h>
|
||||||
#include <qprogressbar.h>
|
|
||||||
#include "check_update.h"
|
#include "check_update.h"
|
||||||
|
|
||||||
using namespace Common::FS;
|
using namespace Common::FS;
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
CheckUpdate::CheckUpdate(const bool showMessage, QWidget* parent)
|
CheckUpdate::CheckUpdate(const bool showMessage, QWidget* parent)
|
||||||
: QDialog(parent), networkManager(new QNetworkAccessManager(this)) {
|
: QDialog(parent), networkManager(new QNetworkAccessManager(this)) {
|
||||||
@ -254,7 +253,11 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
|
|||||||
connect(noButton, &QPushButton::clicked, this, [this]() { close(); });
|
connect(noButton, &QPushButton::clicked, this, [this]() { close(); });
|
||||||
|
|
||||||
autoUpdateCheckBox->setChecked(Config::autoUpdate());
|
autoUpdateCheckBox->setChecked(Config::autoUpdate());
|
||||||
|
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
|
||||||
connect(autoUpdateCheckBox, &QCheckBox::stateChanged, this, [](int state) {
|
connect(autoUpdateCheckBox, &QCheckBox::stateChanged, this, [](int state) {
|
||||||
|
#else
|
||||||
|
connect(autoUpdateCheckBox, &QCheckBox::checkStateChanged, this, [](Qt::CheckState state) {
|
||||||
|
#endif
|
||||||
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
Config::setAutoUpdate(state == Qt::Checked);
|
Config::setAutoUpdate(state == Qt::Checked);
|
||||||
Config::save(user_dir / "config.toml");
|
Config::save(user_dir / "config.toml");
|
||||||
|
@ -133,16 +133,16 @@ void GameListFrame::PopulateGameList() {
|
|||||||
|
|
||||||
QString formattedPlayTime;
|
QString formattedPlayTime;
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
formattedPlayTime += QString("%1h ").arg(hours);
|
formattedPlayTime += QString("%1").arg(hours) + tr("h");
|
||||||
}
|
}
|
||||||
if (minutes > 0) {
|
if (minutes > 0) {
|
||||||
formattedPlayTime += QString("%1m ").arg(minutes);
|
formattedPlayTime += QString("%1").arg(minutes) + tr("m");
|
||||||
}
|
}
|
||||||
|
|
||||||
formattedPlayTime = formattedPlayTime.trimmed();
|
formattedPlayTime = formattedPlayTime.trimmed();
|
||||||
m_game_info->m_games[i].play_time = playTime.toStdString();
|
m_game_info->m_games[i].play_time = playTime.toStdString();
|
||||||
if (formattedPlayTime.isEmpty()) {
|
if (formattedPlayTime.isEmpty()) {
|
||||||
SetTableItem(i, 8, QString("%1s").arg(seconds));
|
SetTableItem(i, 8, QString("%1").arg(seconds) + tr("s"));
|
||||||
} else {
|
} else {
|
||||||
SetTableItem(i, 8, formattedPlayTime);
|
SetTableItem(i, 8, formattedPlayTime);
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,11 @@ struct GameInfo {
|
|||||||
CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown};
|
CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown};
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameListUtils {
|
class GameListUtils : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static QString FormatSize(qint64 size) {
|
static QString FormatSize(qint64 size) {
|
||||||
static const QStringList suffixes = {"B", "KB", "MB", "GB", "TB"};
|
static const QStringList suffixes = {tr("B"), tr("KB"), tr("MB"), tr("GB"), tr("TB")};
|
||||||
int suffixIndex = 0;
|
int suffixIndex = 0;
|
||||||
|
|
||||||
double gameSize = static_cast<double>(size);
|
double gameSize = static_cast<double>(size);
|
||||||
|
@ -283,15 +283,15 @@ public:
|
|||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (createShortcutWin(linkPath, ebootPath, icoPath, exePath)) {
|
if (createShortcutWin(linkPath, ebootPath, icoPath, exePath)) {
|
||||||
#else
|
#else
|
||||||
if (createShortcutLinux(linkPath, ebootPath, iconPath)) {
|
if (createShortcutLinux(linkPath, m_games[itemID].name, ebootPath, iconPath)) {
|
||||||
#endif
|
#endif
|
||||||
QMessageBox::information(
|
QMessageBox::information(
|
||||||
nullptr, tr("Shortcut creation"),
|
nullptr, tr("Shortcut creation"),
|
||||||
QString(tr("Shortcut created successfully!\n %1")).arg(linkPath));
|
QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath));
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
nullptr, tr("Error"),
|
nullptr, tr("Error"),
|
||||||
QString(tr("Error creating shortcut!\n %1")).arg(linkPath));
|
QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(nullptr, tr("Error"), tr("Failed to convert icon."));
|
QMessageBox::critical(nullptr, tr("Error"), tr("Failed to convert icon."));
|
||||||
@ -301,15 +301,15 @@ public:
|
|||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (createShortcutWin(linkPath, ebootPath, iconPath, exePath)) {
|
if (createShortcutWin(linkPath, ebootPath, iconPath, exePath)) {
|
||||||
#else
|
#else
|
||||||
if (createShortcutLinux(linkPath, ebootPath, iconPath)) {
|
if (createShortcutLinux(linkPath, m_games[itemID].name, ebootPath, iconPath)) {
|
||||||
#endif
|
#endif
|
||||||
QMessageBox::information(
|
QMessageBox::information(
|
||||||
nullptr, tr("Shortcut creation"),
|
nullptr, tr("Shortcut creation"),
|
||||||
QString(tr("Shortcut created successfully!\n %1")).arg(linkPath));
|
QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath));
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
nullptr, tr("Error"),
|
nullptr, tr("Error"),
|
||||||
QString(tr("Error creating shortcut!\n %1")).arg(linkPath));
|
QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,9 +347,8 @@ public:
|
|||||||
|
|
||||||
if (selected == deleteUpdate) {
|
if (selected == deleteUpdate) {
|
||||||
if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) {
|
if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(nullptr, tr("Error"),
|
||||||
nullptr, tr("Error"),
|
QString(tr("This game has no update to delete!")));
|
||||||
QString(tr("This game has no separate update to delete!")));
|
|
||||||
error = true;
|
error = true;
|
||||||
} else {
|
} else {
|
||||||
folder_path = game_update_path;
|
folder_path = game_update_path;
|
||||||
@ -511,8 +510,8 @@ private:
|
|||||||
return SUCCEEDED(hres);
|
return SUCCEEDED(hres);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
bool createShortcutLinux(const QString& linkPath, const QString& targetPath,
|
bool createShortcutLinux(const QString& linkPath, const std::string& name,
|
||||||
const QString& iconPath) {
|
const QString& targetPath, const QString& iconPath) {
|
||||||
QFile shortcutFile(linkPath);
|
QFile shortcutFile(linkPath);
|
||||||
if (!shortcutFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
if (!shortcutFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
QMessageBox::critical(nullptr, "Error",
|
QMessageBox::critical(nullptr, "Error",
|
||||||
@ -523,7 +522,7 @@ private:
|
|||||||
QTextStream out(&shortcutFile);
|
QTextStream out(&shortcutFile);
|
||||||
out << "[Desktop Entry]\n";
|
out << "[Desktop Entry]\n";
|
||||||
out << "Version=1.0\n";
|
out << "Version=1.0\n";
|
||||||
out << "Name=" << QFileInfo(linkPath).baseName() << "\n";
|
out << "Name=" << QString::fromStdString(name) << "\n";
|
||||||
out << "Exec=" << QCoreApplication::applicationFilePath() << " \"" << targetPath << "\"\n";
|
out << "Exec=" << QCoreApplication::applicationFilePath() << " \"" << targetPath << "\"\n";
|
||||||
out << "Icon=" << iconPath << "\n";
|
out << "Icon=" << iconPath << "\n";
|
||||||
out << "Terminal=false\n";
|
out << "Terminal=false\n";
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "iostream"
|
#include "iostream"
|
||||||
|
#include "system_error"
|
||||||
#include "unordered_map"
|
#include "unordered_map"
|
||||||
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
@ -31,7 +32,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
bool has_command_line_argument = argc > 1;
|
bool has_command_line_argument = argc > 1;
|
||||||
bool show_gui = false, has_game_argument = false;
|
bool show_gui = false, has_game_argument = false;
|
||||||
std::string gamePath;
|
std::string game_path;
|
||||||
|
|
||||||
// Map of argument strings to lambda functions
|
// Map of argument strings to lambda functions
|
||||||
std::unordered_map<std::string, std::function<void(int&)>> arg_map = {
|
std::unordered_map<std::string, std::function<void(int&)>> arg_map = {
|
||||||
@ -46,6 +47,7 @@ int main(int argc, char* argv[]) {
|
|||||||
" -s, --show-gui Show the GUI\n"
|
" -s, --show-gui Show the GUI\n"
|
||||||
" -f, --fullscreen <true|false> Specify window initial fullscreen "
|
" -f, --fullscreen <true|false> Specify window initial fullscreen "
|
||||||
"state. Does not overwrite the config file.\n"
|
"state. Does not overwrite the config file.\n"
|
||||||
|
" --add-game-folder <folder> Adds a new game folder to the config.\n"
|
||||||
" -h, --help Display this help message\n";
|
" -h, --help Display this help message\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
}},
|
}},
|
||||||
@ -57,7 +59,7 @@ int main(int argc, char* argv[]) {
|
|||||||
{"-g",
|
{"-g",
|
||||||
[&](int& i) {
|
[&](int& i) {
|
||||||
if (i + 1 < argc) {
|
if (i + 1 < argc) {
|
||||||
gamePath = argv[++i];
|
game_path = argv[++i];
|
||||||
has_game_argument = true;
|
has_game_argument = true;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Error: Missing argument for -g/--game\n";
|
std::cerr << "Error: Missing argument for -g/--game\n";
|
||||||
@ -95,9 +97,28 @@ int main(int argc, char* argv[]) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
// Set fullscreen mode without saving it to config file
|
// Set fullscreen mode without saving it to config file
|
||||||
Config::setFullscreenMode(is_fullscreen);
|
Config::setIsFullscreen(is_fullscreen);
|
||||||
}},
|
}},
|
||||||
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
|
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
|
||||||
|
{"--add-game-folder",
|
||||||
|
[&](int& i) {
|
||||||
|
if (++i >= argc) {
|
||||||
|
std::cerr << "Error: Missing argument for --add-game-folder\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::string config_dir(argv[i]);
|
||||||
|
std::filesystem::path config_path = std::filesystem::path(config_dir);
|
||||||
|
std::error_code discard;
|
||||||
|
if (!std::filesystem::is_directory(config_path, discard)) {
|
||||||
|
std::cerr << "Error: Directory does not exist: " << config_path << "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::addGameInstallDir(config_path);
|
||||||
|
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
|
||||||
|
std::cout << "Game folder successfully saved.\n";
|
||||||
|
exit(0);
|
||||||
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse command-line arguments using the map
|
// Parse command-line arguments using the map
|
||||||
@ -106,6 +127,10 @@ int main(int argc, char* argv[]) {
|
|||||||
auto it = arg_map.find(cur_arg);
|
auto it = arg_map.find(cur_arg);
|
||||||
if (it != arg_map.end()) {
|
if (it != arg_map.end()) {
|
||||||
it->second(i); // Call the associated lambda function
|
it->second(i); // Call the associated lambda function
|
||||||
|
} else if (i == argc - 1 && !has_game_argument) {
|
||||||
|
// Assume the last argument is the game file if not specified via -g/--game
|
||||||
|
game_path = argv[i];
|
||||||
|
has_game_argument = true;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n";
|
std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n";
|
||||||
return 1;
|
return 1;
|
||||||
@ -134,14 +159,14 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Process game path or ID if provided
|
// Process game path or ID if provided
|
||||||
if (has_game_argument) {
|
if (has_game_argument) {
|
||||||
std::filesystem::path game_file_path(gamePath);
|
std::filesystem::path game_file_path(game_path);
|
||||||
|
|
||||||
// Check if the provided path is a valid file
|
// Check if the provided path is a valid file
|
||||||
if (!std::filesystem::exists(game_file_path)) {
|
if (!std::filesystem::exists(game_file_path)) {
|
||||||
// If not a file, treat it as a game ID and search in install directories
|
// If not a file, treat it as a game ID and search in install directories
|
||||||
bool game_found = false;
|
bool game_found = false;
|
||||||
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
||||||
auto potential_game_path = install_dir / gamePath / "eboot.bin";
|
auto potential_game_path = install_dir / game_path / "eboot.bin";
|
||||||
if (std::filesystem::exists(potential_game_path)) {
|
if (std::filesystem::exists(potential_game_path)) {
|
||||||
game_file_path = potential_game_path;
|
game_file_path = potential_game_path;
|
||||||
game_found = true;
|
game_found = true;
|
||||||
@ -149,7 +174,7 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!game_found) {
|
if (!game_found) {
|
||||||
std::cerr << "Error: Game ID or file path not found: " << gamePath << std::endl;
|
std::cerr << "Error: Game ID or file path not found: " << game_path << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ bool MainWindow::Init() {
|
|||||||
this->setStatusBar(statusBar.data());
|
this->setStatusBar(statusBar.data());
|
||||||
// Update status bar
|
// Update status bar
|
||||||
int numGames = m_game_info->m_games.size();
|
int numGames = m_game_info->m_games.size();
|
||||||
QString statusMessage =
|
QString statusMessage = tr("Games: ") + QString::number(numGames) + " (" +
|
||||||
"Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)";
|
QString::number(duration.count()) + "ms)";
|
||||||
statusBar->showMessage(statusMessage);
|
statusBar->showMessage(statusMessage);
|
||||||
|
|
||||||
#ifdef ENABLE_DISCORD_RPC
|
#ifdef ENABLE_DISCORD_RPC
|
||||||
@ -116,6 +116,7 @@ void MainWindow::CreateActions() {
|
|||||||
m_theme_act_group->addAction(ui->setThemeBlue);
|
m_theme_act_group->addAction(ui->setThemeBlue);
|
||||||
m_theme_act_group->addAction(ui->setThemeViolet);
|
m_theme_act_group->addAction(ui->setThemeViolet);
|
||||||
m_theme_act_group->addAction(ui->setThemeGruvbox);
|
m_theme_act_group->addAction(ui->setThemeGruvbox);
|
||||||
|
m_theme_act_group->addAction(ui->setThemeTokyoNight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::AddUiWidgets() {
|
void MainWindow::AddUiWidgets() {
|
||||||
@ -569,6 +570,14 @@ void MainWindow::CreateConnects() {
|
|||||||
isIconBlack = false;
|
isIconBlack = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
connect(ui->setThemeTokyoNight, &QAction::triggered, &m_window_themes, [this]() {
|
||||||
|
m_window_themes.SetWindowTheme(Theme::TokyoNight, ui->mw_searchbar);
|
||||||
|
Config::setMainWindowTheme(static_cast<int>(Theme::TokyoNight));
|
||||||
|
if (isIconBlack) {
|
||||||
|
SetUiIcons(false);
|
||||||
|
isIconBlack = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::StartGame() {
|
void MainWindow::StartGame() {
|
||||||
@ -944,6 +953,11 @@ void MainWindow::SetLastUsedTheme() {
|
|||||||
isIconBlack = false;
|
isIconBlack = false;
|
||||||
SetUiIcons(false);
|
SetUiIcons(false);
|
||||||
break;
|
break;
|
||||||
|
case Theme::TokyoNight:
|
||||||
|
ui->setThemeTokyoNight->setChecked(true);
|
||||||
|
isIconBlack = false;
|
||||||
|
SetUiIcons(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,5 +143,27 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
|
|||||||
themePalette.setColor(QPalette::HighlightedText, Qt::black);
|
themePalette.setColor(QPalette::HighlightedText, Qt::black);
|
||||||
qApp->setPalette(themePalette);
|
qApp->setPalette(themePalette);
|
||||||
break;
|
break;
|
||||||
|
case Theme::TokyoNight:
|
||||||
|
mw_searchbar->setStyleSheet(
|
||||||
|
"QLineEdit {"
|
||||||
|
"background-color: #1a1b26; color: #9d7cd8; border: 1px solid #9d7cd8; "
|
||||||
|
"border-radius: 4px; padding: 5px; }"
|
||||||
|
"QLineEdit:focus {"
|
||||||
|
"border: 1px solid #7aa2f7; }");
|
||||||
|
themePalette.setColor(QPalette::Window, QColor(31, 35, 53));
|
||||||
|
themePalette.setColor(QPalette::WindowText, QColor(192, 202, 245));
|
||||||
|
themePalette.setColor(QPalette::Base, QColor(25, 28, 39));
|
||||||
|
themePalette.setColor(QPalette::AlternateBase, QColor(36, 40, 59));
|
||||||
|
themePalette.setColor(QPalette::ToolTipBase, QColor(192, 202, 245));
|
||||||
|
themePalette.setColor(QPalette::ToolTipText, QColor(192, 202, 245));
|
||||||
|
themePalette.setColor(QPalette::Text, QColor(192, 202, 245));
|
||||||
|
themePalette.setColor(QPalette::Button, QColor(30, 30, 41));
|
||||||
|
themePalette.setColor(QPalette::ButtonText, QColor(192, 202, 245));
|
||||||
|
themePalette.setColor(QPalette::BrightText, QColor(197, 59, 83));
|
||||||
|
themePalette.setColor(QPalette::Link, QColor(79, 214, 190));
|
||||||
|
themePalette.setColor(QPalette::Highlight, QColor(79, 214, 190));
|
||||||
|
themePalette.setColor(QPalette::HighlightedText, Qt::black);
|
||||||
|
qApp->setPalette(themePalette);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
enum class Theme : int { Dark, Light, Green, Blue, Violet, Gruvbox };
|
enum class Theme : int { Dark, Light, Green, Blue, Violet, Gruvbox, TokyoNight };
|
||||||
|
|
||||||
class WindowThemes : public QObject {
|
class WindowThemes : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -37,6 +37,7 @@ public:
|
|||||||
QAction* setThemeBlue;
|
QAction* setThemeBlue;
|
||||||
QAction* setThemeViolet;
|
QAction* setThemeViolet;
|
||||||
QAction* setThemeGruvbox;
|
QAction* setThemeGruvbox;
|
||||||
|
QAction* setThemeTokyoNight;
|
||||||
QWidget* centralWidget;
|
QWidget* centralWidget;
|
||||||
QLineEdit* mw_searchbar;
|
QLineEdit* mw_searchbar;
|
||||||
QPushButton* playButton;
|
QPushButton* playButton;
|
||||||
@ -162,6 +163,9 @@ public:
|
|||||||
setThemeGruvbox = new QAction(MainWindow);
|
setThemeGruvbox = new QAction(MainWindow);
|
||||||
setThemeGruvbox->setObjectName("setThemeGruvbox");
|
setThemeGruvbox->setObjectName("setThemeGruvbox");
|
||||||
setThemeGruvbox->setCheckable(true);
|
setThemeGruvbox->setCheckable(true);
|
||||||
|
setThemeTokyoNight = new QAction(MainWindow);
|
||||||
|
setThemeTokyoNight->setObjectName("setThemeTokyoNight");
|
||||||
|
setThemeTokyoNight->setCheckable(true);
|
||||||
centralWidget = new QWidget(MainWindow);
|
centralWidget = new QWidget(MainWindow);
|
||||||
centralWidget->setObjectName("centralWidget");
|
centralWidget->setObjectName("centralWidget");
|
||||||
sizePolicy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth());
|
sizePolicy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth());
|
||||||
@ -287,6 +291,7 @@ public:
|
|||||||
menuThemes->addAction(setThemeBlue);
|
menuThemes->addAction(setThemeBlue);
|
||||||
menuThemes->addAction(setThemeViolet);
|
menuThemes->addAction(setThemeViolet);
|
||||||
menuThemes->addAction(setThemeGruvbox);
|
menuThemes->addAction(setThemeGruvbox);
|
||||||
|
menuThemes->addAction(setThemeTokyoNight);
|
||||||
menuGame_List_Icons->addAction(setIconSizeTinyAct);
|
menuGame_List_Icons->addAction(setIconSizeTinyAct);
|
||||||
menuGame_List_Icons->addAction(setIconSizeSmallAct);
|
menuGame_List_Icons->addAction(setIconSizeSmallAct);
|
||||||
menuGame_List_Icons->addAction(setIconSizeMediumAct);
|
menuGame_List_Icons->addAction(setIconSizeMediumAct);
|
||||||
@ -374,6 +379,7 @@ public:
|
|||||||
setThemeBlue->setText(QCoreApplication::translate("MainWindow", "Blue", nullptr));
|
setThemeBlue->setText(QCoreApplication::translate("MainWindow", "Blue", nullptr));
|
||||||
setThemeViolet->setText(QCoreApplication::translate("MainWindow", "Violet", nullptr));
|
setThemeViolet->setText(QCoreApplication::translate("MainWindow", "Violet", nullptr));
|
||||||
setThemeGruvbox->setText("Gruvbox");
|
setThemeGruvbox->setText("Gruvbox");
|
||||||
|
setThemeTokyoNight->setText("Tokyo Night");
|
||||||
toolBar->setWindowTitle(QCoreApplication::translate("MainWindow", "toolBar", nullptr));
|
toolBar->setWindowTitle(QCoreApplication::translate("MainWindow", "toolBar", nullptr));
|
||||||
} // retranslateUi
|
} // retranslateUi
|
||||||
};
|
};
|
||||||
|
@ -47,6 +47,9 @@ PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* pare
|
|||||||
|
|
||||||
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this,
|
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this,
|
||||||
[=, this](const QPoint& pos) {
|
[=, this](const QPoint& pos) {
|
||||||
|
if (treeWidget->selectedItems().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_gui_context_menus.RequestGameMenuPKGViewer(pos, m_full_pkg_list, treeWidget,
|
m_gui_context_menus.RequestGameMenuPKGViewer(pos, m_full_pkg_list, treeWidget,
|
||||||
InstallDragDropPkg);
|
InstallDragDropPkg);
|
||||||
});
|
});
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user