mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 00:42:48 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
9124e3d536
@ -120,7 +120,7 @@ find_package(SDL3 3.1.2 CONFIG)
|
|||||||
find_package(stb MODULE)
|
find_package(stb MODULE)
|
||||||
find_package(toml11 4.2.0 CONFIG)
|
find_package(toml11 4.2.0 CONFIG)
|
||||||
find_package(tsl-robin-map 1.3.0 CONFIG)
|
find_package(tsl-robin-map 1.3.0 CONFIG)
|
||||||
find_package(VulkanHeaders 1.4.303 CONFIG)
|
find_package(VulkanHeaders 1.4.305 CONFIG)
|
||||||
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
|
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
|
||||||
find_package(xbyak 7.07 CONFIG)
|
find_package(xbyak 7.07 CONFIG)
|
||||||
find_package(xxHash 0.8.2 MODULE)
|
find_package(xxHash 0.8.2 MODULE)
|
||||||
@ -344,6 +344,8 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.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.cpp
|
||||||
src/core/libraries/mouse/mouse.h
|
src/core/libraries/mouse/mouse.h
|
||||||
|
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
|
||||||
|
src/core/libraries/web_browser_dialog/webbrowserdialog.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
||||||
@ -434,6 +436,13 @@ set(NP_LIBS src/core/libraries/np_common/np_common.cpp
|
|||||||
src/core/libraries/np_trophy/np_trophy_error.h
|
src/core/libraries/np_trophy/np_trophy_error.h
|
||||||
src/core/libraries/np_web_api/np_web_api.cpp
|
src/core/libraries/np_web_api/np_web_api.cpp
|
||||||
src/core/libraries/np_web_api/np_web_api.h
|
src/core/libraries/np_web_api/np_web_api.h
|
||||||
|
src/core/libraries/np_party/np_party.cpp
|
||||||
|
src/core/libraries/np_party/np_party.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
|
||||||
|
src/core/libraries/zlib/zlib_sce.h
|
||||||
|
src/core/libraries/zlib/zlib_error.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||||
@ -557,6 +566,16 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||||||
src/core/devices/logger.cpp
|
src/core/devices/logger.cpp
|
||||||
src/core/devices/logger.h
|
src/core/devices/logger.h
|
||||||
src/core/devices/nop_device.h
|
src/core/devices/nop_device.h
|
||||||
|
src/core/devices/console_device.cpp
|
||||||
|
src/core/devices/console_device.h
|
||||||
|
src/core/devices/deci_tty6_device.cpp
|
||||||
|
src/core/devices/deci_tty6_device.h
|
||||||
|
src/core/devices/random_device.cpp
|
||||||
|
src/core/devices/random_device.h
|
||||||
|
src/core/devices/urandom_device.cpp
|
||||||
|
src/core/devices/urandom_device.h
|
||||||
|
src/core/devices/srandom_device.cpp
|
||||||
|
src/core/devices/srandom_device.h
|
||||||
src/core/file_format/pfs.h
|
src/core/file_format/pfs.h
|
||||||
src/core/file_format/pkg.cpp
|
src/core/file_format/pkg.cpp
|
||||||
src/core/file_format/pkg.h
|
src/core/file_format/pkg.h
|
||||||
@ -598,6 +617,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||||||
${PLAYGO_LIB}
|
${PLAYGO_LIB}
|
||||||
${RANDOM_LIB}
|
${RANDOM_LIB}
|
||||||
${USBD_LIB}
|
${USBD_LIB}
|
||||||
|
${ZLIB_LIB}
|
||||||
${MISC_LIBS}
|
${MISC_LIBS}
|
||||||
${IME_LIB}
|
${IME_LIB}
|
||||||
${FIBER_LIB}
|
${FIBER_LIB}
|
||||||
@ -741,8 +761,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
|||||||
src/video_core/renderer_vulkan/vk_common.h
|
src/video_core/renderer_vulkan/vk_common.h
|
||||||
src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
|
src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
|
||||||
src/video_core/renderer_vulkan/vk_compute_pipeline.h
|
src/video_core/renderer_vulkan/vk_compute_pipeline.h
|
||||||
src/video_core/renderer_vulkan/vk_descriptor_update_queue.cpp
|
|
||||||
src/video_core/renderer_vulkan/vk_descriptor_update_queue.h
|
|
||||||
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
|
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
|
||||||
src/video_core/renderer_vulkan/vk_graphics_pipeline.h
|
src/video_core/renderer_vulkan/vk_graphics_pipeline.h
|
||||||
src/video_core/renderer_vulkan/vk_instance.cpp
|
src/video_core/renderer_vulkan/vk_instance.cpp
|
||||||
|
@ -55,6 +55,9 @@ This project began as a fun project. Given our limited free time, it may take so
|
|||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> If you want to use shadPS4 to play your games, you don't have to follow the build instructions, you can simply download the emulator from either the [**release tab**](https://github.com/shadps4-emu/shadPS4/releases) or the [**action tab**](https://github.com/shadps4-emu/shadPS4/actions).
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
Check the build instructions for [**Windows**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-windows.md).
|
Check the build instructions for [**Windows**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-windows.md).
|
||||||
@ -76,6 +79,9 @@ For more information on how to test, debug and report issues with the emulator o
|
|||||||
|
|
||||||
# Keyboard and Mouse Mappings
|
# Keyboard and Mouse Mappings
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Some keyboards may also require you to hold the Fn key to use the F\* keys. Mac users should use the Command key instead of Control, and need to use Command+F11 for full screen to avoid conflicting with system key bindings.
|
||||||
|
|
||||||
| Button | Function |
|
| Button | Function |
|
||||||
|-------------|-------------|
|
|-------------|-------------|
|
||||||
F10 | FPS Counter
|
F10 | FPS Counter
|
||||||
|
@ -14,6 +14,7 @@ path = [
|
|||||||
"documents/changelog.md",
|
"documents/changelog.md",
|
||||||
"documents/Quickstart/2.png",
|
"documents/Quickstart/2.png",
|
||||||
"documents/Screenshots/*",
|
"documents/Screenshots/*",
|
||||||
|
"documents/Screenshots/Linux/*",
|
||||||
"externals/MoltenVK/MoltenVK_icd.json",
|
"externals/MoltenVK/MoltenVK_icd.json",
|
||||||
"scripts/ps4_names.txt",
|
"scripts/ps4_names.txt",
|
||||||
"src/images/about_icon.png",
|
"src/images/about_icon.png",
|
||||||
|
@ -22,7 +22,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
- A processor with at least 4 cores and 6 threads
|
- A processor with at least 4 cores and 6 threads
|
||||||
- Above 2.5 GHz frequency
|
- Above 2.5 GHz frequency
|
||||||
- required support AVX2 extension or Rosetta 2 on ARM
|
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
|
||||||
|
- **Intel**: Haswell generation or newer
|
||||||
|
- **AMD**: Jaguar generation or newer
|
||||||
|
- **Apple**: Rosetta 2 on macOS 15 or newer
|
||||||
|
|
||||||
### GPU
|
### GPU
|
||||||
|
|
||||||
|
BIN
documents/Screenshots/Linux/1.png
Normal file
BIN
documents/Screenshots/Linux/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
documents/Screenshots/Linux/2.png
Normal file
BIN
documents/Screenshots/Linux/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
documents/Screenshots/Linux/3.png
Normal file
BIN
documents/Screenshots/Linux/3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
documents/Screenshots/Linux/4.png
Normal file
BIN
documents/Screenshots/Linux/4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
documents/Screenshots/Linux/5.png
Normal file
BIN
documents/Screenshots/Linux/5.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -3,59 +3,134 @@ SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
|
|||||||
SPDX-License-Identifier: GPL-2.0-or-later
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Build shadPS4 for Linux
|
## Build shadPS4 for Linux
|
||||||
|
|
||||||
### Install the necessary tools to build shadPS4:
|
First and foremost, Clang 18 is the **recommended compiler** as it is used for official builds and CI. If you build with GCC, you might encounter issues — please report any you find. Additionally, if you choose to use GCC, please build shadPS4 with Clang at least once before creating an `[APP BUG]` issue or submitting a pull request.
|
||||||
|
|
||||||
|
## Preparatory steps
|
||||||
|
|
||||||
|
### Installing dependencies
|
||||||
|
|
||||||
#### Debian & Ubuntu
|
#### Debian & Ubuntu
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt install build-essential clang git cmake libasound2-dev libpulse-dev libopenal-dev libssl-dev zlib1g-dev libedit-dev libudev-dev libevdev-dev libsdl2-dev libjack-dev libsndio-dev qt6-base-dev qt6-tools-dev qt6-multimedia-dev libvulkan-dev vulkan-validationlayers
|
sudo apt install build-essential clang git cmake libasound2-dev libpulse-dev libopenal-dev libssl-dev zlib1g-dev libedit-dev libudev-dev libevdev-dev libsdl2-dev libjack-dev libsndio-dev qt6-base-dev qt6-tools-dev qt6-multimedia-dev libvulkan-dev vulkan-validationlayers
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Fedora
|
#### Fedora
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo dnf install clang git cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel libXext-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers
|
sudo dnf install clang git cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel libXext-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Arch Linux
|
#### Arch Linux
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo pacman -S base-devel clang git cmake sndio jack2 openal qt6-base qt6-declarative qt6-multimedia sdl2 vulkan-validation-layers
|
sudo pacman -S base-devel clang git cmake sndio jack2 openal qt6-base qt6-declarative qt6-multimedia sdl2 vulkan-validation-layers
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Note**: The `shadps4-git` AUR package is not maintained by any of the developers, and it uses the default compiler, which is often set to GCC. Use at your own discretion.
|
||||||
|
|
||||||
#### OpenSUSE
|
#### OpenSUSE
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo zypper install clang git cmake libasound2 libpulse-devel libsndio7 libjack-devel openal-soft-devel libopenssl-devel zlib-devel libedit-devel systemd-devel libevdev-devel qt6-base-devel qt6-multimedia-devel qt6-svg-devel qt6-linguist-devel qt6-gui-private-devel vulkan-devel vulkan-validationlayers
|
sudo zypper install clang git cmake libasound2 libpulse-devel libsndio7 libjack-devel openal-soft-devel libopenssl-devel zlib-devel libedit-devel systemd-devel libevdev-devel qt6-base-devel qt6-multimedia-devel qt6-svg-devel qt6-linguist-devel qt6-gui-private-devel vulkan-devel vulkan-validationlayers
|
||||||
```
|
```
|
||||||
### Cloning and compiling:
|
|
||||||
|
|
||||||
Clone the repository recursively:
|
#### Other Linux distributions
|
||||||
|
|
||||||
|
You can try one of two methods:
|
||||||
|
|
||||||
|
- Search the packages by name and install them with your package manager, or
|
||||||
|
- Install [distrobox](https://distrobox.it/), create a container using any of the distributions cited above as a base, for Arch Linux you'd do:
|
||||||
|
|
||||||
|
```
|
||||||
|
distrobox create --name archlinux --init --image archlinux:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
and install the dependencies on that container as cited above.
|
||||||
|
This option is **highly recommended** for NixOS and distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS).
|
||||||
|
|
||||||
|
### Cloning
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone --recursive https://github.com/shadps4-emu/shadPS4.git
|
git clone --recursive https://github.com/shadps4-emu/shadPS4.git
|
||||||
cd shadPS4
|
cd shadPS4
|
||||||
```
|
```
|
||||||
|
|
||||||
Generate the build directory in the shadPS4 directory. To disable the QT GUI, remove the ```-DENABLE_QT_GUI=ON``` flag:
|
## Building
|
||||||
|
|
||||||
|
There are 3 options you can choose from. Option 1 is **highly recommended**.
|
||||||
|
|
||||||
|
#### Option 1: Terminal-only
|
||||||
|
|
||||||
|
1. Generate the build directory in the shadPS4 directory.
|
||||||
|
|
||||||
**Note**: Clang is the compiler used for official builds and CI. If you build with GCC, you might encounter issues—please report any you find. If you choose to use GCC, we recommend building with Clang at least once before submitting a pull request.
|
|
||||||
```
|
```
|
||||||
cmake -S . -B build/ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
cmake -S . -B build/ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||||
```
|
```
|
||||||
|
|
||||||
Enter the directory:
|
To disable the Qt GUI, remove the `-DENABLE_QT_GUI=ON` flag. To change the build type (for debugging), add `-DCMAKE_BUILD_TYPE=Debug`.
|
||||||
|
|
||||||
|
2. Use CMake to build the project:
|
||||||
|
|
||||||
```
|
```
|
||||||
cd build/
|
cmake --build ./build --parallel$(nproc)
|
||||||
```
|
```
|
||||||
|
|
||||||
Use make to build the project:
|
If your computer freezes during this step, this could be caused by excessive system resource usage. In that case, remove `--parallel$(nproc)`.
|
||||||
|
|
||||||
|
Now run the emulator. If Qt was enabled at configure time:
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake --build . --parallel$(nproc)
|
./build/shadps4
|
||||||
```
|
```
|
||||||
|
|
||||||
Now run the emulator. If QT is enabled:
|
|
||||||
```
|
|
||||||
./shadps4
|
|
||||||
```
|
|
||||||
Otherwise, specify the path to your PKG's boot file:
|
Otherwise, specify the path to your PKG's boot file:
|
||||||
|
|
||||||
```
|
```
|
||||||
./shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
|
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also specify the Game ID as an argument for which game to boot, as long as the folder containing the games is specified in config.toml (example: Bloodborne (US) is CUSA00900).
|
||||||
|
#### Option 2: Configuring with cmake-gui
|
||||||
|
|
||||||
|
`cmake-gui` should be installed by default alongside `cmake`, if not search for the package in your package manager and install it.
|
||||||
|
|
||||||
|
Open `cmake-gui` and specify the source code and build directories. If you cloned the source code to your Home directory, it would be `/home/user/shadPS4` and `/home/user/shadPS4/build`.
|
||||||
|
|
||||||
|
Click on Configure, select "Unix Makefiles", select "Specify native compilers", click Next and choose `clang` and `clang++` as the C and CXX compilers. Usually they are located in `/bin/clang` and `/bin/clang++`. Click on Finish and let it configure the project.
|
||||||
|
|
||||||
|
Now every option should be displayed in red. Change anything you want, then click on Generate to make the changes permanent, then open a terminal window and do step 2 of Option 1.
|
||||||
|
|
||||||
|
#### Option 3: Visual Studio Code
|
||||||
|
|
||||||
|
This option is pretty convoluted and should only be used if you have VSCode as your default IDE, or just prefer building and debugging projects through it. This also assumes that you're using an Arch Linux environment, as the naming for some options might differ from other distros.
|
||||||
|
|
||||||
|
[Download Visual Studio Code for your platform](https://code.visualstudio.com/download), or use [Code - OSS](https://github.com/microsoft/vscode) if you'd like. Code - OSS is available on most Linux distributions' package repositories (on Arch Linux it is simply named `code`).
|
||||||
|
|
||||||
|
Once set up, go to Extensions and install "CMake Tools":
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can also install other CMake and Clang related extensions if you'd like, but this one is what enables you to configure and build CMake projects directly within VSCode.
|
||||||
|
|
||||||
|
Go to Settings, filter by `@ext:ms-vscode.cmake-tools configure` and disable this option:
|
||||||
|
|
||||||
|

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

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

|
||||||
|
|
||||||
|
When hovering over Project Status > Configure, there should be an icon titled "Configure". Click on it and let it configure the project, then do the same for Project Status > Build.
|
||||||
|
|
||||||
|
If you want to debug it, change the build type under Project Status > Configure to Debug (it should be the default) and compile it, then click on the icon in Project Status > Debug. If you simply want to launch the shadPS4 executable from within VSCode, click on the icon in Project Status > Launch.
|
||||||
|
|
||||||
|
Don't forget to change the launch target for both options to the shadPS4 executable inside shadPS4/build:
|
||||||
|
|
||||||
|

|
||||||
|
2
externals/MoltenVK/MoltenVK
vendored
2
externals/MoltenVK/MoltenVK
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9f0b616d9e2c39464d2a859b79dbc655c4a30e7e
|
Subproject commit 0c090001cb42997031cfe43914340e2639944972
|
2
externals/MoltenVK/SPIRV-Cross
vendored
2
externals/MoltenVK/SPIRV-Cross
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 6173e24b31f09a0c3217103a130e74c4ddec14a6
|
Subproject commit 1a7b7ef6de02cf6767e42b10ddad217c45e90d47
|
2
externals/sdl3
vendored
2
externals/sdl3
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 22422f7748d5128135995ed34c8f8012861c7332
|
Subproject commit a336b62d8b0b97b09214e053203e442e2b6e2be5
|
2
externals/sirit
vendored
2
externals/sirit
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 26ad5a9d0fe13260b0d7d6c64419d01a196b2e32
|
Subproject commit d6f3c0d99862ab2ff8f95e9ac221560f1f97e29a
|
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 6a74a7d65cafa19e38ec116651436cce6efd5b2e
|
Subproject commit a03d2f6d5753b365d704d58161825890baad0755
|
27
src/common/adaptive_mutex.h
Normal file
27
src/common/adaptive_mutex.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||||
|
class AdaptiveMutex {
|
||||||
|
public:
|
||||||
|
void lock() {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
}
|
||||||
|
void unlock() {
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_mutex_t mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
|
||||||
|
};
|
||||||
|
#endif // PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||||
|
|
||||||
|
} // namespace Common
|
@ -45,6 +45,9 @@ static std::string logFilter;
|
|||||||
static std::string logType = "async";
|
static std::string logType = "async";
|
||||||
static std::string userName = "shadPS4";
|
static std::string userName = "shadPS4";
|
||||||
static std::string updateChannel;
|
static std::string updateChannel;
|
||||||
|
static std::string chooseHomeTab;
|
||||||
|
static u16 deadZoneLeft = 2.0;
|
||||||
|
static u16 deadZoneRight = 2.0;
|
||||||
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;
|
||||||
@ -76,6 +79,7 @@ static std::string trophyKey;
|
|||||||
static bool load_game_size = true;
|
static bool load_game_size = true;
|
||||||
std::vector<std::filesystem::path> settings_install_dirs = {};
|
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||||
std::filesystem::path settings_addon_install_dir = {};
|
std::filesystem::path settings_addon_install_dir = {};
|
||||||
|
std::filesystem::path save_data_path = {};
|
||||||
u32 main_window_geometry_x = 400;
|
u32 main_window_geometry_x = 400;
|
||||||
u32 main_window_geometry_y = 400;
|
u32 main_window_geometry_y = 400;
|
||||||
u32 main_window_geometry_w = 1280;
|
u32 main_window_geometry_w = 1280;
|
||||||
@ -108,6 +112,13 @@ bool GetLoadGameSizeEnabled() {
|
|||||||
return load_game_size;
|
return load_game_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path GetSaveDataPath() {
|
||||||
|
if (save_data_path.empty()) {
|
||||||
|
return Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir);
|
||||||
|
}
|
||||||
|
return save_data_path;
|
||||||
|
}
|
||||||
|
|
||||||
void setLoadGameSizeEnabled(bool enable) {
|
void setLoadGameSizeEnabled(bool enable) {
|
||||||
load_game_size = enable;
|
load_game_size = enable;
|
||||||
}
|
}
|
||||||
@ -140,6 +151,14 @@ bool getEnableDiscordRPC() {
|
|||||||
return enableDiscordRPC;
|
return enableDiscordRPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u16 leftDeadZone() {
|
||||||
|
return deadZoneLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 rightDeadZone() {
|
||||||
|
return deadZoneRight;
|
||||||
|
}
|
||||||
|
|
||||||
s16 getCursorState() {
|
s16 getCursorState() {
|
||||||
return cursorState;
|
return cursorState;
|
||||||
}
|
}
|
||||||
@ -176,6 +195,10 @@ std::string getUpdateChannel() {
|
|||||||
return updateChannel;
|
return updateChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getChooseHomeTab() {
|
||||||
|
return chooseHomeTab;
|
||||||
|
}
|
||||||
|
|
||||||
std::string getBackButtonBehavior() {
|
std::string getBackButtonBehavior() {
|
||||||
return backButtonBehavior;
|
return backButtonBehavior;
|
||||||
}
|
}
|
||||||
@ -244,18 +267,28 @@ bool vkValidationGpuEnabled() {
|
|||||||
return vkValidationGpu;
|
return vkValidationGpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vkCrashDiagnosticEnabled() {
|
bool getVkCrashDiagnosticEnabled() {
|
||||||
return vkCrashDiagnostic;
|
return vkCrashDiagnostic;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vkHostMarkersEnabled() {
|
bool getVkHostMarkersEnabled() {
|
||||||
// Forced on when crash diagnostic enabled.
|
return vkHostMarkers;
|
||||||
return vkHostMarkers || vkCrashDiagnostic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vkGuestMarkersEnabled() {
|
bool getVkGuestMarkersEnabled() {
|
||||||
// Forced on when crash diagnostic enabled.
|
return vkGuestMarkers;
|
||||||
return vkGuestMarkers || vkCrashDiagnostic;
|
}
|
||||||
|
|
||||||
|
void setVkCrashDiagnosticEnabled(bool enable) {
|
||||||
|
vkCrashDiagnostic = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVkHostMarkersEnabled(bool enable) {
|
||||||
|
vkHostMarkers = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVkGuestMarkersEnabled(bool enable) {
|
||||||
|
vkGuestMarkers = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getSeparateUpdateEnabled() {
|
bool getSeparateUpdateEnabled() {
|
||||||
@ -381,6 +414,9 @@ void setUserName(const std::string& type) {
|
|||||||
void setUpdateChannel(const std::string& type) {
|
void setUpdateChannel(const std::string& type) {
|
||||||
updateChannel = type;
|
updateChannel = type;
|
||||||
}
|
}
|
||||||
|
void setChooseHomeTab(const std::string& type) {
|
||||||
|
chooseHomeTab = type;
|
||||||
|
}
|
||||||
|
|
||||||
void setBackButtonBehavior(const std::string& type) {
|
void setBackButtonBehavior(const std::string& type) {
|
||||||
backButtonBehavior = type;
|
backButtonBehavior = type;
|
||||||
@ -492,6 +528,10 @@ void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_insta
|
|||||||
settings_install_dirs = settings_install_dirs_config;
|
settings_install_dirs = settings_install_dirs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSaveDataPath(const std::filesystem::path& path) {
|
||||||
|
save_data_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
u32 getMainWindowGeometryX() {
|
u32 getMainWindowGeometryX() {
|
||||||
return main_window_geometry_x;
|
return main_window_geometry_x;
|
||||||
}
|
}
|
||||||
@ -615,11 +655,14 @@ void load(const std::filesystem::path& path) {
|
|||||||
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
|
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
|
||||||
checkCompatibilityOnStartup =
|
checkCompatibilityOnStartup =
|
||||||
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
|
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
|
||||||
|
chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", "Release");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.contains("Input")) {
|
if (data.contains("Input")) {
|
||||||
const toml::value& input = data.at("Input");
|
const toml::value& input = data.at("Input");
|
||||||
|
|
||||||
|
deadZoneLeft = toml::find_or<float>(input, "deadZoneLeft", 2.0);
|
||||||
|
deadZoneRight = toml::find_or<float>(input, "deadZoneRight", 2.0);
|
||||||
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
||||||
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
||||||
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
||||||
@ -678,6 +721,8 @@ void load(const std::filesystem::path& path) {
|
|||||||
addGameInstallDir(std::filesystem::path{dir});
|
addGameInstallDir(std::filesystem::path{dir});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {});
|
||||||
|
|
||||||
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
||||||
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
|
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
|
||||||
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
|
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
|
||||||
@ -734,11 +779,14 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["General"]["logType"] = logType;
|
data["General"]["logType"] = logType;
|
||||||
data["General"]["userName"] = userName;
|
data["General"]["userName"] = userName;
|
||||||
data["General"]["updateChannel"] = updateChannel;
|
data["General"]["updateChannel"] = updateChannel;
|
||||||
|
data["General"]["chooseHomeTab"] = chooseHomeTab;
|
||||||
data["General"]["showSplash"] = isShowSplash;
|
data["General"]["showSplash"] = isShowSplash;
|
||||||
data["General"]["autoUpdate"] = isAutoUpdate;
|
data["General"]["autoUpdate"] = isAutoUpdate;
|
||||||
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
||||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||||
|
data["Input"]["deadZoneLeft"] = deadZoneLeft;
|
||||||
|
data["Input"]["deadZoneRight"] = deadZoneRight;
|
||||||
data["Input"]["cursorState"] = cursorState;
|
data["Input"]["cursorState"] = cursorState;
|
||||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||||
@ -770,6 +818,7 @@ void save(const std::filesystem::path& path) {
|
|||||||
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||||
}
|
}
|
||||||
data["GUI"]["installDirs"] = install_dirs;
|
data["GUI"]["installDirs"] = install_dirs;
|
||||||
|
data["GUI"]["saveDataPath"] = std::string{fmt::UTF(save_data_path.u8string()).data};
|
||||||
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
|
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
|
||||||
|
|
||||||
data["GUI"]["addonInstallDir"] =
|
data["GUI"]["addonInstallDir"] =
|
||||||
@ -842,6 +891,7 @@ void setDefaultValues() {
|
|||||||
} else {
|
} else {
|
||||||
updateChannel = "Nightly";
|
updateChannel = "Nightly";
|
||||||
}
|
}
|
||||||
|
chooseHomeTab = "General";
|
||||||
cursorState = HideCursorState::Idle;
|
cursorState = HideCursorState::Idle;
|
||||||
cursorHideTimeout = 5;
|
cursorHideTimeout = 5;
|
||||||
backButtonBehavior = "left";
|
backButtonBehavior = "left";
|
||||||
|
@ -18,6 +18,7 @@ void saveMainWindow(const std::filesystem::path& path);
|
|||||||
std::string getTrophyKey();
|
std::string getTrophyKey();
|
||||||
void setTrophyKey(std::string key);
|
void setTrophyKey(std::string key);
|
||||||
bool GetLoadGameSizeEnabled();
|
bool GetLoadGameSizeEnabled();
|
||||||
|
std::filesystem::path GetSaveDataPath();
|
||||||
void setLoadGameSizeEnabled(bool enable);
|
void setLoadGameSizeEnabled(bool enable);
|
||||||
bool getIsFullscreen();
|
bool getIsFullscreen();
|
||||||
std::string getFullscreenMode();
|
std::string getFullscreenMode();
|
||||||
@ -34,7 +35,10 @@ std::string getLogFilter();
|
|||||||
std::string getLogType();
|
std::string getLogType();
|
||||||
std::string getUserName();
|
std::string getUserName();
|
||||||
std::string getUpdateChannel();
|
std::string getUpdateChannel();
|
||||||
|
std::string getChooseHomeTab();
|
||||||
|
|
||||||
|
u16 leftDeadZone();
|
||||||
|
u16 rightDeadZone();
|
||||||
s16 getCursorState();
|
s16 getCursorState();
|
||||||
int getCursorHideTimeout();
|
int getCursorHideTimeout();
|
||||||
std::string getBackButtonBehavior();
|
std::string getBackButtonBehavior();
|
||||||
@ -78,8 +82,10 @@ void setLanguage(u32 language);
|
|||||||
void setNeoMode(bool enable);
|
void setNeoMode(bool enable);
|
||||||
void setUserName(const std::string& type);
|
void setUserName(const std::string& type);
|
||||||
void setUpdateChannel(const std::string& type);
|
void setUpdateChannel(const std::string& type);
|
||||||
|
void setChooseHomeTab(const std::string& type);
|
||||||
void setSeparateUpdateEnabled(bool use);
|
void setSeparateUpdateEnabled(bool use);
|
||||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
|
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
|
||||||
|
void setSaveDataPath(const std::filesystem::path& path);
|
||||||
void setCompatibilityEnabled(bool use);
|
void setCompatibilityEnabled(bool use);
|
||||||
void setCheckCompatibilityOnStartup(bool use);
|
void setCheckCompatibilityOnStartup(bool use);
|
||||||
|
|
||||||
@ -100,9 +106,12 @@ void setRdocEnabled(bool enable);
|
|||||||
bool vkValidationEnabled();
|
bool vkValidationEnabled();
|
||||||
bool vkValidationSyncEnabled();
|
bool vkValidationSyncEnabled();
|
||||||
bool vkValidationGpuEnabled();
|
bool vkValidationGpuEnabled();
|
||||||
bool vkCrashDiagnosticEnabled();
|
bool getVkCrashDiagnosticEnabled();
|
||||||
bool vkHostMarkersEnabled();
|
bool getVkHostMarkersEnabled();
|
||||||
bool vkGuestMarkersEnabled();
|
bool getVkGuestMarkersEnabled();
|
||||||
|
void setVkCrashDiagnosticEnabled(bool enable);
|
||||||
|
void setVkHostMarkersEnabled(bool enable);
|
||||||
|
void setVkGuestMarkersEnabled(bool enable);
|
||||||
|
|
||||||
// Gui
|
// Gui
|
||||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||||
|
@ -80,6 +80,7 @@ public:
|
|||||||
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;
|
||||||
|
static constexpr u32 FW_55 = 0x5500000;
|
||||||
static constexpr u32 FW_80 = 0x8000000;
|
static constexpr u32 FW_80 = 0x8000000;
|
||||||
|
|
||||||
static ElfInfo& Instance() {
|
static ElfInfo& Instance() {
|
||||||
|
@ -131,6 +131,9 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||||||
SUB(Lib, Videodec) \
|
SUB(Lib, Videodec) \
|
||||||
SUB(Lib, RazorCpu) \
|
SUB(Lib, RazorCpu) \
|
||||||
SUB(Lib, Mouse) \
|
SUB(Lib, Mouse) \
|
||||||
|
SUB(Lib, WebBrowserDialog) \
|
||||||
|
SUB(Lib, NpParty) \
|
||||||
|
SUB(Lib, Zlib) \
|
||||||
CLS(Frontend) \
|
CLS(Frontend) \
|
||||||
CLS(Render) \
|
CLS(Render) \
|
||||||
SUB(Render, Vulkan) \
|
SUB(Render, Vulkan) \
|
||||||
|
@ -98,6 +98,9 @@ enum class Class : u8 {
|
|||||||
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
|
Lib_Mouse, ///< The LibSceMouse implementation
|
||||||
|
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||||
|
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||||
|
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||||
Frontend, ///< Emulator UI
|
Frontend, ///< Emulator UI
|
||||||
Render, ///< Video Core
|
Render, ///< Video Core
|
||||||
Render_Vulkan, ///< Vulkan backend
|
Render_Vulkan, ///< Vulkan backend
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@ -189,14 +190,16 @@ void OnGameLoaded() {
|
|||||||
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
|
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
|
||||||
QString patchDir;
|
QString patchDir;
|
||||||
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
|
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
|
||||||
QString repositories[] = {"GoldHEN", "shadPS4"};
|
QDir dir(patchDir);
|
||||||
|
QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
for (const QString& repository : repositories) {
|
for (const QString& folder : folders) {
|
||||||
QString filesJsonPath = patchDir + "/" + repository + "/files.json";
|
QString filesJsonPath = patchDir + "/" + folder + "/files.json";
|
||||||
|
|
||||||
QFile jsonFile(filesJsonPath);
|
QFile jsonFile(filesJsonPath);
|
||||||
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
||||||
LOG_ERROR(Loader, "Unable to open files.json for reading.");
|
LOG_ERROR(Loader, "Unable to open files.json for reading in repository {}",
|
||||||
|
folder.toStdString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,11 +223,12 @@ void OnGameLoaded() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (selectedFileName.isEmpty()) {
|
if (selectedFileName.isEmpty()) {
|
||||||
LOG_ERROR(Loader, "No patch file found for the current serial.");
|
LOG_ERROR(Loader, "No patch file found for the current serial in repository {}",
|
||||||
|
folder.toStdString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filePath = patchDir + "/" + repository + "/" + selectedFileName;
|
QString filePath = patchDir + "/" + folder + "/" + selectedFileName;
|
||||||
QFile file(filePath);
|
QFile file(filePath);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
LOG_ERROR(Loader, "Unable to open the file for reading.");
|
LOG_ERROR(Loader, "Unable to open the file for reading.");
|
||||||
|
@ -67,28 +67,25 @@ struct AddressSpace::Impl {
|
|||||||
static constexpr size_t ReductionOnFail = 1_GB;
|
static constexpr size_t ReductionOnFail = 1_GB;
|
||||||
static constexpr size_t MaxReductions = 10;
|
static constexpr size_t MaxReductions = 10;
|
||||||
|
|
||||||
size_t reduction = 0;
|
|
||||||
size_t virtual_size = SystemManagedSize + SystemReservedSize + UserSize;
|
size_t virtual_size = SystemManagedSize + SystemReservedSize + UserSize;
|
||||||
for (u32 i = 0; i < MaxReductions; i++) {
|
for (u32 i = 0; i < MaxReductions; i++) {
|
||||||
virtual_base = static_cast<u8*>(VirtualAlloc2(process, NULL, virtual_size - reduction,
|
virtual_base = static_cast<u8*>(VirtualAlloc2(process, NULL, virtual_size,
|
||||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||||
PAGE_NOACCESS, ¶m, 1));
|
PAGE_NOACCESS, ¶m, 1));
|
||||||
if (virtual_base) {
|
if (virtual_base) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reduction += ReductionOnFail;
|
virtual_size -= ReductionOnFail;
|
||||||
}
|
}
|
||||||
ASSERT_MSG(virtual_base, "Unable to reserve virtual address space: {}",
|
ASSERT_MSG(virtual_base, "Unable to reserve virtual address space: {}",
|
||||||
Common::GetLastErrorMsg());
|
Common::GetLastErrorMsg());
|
||||||
|
|
||||||
// Take the reduction off of the system managed area, and leave the others unchanged.
|
|
||||||
reduction = size_t(virtual_base - SYSTEM_MANAGED_MIN);
|
|
||||||
system_managed_base = virtual_base;
|
|
||||||
system_managed_size = SystemManagedSize - reduction;
|
|
||||||
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
|
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
|
||||||
system_reserved_size = SystemReservedSize;
|
system_reserved_size = SystemReservedSize;
|
||||||
|
system_managed_base = virtual_base;
|
||||||
|
system_managed_size = system_reserved_base - virtual_base;
|
||||||
user_base = reinterpret_cast<u8*>(USER_MIN);
|
user_base = reinterpret_cast<u8*>(USER_MIN);
|
||||||
user_size = UserSize;
|
user_size = virtual_base + virtual_size - user_base;
|
||||||
|
|
||||||
LOG_INFO(Kernel_Vmm, "System managed virtual memory region: {} - {}",
|
LOG_INFO(Kernel_Vmm, "System managed virtual memory region: {} - {}",
|
||||||
fmt::ptr(system_managed_base),
|
fmt::ptr(system_managed_base),
|
||||||
@ -101,10 +98,8 @@ struct AddressSpace::Impl {
|
|||||||
|
|
||||||
// Initializer placeholder tracker
|
// Initializer placeholder tracker
|
||||||
const uintptr_t system_managed_addr = reinterpret_cast<uintptr_t>(system_managed_base);
|
const uintptr_t system_managed_addr = reinterpret_cast<uintptr_t>(system_managed_base);
|
||||||
const uintptr_t system_reserved_addr = reinterpret_cast<uintptr_t>(system_reserved_base);
|
|
||||||
const uintptr_t user_addr = reinterpret_cast<uintptr_t>(user_base);
|
|
||||||
regions.emplace(system_managed_addr,
|
regions.emplace(system_managed_addr,
|
||||||
MemoryRegion{system_managed_addr, virtual_size - reduction, false});
|
MemoryRegion{system_managed_addr, virtual_size, false});
|
||||||
|
|
||||||
// Allocate backing file that represents the total physical memory.
|
// Allocate backing file that represents the total physical memory.
|
||||||
backing_handle =
|
backing_handle =
|
||||||
|
@ -30,16 +30,6 @@
|
|||||||
|
|
||||||
using namespace Xbyak::util;
|
using namespace Xbyak::util;
|
||||||
|
|
||||||
#define MAYBE_AVX(OPCODE, ...) \
|
|
||||||
[&] { \
|
|
||||||
Cpu cpu; \
|
|
||||||
if (cpu.has(Cpu::tAVX)) { \
|
|
||||||
c.v##OPCODE(__VA_ARGS__); \
|
|
||||||
} else { \
|
|
||||||
c.OPCODE(__VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
}()
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
static Xbyak::Reg ZydisToXbyakRegister(const ZydisRegister reg) {
|
static Xbyak::Reg ZydisToXbyakRegister(const ZydisRegister reg) {
|
||||||
@ -643,7 +633,7 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||||||
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64.");
|
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64.");
|
||||||
|
|
||||||
// Get lower qword from xmm register
|
// Get lower qword from xmm register
|
||||||
MAYBE_AVX(movq, scratch1, xmm_dst);
|
c.vmovq(scratch1, xmm_dst);
|
||||||
|
|
||||||
if (index != 0) {
|
if (index != 0) {
|
||||||
c.shr(scratch1, index);
|
c.shr(scratch1, index);
|
||||||
@ -656,7 +646,7 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||||||
|
|
||||||
// Writeback to xmm register, extrq instruction says top 64-bits are undefined so we don't
|
// Writeback to xmm register, extrq instruction says top 64-bits are undefined so we don't
|
||||||
// care to preserve them
|
// care to preserve them
|
||||||
MAYBE_AVX(movq, xmm_dst, scratch1);
|
c.vmovq(xmm_dst, scratch1);
|
||||||
|
|
||||||
c.pop(scratch2);
|
c.pop(scratch2);
|
||||||
c.pop(scratch1);
|
c.pop(scratch1);
|
||||||
@ -690,7 +680,7 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||||||
c.push(mask);
|
c.push(mask);
|
||||||
|
|
||||||
// Construct the mask out of the length that resides in bottom 6 bits of source xmm
|
// Construct the mask out of the length that resides in bottom 6 bits of source xmm
|
||||||
MAYBE_AVX(movq, scratch1, xmm_src);
|
c.vmovq(scratch1, xmm_src);
|
||||||
c.mov(scratch2, scratch1);
|
c.mov(scratch2, scratch1);
|
||||||
c.and_(scratch2, 0x3F);
|
c.and_(scratch2, 0x3F);
|
||||||
c.jz(length_zero);
|
c.jz(length_zero);
|
||||||
@ -711,10 +701,10 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||||||
c.and_(scratch1, 0x3F);
|
c.and_(scratch1, 0x3F);
|
||||||
c.mov(scratch2, scratch1); // cl now contains the shift amount
|
c.mov(scratch2, scratch1); // cl now contains the shift amount
|
||||||
|
|
||||||
MAYBE_AVX(movq, scratch1, xmm_dst);
|
c.vmovq(scratch1, xmm_dst);
|
||||||
c.shr(scratch1, cl);
|
c.shr(scratch1, cl);
|
||||||
c.and_(scratch1, mask);
|
c.and_(scratch1, mask);
|
||||||
MAYBE_AVX(movq, xmm_dst, scratch1);
|
c.vmovq(xmm_dst, scratch1);
|
||||||
|
|
||||||
c.pop(mask);
|
c.pop(mask);
|
||||||
c.pop(scratch2);
|
c.pop(scratch2);
|
||||||
@ -765,8 +755,8 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||||||
|
|
||||||
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64.");
|
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64.");
|
||||||
|
|
||||||
MAYBE_AVX(movq, scratch1, xmm_src);
|
c.vmovq(scratch1, xmm_src);
|
||||||
MAYBE_AVX(movq, scratch2, xmm_dst);
|
c.vmovq(scratch2, xmm_dst);
|
||||||
c.mov(mask, mask_value);
|
c.mov(mask, mask_value);
|
||||||
|
|
||||||
// src &= mask
|
// src &= mask
|
||||||
@ -784,12 +774,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||||||
c.or_(scratch2, scratch1);
|
c.or_(scratch2, scratch1);
|
||||||
|
|
||||||
// Insert scratch2 into low 64 bits of dst, upper 64 bits are unaffected
|
// Insert scratch2 into low 64 bits of dst, upper 64 bits are unaffected
|
||||||
Cpu cpu;
|
c.vpinsrq(xmm_dst, xmm_dst, scratch2, 0);
|
||||||
if (cpu.has(Cpu::tAVX)) {
|
|
||||||
c.vpinsrq(xmm_dst, xmm_dst, scratch2, 0);
|
|
||||||
} else {
|
|
||||||
c.pinsrq(xmm_dst, scratch2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.pop(mask);
|
c.pop(mask);
|
||||||
c.pop(scratch2);
|
c.pop(scratch2);
|
||||||
@ -816,7 +801,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||||||
c.push(mask);
|
c.push(mask);
|
||||||
|
|
||||||
// Get upper 64 bits of src and copy it to mask and index
|
// Get upper 64 bits of src and copy it to mask and index
|
||||||
MAYBE_AVX(pextrq, index, xmm_src, 1);
|
c.vpextrq(index, xmm_src, 1);
|
||||||
c.mov(mask, index);
|
c.mov(mask, index);
|
||||||
|
|
||||||
// When length is 0, set it to 64
|
// When length is 0, set it to 64
|
||||||
@ -839,7 +824,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||||||
c.and_(index, 0x3F);
|
c.and_(index, 0x3F);
|
||||||
|
|
||||||
// src &= mask
|
// src &= mask
|
||||||
MAYBE_AVX(movq, scratch1, xmm_src);
|
c.vmovq(scratch1, xmm_src);
|
||||||
c.and_(scratch1, mask);
|
c.and_(scratch1, mask);
|
||||||
|
|
||||||
// mask = ~(mask << index)
|
// mask = ~(mask << index)
|
||||||
@ -851,12 +836,12 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||||||
c.shl(scratch1, cl);
|
c.shl(scratch1, cl);
|
||||||
|
|
||||||
// dst = (dst & mask) | src
|
// dst = (dst & mask) | src
|
||||||
MAYBE_AVX(movq, scratch2, xmm_dst);
|
c.vmovq(scratch2, xmm_dst);
|
||||||
c.and_(scratch2, mask);
|
c.and_(scratch2, mask);
|
||||||
c.or_(scratch2, scratch1);
|
c.or_(scratch2, scratch1);
|
||||||
|
|
||||||
// Upper 64 bits are undefined in insertq
|
// Upper 64 bits are undefined in insertq
|
||||||
MAYBE_AVX(movq, xmm_dst, scratch2);
|
c.vmovq(xmm_dst, scratch2);
|
||||||
|
|
||||||
c.pop(mask);
|
c.pop(mask);
|
||||||
c.pop(index);
|
c.pop(index);
|
||||||
|
@ -17,6 +17,8 @@ using namespace DebugStateType;
|
|||||||
|
|
||||||
DebugStateImpl& DebugState = *Common::Singleton<DebugStateImpl>::Instance();
|
DebugStateImpl& DebugState = *Common::Singleton<DebugStateImpl>::Instance();
|
||||||
|
|
||||||
|
bool DebugStateType::showing_debug_menu_bar = false;
|
||||||
|
|
||||||
static ThreadID ThisThreadID() {
|
static ThreadID ThisThreadID() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return GetCurrentThreadId();
|
return GetCurrentThreadId();
|
||||||
|
@ -35,6 +35,8 @@ class ShaderList;
|
|||||||
|
|
||||||
namespace DebugStateType {
|
namespace DebugStateType {
|
||||||
|
|
||||||
|
extern bool showing_debug_menu_bar;
|
||||||
|
|
||||||
enum class QueueType {
|
enum class QueueType {
|
||||||
dcb = 0,
|
dcb = 0,
|
||||||
ccb = 1,
|
ccb = 1,
|
||||||
@ -131,8 +133,6 @@ class DebugStateImpl {
|
|||||||
friend class Core::Devtools::Widget::FrameGraph;
|
friend class Core::Devtools::Widget::FrameGraph;
|
||||||
friend class Core::Devtools::Widget::ShaderList;
|
friend class Core::Devtools::Widget::ShaderList;
|
||||||
|
|
||||||
bool showing_debug_menu_bar = false;
|
|
||||||
|
|
||||||
std::queue<std::string> debug_message_popup;
|
std::queue<std::string> debug_message_popup;
|
||||||
|
|
||||||
std::mutex guest_threads_mutex{};
|
std::mutex guest_threads_mutex{};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// 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 "base_device.h"
|
#include "base_device.h"
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// 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
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
74
src/core/devices/console_device.cpp
Normal file
74
src/core/devices/console_device.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "console_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
std::shared_ptr<BaseDevice> ConsoleDevice::Create(u32 handle, const char*, int, u16) {
|
||||||
|
return std::shared_ptr<BaseDevice>(
|
||||||
|
reinterpret_cast<Devices::BaseDevice*>(new ConsoleDevice(handle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConsoleDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 ConsoleDevice::write(const void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ConsoleDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ConsoleDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 ConsoleDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 ConsoleDevice::lseek(s64 offset, int whence) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 ConsoleDevice::read(void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConsoleDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 ConsoleDevice::fsync() {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConsoleDevice::ftruncate(s64 length) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConsoleDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 ConsoleDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
33
src/core/devices/console_device.h
Normal file
33
src/core/devices/console_device.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "base_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
class ConsoleDevice final : BaseDevice {
|
||||||
|
u32 handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||||
|
explicit ConsoleDevice(u32 handle) : handle(handle) {}
|
||||||
|
|
||||||
|
~ConsoleDevice() override = default;
|
||||||
|
|
||||||
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
|
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
|
s64 lseek(s64 offset, int whence) override;
|
||||||
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
|
s32 fsync() override;
|
||||||
|
int ftruncate(s64 length) override;
|
||||||
|
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||||
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
74
src/core/devices/deci_tty6_device.cpp
Normal file
74
src/core/devices/deci_tty6_device.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "deci_tty6_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
std::shared_ptr<BaseDevice> DeciTty6Device::Create(u32 handle, const char*, int, u16) {
|
||||||
|
return std::shared_ptr<BaseDevice>(
|
||||||
|
reinterpret_cast<Devices::BaseDevice*>(new DeciTty6Device(handle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeciTty6Device::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 DeciTty6Device::write(const void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DeciTty6Device::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DeciTty6Device::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 DeciTty6Device::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 DeciTty6Device::lseek(s64 offset, int whence) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 DeciTty6Device::read(void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeciTty6Device::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 DeciTty6Device::fsync() {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeciTty6Device::ftruncate(s64 length) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeciTty6Device::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 DeciTty6Device::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
33
src/core/devices/deci_tty6_device.h
Normal file
33
src/core/devices/deci_tty6_device.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "base_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
class DeciTty6Device final : BaseDevice {
|
||||||
|
u32 handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||||
|
explicit DeciTty6Device(u32 handle) : handle(handle) {}
|
||||||
|
|
||||||
|
~DeciTty6Device() override = default;
|
||||||
|
|
||||||
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
|
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
|
s64 lseek(s64 offset, int whence) override;
|
||||||
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
|
s32 fsync() override;
|
||||||
|
int ftruncate(s64 length) override;
|
||||||
|
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||||
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
@ -1,5 +1,5 @@
|
|||||||
// 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
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// 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/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/kernel/file_system.h"
|
#include "core/libraries/kernel/file_system.h"
|
||||||
@ -17,10 +17,12 @@ s64 Logger::write(const void* buf, size_t nbytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t Logger::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
size_t Logger::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
size_t total_written = 0;
|
||||||
for (int i = 0; i < iovcnt; i++) {
|
for (int i = 0; i < iovcnt; i++) {
|
||||||
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
|
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
|
||||||
|
total_written += iov[i].iov_len;
|
||||||
}
|
}
|
||||||
return iovcnt;
|
return total_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 Logger::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
s64 Logger::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// 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
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// 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
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "base_device.h"
|
#include "base_device.h"
|
||||||
@ -17,36 +17,47 @@ public:
|
|||||||
int ioctl(u64 cmd, Common::VaCtx* args) override {
|
int ioctl(u64 cmd, Common::VaCtx* args) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 write(const void* buf, size_t nbytes) override {
|
s64 write(const void* buf, size_t nbytes) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
|
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
|
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override {
|
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 lseek(s64 offset, int whence) override {
|
s64 lseek(s64 offset, int whence) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 read(void* buf, size_t nbytes) override {
|
s64 read(void* buf, size_t nbytes) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 fsync() override {
|
s32 fsync() override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ftruncate(s64 length) override {
|
int ftruncate(s64 length) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getdents(void* buf, u32 nbytes, s64* basep) override {
|
int getdents(void* buf, u32 nbytes, s64* basep) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override {
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
78
src/core/devices/random_device.cpp
Normal file
78
src/core/devices/random_device.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "random_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
std::shared_ptr<BaseDevice> RandomDevice::Create(u32 handle, const char*, int, u16) {
|
||||||
|
std::srand(std::time(nullptr));
|
||||||
|
return std::shared_ptr<BaseDevice>(
|
||||||
|
reinterpret_cast<Devices::BaseDevice*>(new RandomDevice(handle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 RandomDevice::write(const void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RandomDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RandomDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 RandomDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 RandomDevice::lseek(s64 offset, int whence) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 RandomDevice::read(void* buf, size_t nbytes) {
|
||||||
|
auto rbuf = static_cast<char*>(buf);
|
||||||
|
for (size_t i = 0; i < nbytes; i++) {
|
||||||
|
rbuf[i] = std::rand() & 0xFF;
|
||||||
|
}
|
||||||
|
return nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 RandomDevice::fsync() {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandomDevice::ftruncate(s64 length) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 RandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
33
src/core/devices/random_device.h
Normal file
33
src/core/devices/random_device.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "base_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
class RandomDevice final : BaseDevice {
|
||||||
|
u32 handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||||
|
explicit RandomDevice(u32 handle) : handle(handle) {}
|
||||||
|
|
||||||
|
~RandomDevice() override = default;
|
||||||
|
|
||||||
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
|
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
|
s64 lseek(s64 offset, int whence) override;
|
||||||
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
|
s32 fsync() override;
|
||||||
|
int ftruncate(s64 length) override;
|
||||||
|
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||||
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
79
src/core/devices/srandom_device.cpp
Normal file
79
src/core/devices/srandom_device.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "srandom_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
std::shared_ptr<BaseDevice> SRandomDevice::Create(u32 handle, const char*, int, u16) {
|
||||||
|
std::srand(std::time(nullptr));
|
||||||
|
return std::shared_ptr<BaseDevice>(
|
||||||
|
reinterpret_cast<Devices::BaseDevice*>(new SRandomDevice(handle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int SRandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 SRandomDevice::write(const void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SRandomDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SRandomDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 SRandomDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 SRandomDevice::lseek(s64 offset, int whence) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 SRandomDevice::read(void* buf, size_t nbytes) {
|
||||||
|
auto rbuf = static_cast<char*>(buf);
|
||||||
|
for (size_t i = 0; i < nbytes; i++) {
|
||||||
|
rbuf[i] = std::rand();
|
||||||
|
}
|
||||||
|
return nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SRandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SRandomDevice::fsync() {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return s32();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SRandomDevice::ftruncate(s64 length) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SRandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 SRandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
33
src/core/devices/srandom_device.h
Normal file
33
src/core/devices/srandom_device.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "base_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
class SRandomDevice final : BaseDevice {
|
||||||
|
u32 handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||||
|
explicit SRandomDevice(u32 handle) : handle(handle) {}
|
||||||
|
|
||||||
|
~SRandomDevice() override = default;
|
||||||
|
|
||||||
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
|
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
|
s64 lseek(s64 offset, int whence) override;
|
||||||
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
|
s32 fsync() override;
|
||||||
|
int ftruncate(s64 length) override;
|
||||||
|
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||||
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
79
src/core/devices/urandom_device.cpp
Normal file
79
src/core/devices/urandom_device.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "urandom_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
std::shared_ptr<BaseDevice> URandomDevice::Create(u32 handle, const char*, int, u16) {
|
||||||
|
std::srand(std::time(nullptr));
|
||||||
|
return std::shared_ptr<BaseDevice>(
|
||||||
|
reinterpret_cast<Devices::BaseDevice*>(new URandomDevice(handle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int URandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 URandomDevice::write(const void* buf, size_t nbytes) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t URandomDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t URandomDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 URandomDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 URandomDevice::lseek(s64 offset, int whence) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 URandomDevice::read(void* buf, size_t nbytes) {
|
||||||
|
auto rbuf = static_cast<char*>(buf);
|
||||||
|
for (size_t i = 0; i < nbytes; i++) {
|
||||||
|
rbuf[i] = std::rand() & 0xFF;
|
||||||
|
}
|
||||||
|
return nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int URandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 URandomDevice::fsync() {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int URandomDevice::ftruncate(s64 length) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int URandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 URandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||||
|
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
33
src/core/devices/urandom_device.h
Normal file
33
src/core/devices/urandom_device.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "base_device.h"
|
||||||
|
|
||||||
|
namespace Core::Devices {
|
||||||
|
|
||||||
|
class URandomDevice final : BaseDevice {
|
||||||
|
u32 handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||||
|
explicit URandomDevice(u32 handle) : handle(handle) {}
|
||||||
|
|
||||||
|
~URandomDevice() override = default;
|
||||||
|
|
||||||
|
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||||
|
s64 write(const void* buf, size_t nbytes) override;
|
||||||
|
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||||
|
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||||
|
s64 lseek(s64 offset, int whence) override;
|
||||||
|
s64 read(void* buf, size_t nbytes) override;
|
||||||
|
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||||
|
s32 fsync() override;
|
||||||
|
int ftruncate(s64 length) override;
|
||||||
|
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||||
|
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devices
|
@ -93,6 +93,12 @@ void L::DrawMenuBar() {
|
|||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SameLine(ImGui::GetWindowWidth() - 30.0f);
|
||||||
|
if (Button("X", ImVec2(25, 25))) {
|
||||||
|
DebugState.IsShowingDebugMenuBar() = false;
|
||||||
|
}
|
||||||
|
|
||||||
EndMainMenuBar();
|
EndMainMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,16 +24,33 @@ using namespace ImGui;
|
|||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
ShaderList::Selection::Selection(int index) : index(index) {
|
ShaderList::Selection::Selection(int index)
|
||||||
isa_editor.SetPalette(TextEditor::GetDarkPalette());
|
: index(index), isa_editor(std::make_unique<TextEditor>()),
|
||||||
isa_editor.SetReadOnly(true);
|
glsl_editor(std::make_unique<TextEditor>()) {
|
||||||
glsl_editor.SetPalette(TextEditor::GetDarkPalette());
|
isa_editor->SetPalette(TextEditor::GetDarkPalette());
|
||||||
glsl_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::GLSL());
|
isa_editor->SetReadOnly(true);
|
||||||
|
glsl_editor->SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
glsl_editor->SetLanguageDefinition(TextEditor::LanguageDefinition::GLSL());
|
||||||
presenter->GetWindow().RequestKeyboard();
|
presenter->GetWindow().RequestKeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderList::Selection::~Selection() {
|
ShaderList::Selection::~Selection() {
|
||||||
presenter->GetWindow().ReleaseKeyboard();
|
if (index >= 0) {
|
||||||
|
presenter->GetWindow().ReleaseKeyboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderList::Selection::Selection(Selection&& other) noexcept
|
||||||
|
: index{other.index}, isa_editor{std::move(other.isa_editor)},
|
||||||
|
glsl_editor{std::move(other.glsl_editor)}, open{other.open}, showing_bin{other.showing_bin},
|
||||||
|
patch_path{std::move(other.patch_path)}, patch_bin_path{std::move(other.patch_bin_path)} {
|
||||||
|
other.index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderList::Selection& ShaderList::Selection::operator=(Selection other) {
|
||||||
|
using std::swap;
|
||||||
|
swap(*this, other);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderList::Selection::ReloadShader(DebugStateType::ShaderDump& value) {
|
void ShaderList::Selection::ReloadShader(DebugStateType::ShaderDump& value) {
|
||||||
@ -72,13 +89,13 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
|
|||||||
|
|
||||||
value.is_patched = !value.patch_spv.empty();
|
value.is_patched = !value.patch_spv.empty();
|
||||||
if (!value.is_patched) { // No patch
|
if (!value.is_patched) { // No patch
|
||||||
isa_editor.SetText(value.cache_isa_disasm);
|
isa_editor->SetText(value.cache_isa_disasm);
|
||||||
glsl_editor.SetText(value.cache_spv_disasm);
|
glsl_editor->SetText(value.cache_spv_disasm);
|
||||||
} else {
|
} else {
|
||||||
isa_editor.SetText(value.cache_patch_disasm);
|
isa_editor->SetText(value.cache_patch_disasm);
|
||||||
isa_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::SPIRV());
|
isa_editor->SetLanguageDefinition(TextEditor::LanguageDefinition::SPIRV());
|
||||||
glsl_editor.SetText(value.patch_source);
|
glsl_editor->SetText(value.patch_source);
|
||||||
glsl_editor.SetReadOnly(false);
|
glsl_editor->SetReadOnly(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,18 +114,18 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
|
|||||||
if (value.patch_source.empty()) {
|
if (value.patch_source.empty()) {
|
||||||
value.patch_source = value.cache_spv_disasm;
|
value.patch_source = value.cache_spv_disasm;
|
||||||
}
|
}
|
||||||
isa_editor.SetText(value.cache_patch_disasm);
|
isa_editor->SetText(value.cache_patch_disasm);
|
||||||
isa_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::SPIRV());
|
isa_editor->SetLanguageDefinition(TextEditor::LanguageDefinition::SPIRV());
|
||||||
glsl_editor.SetText(value.patch_source);
|
glsl_editor->SetText(value.patch_source);
|
||||||
glsl_editor.SetReadOnly(false);
|
glsl_editor->SetReadOnly(false);
|
||||||
if (!value.patch_spv.empty()) {
|
if (!value.patch_spv.empty()) {
|
||||||
ReloadShader(value);
|
ReloadShader(value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
isa_editor.SetText(value.cache_isa_disasm);
|
isa_editor->SetText(value.cache_isa_disasm);
|
||||||
isa_editor.SetLanguageDefinition(TextEditor::LanguageDefinition());
|
isa_editor->SetLanguageDefinition(TextEditor::LanguageDefinition());
|
||||||
glsl_editor.SetText(value.cache_spv_disasm);
|
glsl_editor->SetText(value.cache_spv_disasm);
|
||||||
glsl_editor.SetReadOnly(true);
|
glsl_editor->SetReadOnly(true);
|
||||||
ReloadShader(value);
|
ReloadShader(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,7 +171,7 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
|
|||||||
compile = true;
|
compile = true;
|
||||||
}
|
}
|
||||||
if (save) {
|
if (save) {
|
||||||
value.patch_source = glsl_editor.GetText();
|
value.patch_source = glsl_editor->GetText();
|
||||||
std::ofstream file{patch_path, std::ios::binary | std::ios::trunc};
|
std::ofstream file{patch_path, std::ios::binary | std::ios::trunc};
|
||||||
file << value.patch_source;
|
file << value.patch_source;
|
||||||
std::string msg = "Patch saved to ";
|
std::string msg = "Patch saved to ";
|
||||||
@ -192,7 +209,7 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
|
|||||||
DebugState.ShowDebugMessage("Decompilation failed (Compile was ok):\n" +
|
DebugState.ShowDebugMessage("Decompilation failed (Compile was ok):\n" +
|
||||||
res);
|
res);
|
||||||
} else {
|
} else {
|
||||||
isa_editor.SetText(value.cache_patch_disasm);
|
isa_editor->SetText(value.cache_patch_disasm);
|
||||||
ReloadShader(value);
|
ReloadShader(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,9 +218,9 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (showing_bin) {
|
if (showing_bin) {
|
||||||
isa_editor.Render(value.is_patched ? "SPIRV" : "ISA", GetContentRegionAvail());
|
isa_editor->Render(value.is_patched ? "SPIRV" : "ISA", GetContentRegionAvail());
|
||||||
} else {
|
} else {
|
||||||
glsl_editor.Render("GLSL", GetContentRegionAvail());
|
glsl_editor->Render("GLSL", GetContentRegionAvail());
|
||||||
}
|
}
|
||||||
|
|
||||||
End();
|
End();
|
||||||
|
@ -14,14 +14,17 @@ class ShaderList {
|
|||||||
struct Selection {
|
struct Selection {
|
||||||
explicit Selection(int index);
|
explicit Selection(int index);
|
||||||
~Selection();
|
~Selection();
|
||||||
|
Selection(const Selection& other) = delete;
|
||||||
|
Selection(Selection&& other) noexcept;
|
||||||
|
Selection& operator=(Selection other);
|
||||||
|
|
||||||
void ReloadShader(DebugStateType::ShaderDump& value);
|
void ReloadShader(DebugStateType::ShaderDump& value);
|
||||||
|
|
||||||
bool DrawShader(DebugStateType::ShaderDump& value);
|
bool DrawShader(DebugStateType::ShaderDump& value);
|
||||||
|
|
||||||
int index;
|
int index{-1};
|
||||||
TextEditor isa_editor{};
|
std::unique_ptr<TextEditor> isa_editor{};
|
||||||
TextEditor glsl_editor{};
|
std::unique_ptr<TextEditor> glsl_editor{};
|
||||||
bool open = true;
|
bool open = true;
|
||||||
bool showing_bin = false;
|
bool showing_bin = false;
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ void HandleTable::CreateStdHandles() {
|
|||||||
std::shared_ptr<Devices::BaseDevice>{reinterpret_cast<Devices::BaseDevice*>(device)};
|
std::shared_ptr<Devices::BaseDevice>{reinterpret_cast<Devices::BaseDevice*>(device)};
|
||||||
};
|
};
|
||||||
// order matters
|
// order matters
|
||||||
setup("/dev/stdin", new Devices::NopDevice(0)); // stdin
|
setup("/dev/stdin", new Devices::Logger("stdin", false)); // stdin
|
||||||
setup("/dev/stdout", new Devices::Logger("stdout", false)); // stdout
|
setup("/dev/stdout", new Devices::Logger("stdout", false)); // stdout
|
||||||
setup("/dev/stderr", new Devices::Logger("stderr", true)); // stderr
|
setup("/dev/stderr", new Devices::Logger("stderr", true)); // stderr
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/app_content/app_content_error.h"
|
#include "core/libraries/app_content/app_content_error.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/libraries/system/systemservice.h"
|
||||||
|
|
||||||
namespace Libraries::AppContent {
|
namespace Libraries::AppContent {
|
||||||
|
|
||||||
@ -262,6 +263,15 @@ int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initPar
|
|||||||
entitlement_label.copy(info.entitlement_label, sizeof(info.entitlement_label));
|
entitlement_label.copy(info.entitlement_label, sizeof(info.entitlement_label));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addcont_count > 0) {
|
||||||
|
SystemService::OrbisSystemServiceEvent event{};
|
||||||
|
event.event_type = SystemService::OrbisSystemServiceEventType::EntitlementUpdate;
|
||||||
|
event.service_entitlement_update.user_id = 0;
|
||||||
|
event.service_entitlement_update.np_service_label = 0;
|
||||||
|
SystemService::PushSystemServiceEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,9 @@ extern "C" void PS4_SYSV_ABI _sceFiberForceQuit(u64 ret) {
|
|||||||
|
|
||||||
void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
|
void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
|
||||||
u64* stack_base = reinterpret_cast<u64*>(ctx->current_fiber->addr_context);
|
u64* stack_base = reinterpret_cast<u64*>(ctx->current_fiber->addr_context);
|
||||||
|
u64 stack_size = ctx->current_fiber->size_context;
|
||||||
if (stack_base && *stack_base != kFiberStackSignature) {
|
if (stack_base && *stack_base != kFiberStackSignature) {
|
||||||
UNREACHABLE_MSG("Stack overflow detected in fiber.");
|
UNREACHABLE_MSG("Stack overflow detected in fiber with size = 0x{:x}", stack_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1366,7 +1366,7 @@ s32 PS4_SYSV_ABI sceGnmSetEmbeddedPsShader(u32* cmdbuf, u32 size, u32 shader_id,
|
|||||||
// pointer to a stack memory, so the check will likely fail. To workaround it we will
|
// pointer to a stack memory, so the check will likely fail. To workaround it we will
|
||||||
// repeat set shader functionality here as it is trivial.
|
// repeat set shader functionality here as it is trivial.
|
||||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 8u, ps_regs[0],
|
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 8u, ps_regs[0],
|
||||||
0u); // SPI_SHADER_PGM_LO_PS/SPI_SHADER_PGM_HI_PS
|
ps_regs[1]); // SPI_SHADER_PGM_LO_PS/SPI_SHADER_PGM_HI_PS
|
||||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 10u, ps_regs[2],
|
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 10u, ps_regs[2],
|
||||||
ps_regs[3]); // SPI_SHADER_PGM_RSRC1_PS/SPI_SHADER_PGM_RSRC2_PS
|
ps_regs[3]); // SPI_SHADER_PGM_RSRC1_PS/SPI_SHADER_PGM_RSRC2_PS
|
||||||
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x1c4u, ps_regs[4],
|
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x1c4u, ps_regs[4],
|
||||||
|
@ -8,8 +8,13 @@
|
|||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
|
#include "core/devices/console_device.h"
|
||||||
|
#include "core/devices/deci_tty6_device.h"
|
||||||
#include "core/devices/logger.h"
|
#include "core/devices/logger.h"
|
||||||
#include "core/devices/nop_device.h"
|
#include "core/devices/nop_device.h"
|
||||||
|
#include "core/devices/random_device.h"
|
||||||
|
#include "core/devices/srandom_device.h"
|
||||||
|
#include "core/devices/urandom_device.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/kernel/file_system.h"
|
#include "core/libraries/kernel/file_system.h"
|
||||||
#include "core/libraries/kernel/orbis_error.h"
|
#include "core/libraries/kernel/orbis_error.h"
|
||||||
@ -41,6 +46,12 @@ static std::map<std::string, FactoryDevice> available_device = {
|
|||||||
{"/dev/deci_stderr", GET_DEVICE_FD(2)},
|
{"/dev/deci_stderr", GET_DEVICE_FD(2)},
|
||||||
|
|
||||||
{"/dev/null", GET_DEVICE_FD(0)}, // fd0 (stdin) is a nop device
|
{"/dev/null", GET_DEVICE_FD(0)}, // fd0 (stdin) is a nop device
|
||||||
|
|
||||||
|
{"/dev/urandom", &D::URandomDevice::Create },
|
||||||
|
{"/dev/random", &D::RandomDevice::Create },
|
||||||
|
{"/dev/srandom", &D::SRandomDevice::Create },
|
||||||
|
{"/dev/console", &D::ConsoleDevice::Create },
|
||||||
|
{"/dev/deci_tty6",&D::DeciTty6Device::Create }
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,17 +78,6 @@ int PS4_SYSV_ABI sceKernelOpen(const char* raw_path, int flags, u16 mode) {
|
|||||||
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
||||||
|
|
||||||
std::string_view path{raw_path};
|
std::string_view path{raw_path};
|
||||||
|
|
||||||
if (path == "/dev/console") {
|
|
||||||
return 2000;
|
|
||||||
}
|
|
||||||
if (path == "/dev/deci_tty6") {
|
|
||||||
return 2001;
|
|
||||||
}
|
|
||||||
if (path == "/dev/urandom") {
|
|
||||||
return 2003;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 handle = h->CreateHandle();
|
u32 handle = h->CreateHandle();
|
||||||
auto* file = h->GetFile(handle);
|
auto* file = h->GetFile(handle);
|
||||||
|
|
||||||
@ -167,9 +167,6 @@ int PS4_SYSV_ABI sceKernelClose(int d) {
|
|||||||
if (d < 3) { // d probably hold an error code
|
if (d < 3) { // d probably hold an error code
|
||||||
return ORBIS_KERNEL_ERROR_EPERM;
|
return ORBIS_KERNEL_ERROR_EPERM;
|
||||||
}
|
}
|
||||||
if (d == 2003) { // dev/urandom case
|
|
||||||
return ORBIS_OK;
|
|
||||||
}
|
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(d);
|
auto* file = h->GetFile(d);
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
@ -273,13 +270,6 @@ size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t PS4_SYSV_ABI _writev(int fd, const SceKernelIovec* iov, int iovcn) {
|
size_t PS4_SYSV_ABI _writev(int fd, const SceKernelIovec* iov, int iovcn) {
|
||||||
if (fd == 1) {
|
|
||||||
size_t total_written = 0;
|
|
||||||
for (int i = 0; i < iovcn; i++) {
|
|
||||||
total_written += ::fwrite(iov[i].iov_base, 1, iov[i].iov_len, stdout);
|
|
||||||
}
|
|
||||||
return total_written;
|
|
||||||
}
|
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(fd);
|
auto* file = h->GetFile(fd);
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
@ -337,13 +327,6 @@ s64 PS4_SYSV_ABI posix_lseek(int d, s64 offset, int whence) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes) {
|
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes) {
|
||||||
if (d == 2003) // dev urandom case
|
|
||||||
{
|
|
||||||
auto rbuf = static_cast<char*>(buf);
|
|
||||||
for (size_t i = 0; i < nbytes; i++)
|
|
||||||
rbuf[i] = std::rand() & 0xFF;
|
|
||||||
return nbytes;
|
|
||||||
}
|
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(d);
|
auto* file = h->GetFile(d);
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
@ -757,7 +740,6 @@ s32 PS4_SYSV_ABI sceKernelRename(const char* from, const char* to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
|
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
|
||||||
std::srand(std::time(nullptr));
|
|
||||||
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
|
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
|
||||||
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open);
|
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open);
|
||||||
LIB_FUNCTION("wuCroIGjt2g", "libkernel", 1, "libkernel", 1, 1, open);
|
LIB_FUNCTION("wuCroIGjt2g", "libkernel", 1, "libkernel", 1, 1, open);
|
||||||
|
@ -60,7 +60,7 @@ static void KernelServiceThread(std::stop_token stoken) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
io_context.run();
|
io_context.run();
|
||||||
io_context.reset();
|
io_context.restart();
|
||||||
|
|
||||||
asio_requests = 0;
|
asio_requests = 0;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "core/libraries/network/ssl2.h"
|
#include "core/libraries/network/ssl2.h"
|
||||||
#include "core/libraries/np_common/np_common.h"
|
#include "core/libraries/np_common/np_common.h"
|
||||||
#include "core/libraries/np_manager/np_manager.h"
|
#include "core/libraries/np_manager/np_manager.h"
|
||||||
|
#include "core/libraries/np_party/np_party.h"
|
||||||
#include "core/libraries/np_score/np_score.h"
|
#include "core/libraries/np_score/np_score.h"
|
||||||
#include "core/libraries/np_trophy/np_trophy.h"
|
#include "core/libraries/np_trophy/np_trophy.h"
|
||||||
#include "core/libraries/np_web_api/np_web_api.h"
|
#include "core/libraries/np_web_api/np_web_api.h"
|
||||||
@ -52,6 +53,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 "core/libraries/web_browser_dialog/webbrowserdialog.h"
|
||||||
|
#include "core/libraries/zlib/zlib_sce.h"
|
||||||
#include "fiber/fiber.h"
|
#include "fiber/fiber.h"
|
||||||
#include "jpeg/jpegenc.h"
|
#include "jpeg/jpegenc.h"
|
||||||
|
|
||||||
@ -107,6 +110,9 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||||||
Libraries::Fiber::RegisterlibSceFiber(sym);
|
Libraries::Fiber::RegisterlibSceFiber(sym);
|
||||||
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
|
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
|
||||||
Libraries::Mouse::RegisterlibSceMouse(sym);
|
Libraries::Mouse::RegisterlibSceMouse(sym);
|
||||||
|
Libraries::WebBrowserDialog::RegisterlibSceWebBrowserDialog(sym);
|
||||||
|
Libraries::NpParty::RegisterlibSceNpParty(sym);
|
||||||
|
Libraries::Zlib::RegisterlibSceZlib(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries
|
} // namespace Libraries
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "core/libraries/np_manager/np_manager.h"
|
#include "core/libraries/np_manager/np_manager.h"
|
||||||
|
#include "core/libraries/np_manager/np_manager_error.h"
|
||||||
#include "core/tls.h"
|
#include "core/tls.h"
|
||||||
|
|
||||||
namespace Libraries::NpManager {
|
namespace Libraries::NpManager {
|
||||||
@ -935,14 +936,22 @@ int PS4_SYSV_ABI sceNpGetAccountDateOfBirthA() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetAccountId() {
|
int PS4_SYSV_ABI sceNpGetAccountId(OrbisNpOnlineId* online_id, u64* account_id) {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_DEBUG(Lib_NpManager, "called");
|
||||||
return ORBIS_OK;
|
if (online_id == nullptr || account_id == nullptr) {
|
||||||
|
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
*account_id = 0;
|
||||||
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetAccountIdA() {
|
int PS4_SYSV_ABI sceNpGetAccountIdA(OrbisUserServiceUserId user_id, u64* account_id) {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||||
return ORBIS_OK;
|
if (account_id == nullptr) {
|
||||||
|
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
*account_id = 0;
|
||||||
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetAccountLanguage() {
|
int PS4_SYSV_ABI sceNpGetAccountLanguage() {
|
||||||
@ -972,6 +981,9 @@ 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_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||||
|
if (np_id == nullptr) {
|
||||||
|
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -980,8 +992,11 @@ int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetOnlineId(s32 user_id, OrbisNpOnlineId* online_id) {
|
int PS4_SYSV_ABI sceNpGetOnlineId(OrbisUserServiceUserId user_id, OrbisNpOnlineId* online_id) {
|
||||||
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
LOG_DEBUG(Lib_NpManager, "user_id {}", user_id);
|
||||||
|
if (online_id == nullptr) {
|
||||||
|
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,7 +1010,10 @@ int PS4_SYSV_ABI sceNpGetParentalControlInfoA() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetState(s32 userId, OrbisNpState* state) {
|
int PS4_SYSV_ABI sceNpGetState(OrbisUserServiceUserId user_id, OrbisNpState* state) {
|
||||||
|
if (state == nullptr) {
|
||||||
|
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
*state = OrbisNpState::SignedOut;
|
*state = OrbisNpState::SignedOut;
|
||||||
LOG_DEBUG(Lib_NpManager, "Signed out");
|
LOG_DEBUG(Lib_NpManager, "Signed out");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -1011,8 +1029,12 @@ int PS4_SYSV_ABI sceNpGetUserIdByOnlineId() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpHasSignedUp() {
|
int PS4_SYSV_ABI sceNpHasSignedUp(OrbisUserServiceUserId user_id, bool* has_signed_up) {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_DEBUG(Lib_NpManager, "called");
|
||||||
|
if (has_signed_up == nullptr) {
|
||||||
|
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
*has_signed_up = false;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@ class SymbolsResolver;
|
|||||||
|
|
||||||
namespace Libraries::NpManager {
|
namespace Libraries::NpManager {
|
||||||
|
|
||||||
constexpr int ORBIS_NP_ERROR_SIGNED_OUT = 0x80550006;
|
|
||||||
|
|
||||||
enum class OrbisNpState : u32 { Unknown = 0, SignedOut, SignedIn };
|
enum class OrbisNpState : u32 { Unknown = 0, SignedOut, SignedIn };
|
||||||
|
|
||||||
using OrbisNpStateCallbackForNpToolkit = PS4_SYSV_ABI void (*)(s32 userId, OrbisNpState state,
|
using OrbisNpStateCallbackForNpToolkit = PS4_SYSV_ABI void (*)(s32 userId, OrbisNpState state,
|
||||||
@ -220,22 +218,22 @@ int PS4_SYSV_ABI sceNpGetAccountCountry();
|
|||||||
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirth();
|
int PS4_SYSV_ABI sceNpGetAccountDateOfBirth();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirthA();
|
int PS4_SYSV_ABI sceNpGetAccountDateOfBirthA();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountId();
|
int PS4_SYSV_ABI sceNpGetAccountId(OrbisNpOnlineId* online_id, u64* account_id);
|
||||||
int PS4_SYSV_ABI sceNpGetAccountIdA();
|
int PS4_SYSV_ABI sceNpGetAccountIdA(OrbisUserServiceUserId user_id, u64* account_id);
|
||||||
int PS4_SYSV_ABI sceNpGetAccountLanguage();
|
int PS4_SYSV_ABI sceNpGetAccountLanguage();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountLanguage2();
|
int PS4_SYSV_ABI sceNpGetAccountLanguage2();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountLanguageA();
|
int PS4_SYSV_ABI sceNpGetAccountLanguageA();
|
||||||
int PS4_SYSV_ABI sceNpGetGamePresenceStatus();
|
int PS4_SYSV_ABI sceNpGetGamePresenceStatus();
|
||||||
int PS4_SYSV_ABI sceNpGetGamePresenceStatusA();
|
int PS4_SYSV_ABI sceNpGetGamePresenceStatusA();
|
||||||
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId userId, OrbisNpId* npId);
|
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id);
|
||||||
int PS4_SYSV_ABI sceNpGetNpReachabilityState();
|
int PS4_SYSV_ABI sceNpGetNpReachabilityState();
|
||||||
int PS4_SYSV_ABI sceNpGetOnlineId(s32 userId, OrbisNpOnlineId* onlineId);
|
int PS4_SYSV_ABI sceNpGetOnlineId(OrbisUserServiceUserId user_id, OrbisNpOnlineId* online_id);
|
||||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo();
|
int PS4_SYSV_ABI sceNpGetParentalControlInfo();
|
||||||
int PS4_SYSV_ABI sceNpGetParentalControlInfoA();
|
int PS4_SYSV_ABI sceNpGetParentalControlInfoA();
|
||||||
int PS4_SYSV_ABI sceNpGetState(s32 userId, OrbisNpState* state);
|
int PS4_SYSV_ABI sceNpGetState(OrbisUserServiceUserId user_id, OrbisNpState* state);
|
||||||
int PS4_SYSV_ABI sceNpGetUserIdByAccountId();
|
int PS4_SYSV_ABI sceNpGetUserIdByAccountId();
|
||||||
int PS4_SYSV_ABI sceNpGetUserIdByOnlineId();
|
int PS4_SYSV_ABI sceNpGetUserIdByOnlineId();
|
||||||
int PS4_SYSV_ABI sceNpHasSignedUp();
|
int PS4_SYSV_ABI sceNpHasSignedUp(OrbisUserServiceUserId user_id, bool* has_signed_up);
|
||||||
int PS4_SYSV_ABI sceNpIdMapperAbortRequest();
|
int PS4_SYSV_ABI sceNpIdMapperAbortRequest();
|
||||||
int PS4_SYSV_ABI sceNpIdMapperAccountIdToNpId();
|
int PS4_SYSV_ABI sceNpIdMapperAccountIdToNpId();
|
||||||
int PS4_SYSV_ABI sceNpIdMapperAccountIdToOnlineId();
|
int PS4_SYSV_ABI sceNpIdMapperAccountIdToOnlineId();
|
||||||
|
9
src/core/libraries/np_manager/np_manager_error.h
Normal file
9
src/core/libraries/np_manager/np_manager_error.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
|
||||||
|
constexpr int ORBIS_NP_ERROR_INVALID_ARGUMENT = 0x80550003;
|
||||||
|
constexpr int ORBIS_NP_ERROR_SIGNED_OUT = 0x80550006;
|
195
src/core/libraries/np_party/np_party.cpp
Normal file
195
src/core/libraries/np_party/np_party.cpp
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
// 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 "core/libraries/np_party/np_party.h"
|
||||||
|
|
||||||
|
namespace Libraries::NpParty {
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyCheckCallback() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyCreate() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyCreateA() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetId() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfo() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfoA() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMembers() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMembersA() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberSessionInfo() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberVoiceInfo() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetState() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUser() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUserA() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetVoiceChatPriority() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyInitialize() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyJoin() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyLeave() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyRegisterHandler() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyRegisterHandlerA() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyRegisterPrivateHandler() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartySendBinaryMessage() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartySetVoiceChatPriority() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyShowInvitationList() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyShowInvitationListA() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyTerminate() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyUnregisterPrivateHandler() {
|
||||||
|
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceNpParty(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("3e4k2mzLkmc", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCheckCallback);
|
||||||
|
LIB_FUNCTION("nOZRy-slBoA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCreate);
|
||||||
|
LIB_FUNCTION("XQSUbbnpPBA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCreateA);
|
||||||
|
LIB_FUNCTION("DRA3ay-1DFQ", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetId);
|
||||||
|
LIB_FUNCTION("F1P+-wpxQow", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMemberInfo);
|
||||||
|
LIB_FUNCTION("v2RYVGrJDkM", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetMemberInfoA);
|
||||||
|
LIB_FUNCTION("T2UOKf00ZN0", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMembers);
|
||||||
|
LIB_FUNCTION("TaNw7W25QJw", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMembersA);
|
||||||
|
LIB_FUNCTION("4gOMfNYzllw", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetMemberSessionInfo);
|
||||||
|
LIB_FUNCTION("EKi1jx59SP4", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetMemberVoiceInfo);
|
||||||
|
LIB_FUNCTION("aEzKdJzATZ0", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetState);
|
||||||
|
LIB_FUNCTION("o7grRhiGHYI", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetStateAsUser);
|
||||||
|
LIB_FUNCTION("EjyAI+QNgFw", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetStateAsUserA);
|
||||||
|
LIB_FUNCTION("-lc6XZnQXvM", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetVoiceChatPriority);
|
||||||
|
LIB_FUNCTION("lhYCTQmBkds", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyInitialize);
|
||||||
|
LIB_FUNCTION("RXNCDw2GDEg", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyJoin);
|
||||||
|
LIB_FUNCTION("J8jAi-tfJHc", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyLeave);
|
||||||
|
LIB_FUNCTION("kA88gbv71ao", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyRegisterHandler);
|
||||||
|
LIB_FUNCTION("+v4fVHMwFWc", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyRegisterHandlerA);
|
||||||
|
LIB_FUNCTION("zo4G5WWYpKg", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyRegisterPrivateHandler);
|
||||||
|
LIB_FUNCTION("U6VdUe-PNAY", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartySendBinaryMessage);
|
||||||
|
LIB_FUNCTION("nazKyHygHhY", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartySetVoiceChatPriority);
|
||||||
|
LIB_FUNCTION("-MFiL7hEnPE", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyShowInvitationList);
|
||||||
|
LIB_FUNCTION("yARHEYLajs0", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyShowInvitationListA);
|
||||||
|
LIB_FUNCTION("oLYkibiHqRA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyTerminate);
|
||||||
|
LIB_FUNCTION("zQ7gIvt11Pc", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyUnregisterPrivateHandler);
|
||||||
|
LIB_FUNCTION("nOZRy-slBoA", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1, sceNpPartyCreate);
|
||||||
|
LIB_FUNCTION("F1P+-wpxQow", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetMemberInfo);
|
||||||
|
LIB_FUNCTION("T2UOKf00ZN0", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetMembers);
|
||||||
|
LIB_FUNCTION("o7grRhiGHYI", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyGetStateAsUser);
|
||||||
|
LIB_FUNCTION("kA88gbv71ao", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyRegisterHandler);
|
||||||
|
LIB_FUNCTION("-MFiL7hEnPE", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||||
|
sceNpPartyShowInvitationList);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::NpParty
|
44
src/core/libraries/np_party/np_party.h
Normal file
44
src/core/libraries/np_party/np_party.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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::NpParty {
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyCheckCallback();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyCreate();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyCreateA();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetId();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfo();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfoA();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMembers();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMembersA();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberSessionInfo();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetMemberVoiceInfo();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetState();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUser();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUserA();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyGetVoiceChatPriority();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyInitialize();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyJoin();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyLeave();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyRegisterHandler();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyRegisterHandlerA();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyRegisterPrivateHandler();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartySendBinaryMessage();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartySetVoiceChatPriority();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyShowInvitationList();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyShowInvitationListA();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyTerminate();
|
||||||
|
s32 PS4_SYSV_ABI sceNpPartyUnregisterPrivateHandler();
|
||||||
|
s32 PS4_SYSV_ABI module_start();
|
||||||
|
s32 PS4_SYSV_ABI module_stop();
|
||||||
|
|
||||||
|
void RegisterlibSceNpParty(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::NpParty
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace Libraries::Pad {
|
namespace Libraries::Pad {
|
||||||
|
|
||||||
|
using Input::GameController;
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadClose(s32 handle) {
|
int PS4_SYSV_ABI scePadClose(s32 handle) {
|
||||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -93,8 +95,8 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn
|
|||||||
pInfo->touchPadInfo.pixelDensity = 1;
|
pInfo->touchPadInfo.pixelDensity = 1;
|
||||||
pInfo->touchPadInfo.resolution.x = 1920;
|
pInfo->touchPadInfo.resolution.x = 1920;
|
||||||
pInfo->touchPadInfo.resolution.y = 950;
|
pInfo->touchPadInfo.resolution.y = 950;
|
||||||
pInfo->stickInfo.deadZoneLeft = 2;
|
pInfo->stickInfo.deadZoneLeft = Config::leftDeadZone();
|
||||||
pInfo->stickInfo.deadZoneRight = 2;
|
pInfo->stickInfo.deadZoneRight = Config::rightDeadZone();
|
||||||
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
|
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
|
||||||
pInfo->connectedCount = 1;
|
pInfo->connectedCount = 1;
|
||||||
pInfo->connected = false;
|
pInfo->connected = false;
|
||||||
@ -104,8 +106,8 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn
|
|||||||
pInfo->touchPadInfo.pixelDensity = 1;
|
pInfo->touchPadInfo.pixelDensity = 1;
|
||||||
pInfo->touchPadInfo.resolution.x = 1920;
|
pInfo->touchPadInfo.resolution.x = 1920;
|
||||||
pInfo->touchPadInfo.resolution.y = 950;
|
pInfo->touchPadInfo.resolution.y = 950;
|
||||||
pInfo->stickInfo.deadZoneLeft = 2;
|
pInfo->stickInfo.deadZoneLeft = Config::leftDeadZone();
|
||||||
pInfo->stickInfo.deadZoneRight = 2;
|
pInfo->stickInfo.deadZoneRight = Config::rightDeadZone();
|
||||||
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
|
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
|
||||||
pInfo->connectedCount = 1;
|
pInfo->connectedCount = 1;
|
||||||
pInfo->connected = true;
|
pInfo->connected = true;
|
||||||
@ -290,7 +292,8 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||||||
int connected_count = 0;
|
int connected_count = 0;
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
Input::State states[64];
|
Input::State states[64];
|
||||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
auto* controller = Common::Singleton<GameController>::Instance();
|
||||||
|
const auto* engine = controller->GetEngine();
|
||||||
int ret_num = controller->ReadStates(states, num, &connected, &connected_count);
|
int ret_num = controller->ReadStates(states, num, &connected, &connected_count);
|
||||||
|
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
@ -311,9 +314,14 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||||||
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||||
Input::GameController::CalculateOrientation(pData[i].acceleration, pData[i].angularVelocity,
|
if (engine) {
|
||||||
1.0f / controller->accel_poll_rate,
|
const auto accel_poll_rate = engine->GetAccelPollRate();
|
||||||
pData[i].orientation);
|
if (accel_poll_rate != 0.0f) {
|
||||||
|
GameController::CalculateOrientation(pData[i].acceleration,
|
||||||
|
pData[i].angularVelocity,
|
||||||
|
1.0f / accel_poll_rate, pData[i].orientation);
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
@ -356,7 +364,8 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
auto* controller = Common::Singleton<GameController>::Instance();
|
||||||
|
const auto* engine = controller->GetEngine();
|
||||||
int connectedCount = 0;
|
int connectedCount = 0;
|
||||||
bool isConnected = false;
|
bool isConnected = false;
|
||||||
Input::State state;
|
Input::State state;
|
||||||
@ -374,9 +383,13 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||||||
pData->angularVelocity.x = state.angularVelocity.x;
|
pData->angularVelocity.x = state.angularVelocity.x;
|
||||||
pData->angularVelocity.y = state.angularVelocity.y;
|
pData->angularVelocity.y = state.angularVelocity.y;
|
||||||
pData->angularVelocity.z = state.angularVelocity.z;
|
pData->angularVelocity.z = state.angularVelocity.z;
|
||||||
Input::GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
if (engine) {
|
||||||
1.0f / controller->accel_poll_rate,
|
const auto accel_poll_rate = engine->GetAccelPollRate();
|
||||||
pData->orientation);
|
if (accel_poll_rate != 0.0f) {
|
||||||
|
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||||
|
1.0f / accel_poll_rate, pData->orientation);
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
@ -460,15 +473,15 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() {
|
|||||||
|
|
||||||
int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) {
|
int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) {
|
||||||
if (pParam != nullptr) {
|
if (pParam != nullptr) {
|
||||||
LOG_INFO(Lib_Pad, "scePadSetLightBar called handle = {} rgb = {} {} {}", handle, pParam->r,
|
LOG_DEBUG(Lib_Pad, "called handle = {} rgb = {} {} {}", handle, pParam->r, pParam->g,
|
||||||
pParam->g, pParam->b);
|
pParam->b);
|
||||||
|
|
||||||
if (pParam->r < 0xD && pParam->g < 0xD && pParam->b < 0xD) {
|
if (pParam->r < 0xD && pParam->g < 0xD && pParam->b < 0xD) {
|
||||||
LOG_INFO(Lib_Pad, "Invalid lightbar setting");
|
LOG_INFO(Lib_Pad, "Invalid lightbar setting");
|
||||||
return ORBIS_PAD_ERROR_INVALID_LIGHTBAR_SETTING;
|
return ORBIS_PAD_ERROR_INVALID_LIGHTBAR_SETTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
auto* controller = Common::Singleton<GameController>::Instance();
|
||||||
controller->SetLightBarRGB(pParam->r, pParam->g, pParam->b);
|
controller->SetLightBarRGB(pParam->r, pParam->g, pParam->b);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
@ -536,7 +549,7 @@ int PS4_SYSV_ABI scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pP
|
|||||||
if (pParam != nullptr) {
|
if (pParam != nullptr) {
|
||||||
LOG_DEBUG(Lib_Pad, "scePadSetVibration called handle = {} data = {} , {}", handle,
|
LOG_DEBUG(Lib_Pad, "scePadSetVibration called handle = {} data = {} , {}", handle,
|
||||||
pParam->smallMotor, pParam->largeMotor);
|
pParam->smallMotor, pParam->largeMotor);
|
||||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
auto* controller = Common::Singleton<GameController>::Instance();
|
||||||
controller->SetVibration(pParam->smallMotor, pParam->largeMotor);
|
controller->SetVibration(pParam->smallMotor, pParam->largeMotor);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -121,15 +121,17 @@ static void BackupThreadBody() {
|
|||||||
std::scoped_lock lk{g_backup_queue_mutex};
|
std::scoped_lock lk{g_backup_queue_mutex};
|
||||||
g_backup_queue.front().done = true;
|
g_backup_queue.front().done = true;
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5)); // Don't backup too often
|
|
||||||
{
|
{
|
||||||
std::scoped_lock lk{g_backup_queue_mutex};
|
std::scoped_lock lk{g_backup_queue_mutex};
|
||||||
g_backup_queue.pop_front();
|
g_backup_queue.pop_front();
|
||||||
g_result_queue.push_back(std::move(req));
|
if (req.origin != OrbisSaveDataEventType::__DO_NOT_SAVE) {
|
||||||
if (g_result_queue.size() > 20) {
|
g_result_queue.push_back(std::move(req));
|
||||||
g_result_queue.pop_front();
|
if (g_result_queue.size() > 20) {
|
||||||
|
g_result_queue.pop_front();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5)); // Don't backup too often
|
||||||
}
|
}
|
||||||
g_backup_status = WorkerStatus::NotStarted;
|
g_backup_status = WorkerStatus::NotStarted;
|
||||||
}
|
}
|
||||||
@ -141,6 +143,15 @@ void StartThread() {
|
|||||||
LOG_DEBUG(Lib_SaveData, "Starting backup thread");
|
LOG_DEBUG(Lib_SaveData, "Starting backup thread");
|
||||||
g_backup_status = WorkerStatus::Waiting;
|
g_backup_status = WorkerStatus::Waiting;
|
||||||
g_backup_thread = std::jthread{BackupThreadBody};
|
g_backup_thread = std::jthread{BackupThreadBody};
|
||||||
|
static std::once_flag flag;
|
||||||
|
std::call_once(flag, [] {
|
||||||
|
std::at_quick_exit([] {
|
||||||
|
StopThread();
|
||||||
|
while (GetWorkerStatus() != WorkerStatus::NotStarted) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopThread() {
|
void StopThread() {
|
||||||
@ -148,12 +159,12 @@ void StopThread() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(Lib_SaveData, "Stopping backup thread");
|
LOG_DEBUG(Lib_SaveData, "Stopping backup thread");
|
||||||
|
g_backup_status = WorkerStatus::Stopping;
|
||||||
{
|
{
|
||||||
std::scoped_lock lk{g_backup_queue_mutex};
|
std::scoped_lock lk{g_backup_queue_mutex};
|
||||||
g_backup_queue.emplace_back(BackupRequest{});
|
g_backup_queue.emplace_back(BackupRequest{});
|
||||||
}
|
}
|
||||||
g_backup_thread_semaphore.release();
|
g_backup_thread_semaphore.release();
|
||||||
g_backup_status = WorkerStatus::Stopping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRequest(OrbisUserServiceUserId user_id, std::string_view title_id,
|
bool NewRequest(OrbisUserServiceUserId user_id, std::string_view title_id,
|
||||||
|
@ -25,6 +25,8 @@ enum class OrbisSaveDataEventType : u32 {
|
|||||||
UMOUNT_BACKUP = 1,
|
UMOUNT_BACKUP = 1,
|
||||||
BACKUP = 2,
|
BACKUP = 2,
|
||||||
SAVE_DATA_MEMORY_SYNC = 3,
|
SAVE_DATA_MEMORY_SYNC = 3,
|
||||||
|
|
||||||
|
__DO_NOT_SAVE = 1000000, // This value is only for the backup thread
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BackupRequest {
|
struct BackupRequest {
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
|
#include "save_backup.h"
|
||||||
#include "save_instance.h"
|
#include "save_instance.h"
|
||||||
|
|
||||||
constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
|
constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
|
||||||
@ -45,17 +46,14 @@ static const std::unordered_map<std::string, std::string> default_title = {
|
|||||||
|
|
||||||
namespace Libraries::SaveData {
|
namespace Libraries::SaveData {
|
||||||
|
|
||||||
std::filesystem::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
|
fs::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
|
||||||
std::string_view game_serial) {
|
std::string_view game_serial) {
|
||||||
return Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / std::to_string(user_id) /
|
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial;
|
||||||
game_serial;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_id,
|
fs::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_id, std::string_view game_serial,
|
||||||
std::string_view game_serial,
|
std::string_view dir_name) {
|
||||||
std::string_view dir_name) {
|
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial / dir_name;
|
||||||
return Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / std::to_string(user_id) /
|
|
||||||
game_serial / dir_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
|
uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
|
||||||
@ -67,7 +65,7 @@ uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
|
|||||||
return *(uint64_t*)value.data();
|
return *(uint64_t*)value.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
|
fs::path SaveInstance::GetParamSFOPath(const fs::path& dir_path) {
|
||||||
return dir_path / sce_sys / "param.sfo";
|
return dir_path / sce_sys / "param.sfo";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +129,6 @@ SaveInstance& SaveInstance::operator=(SaveInstance&& other) noexcept {
|
|||||||
save_path = std::move(other.save_path);
|
save_path = std::move(other.save_path);
|
||||||
param_sfo_path = std::move(other.param_sfo_path);
|
param_sfo_path = std::move(other.param_sfo_path);
|
||||||
corrupt_file_path = std::move(other.corrupt_file_path);
|
corrupt_file_path = std::move(other.corrupt_file_path);
|
||||||
corrupt_file = std::move(other.corrupt_file);
|
|
||||||
param_sfo = std::move(other.param_sfo);
|
param_sfo = std::move(other.param_sfo);
|
||||||
mount_point = std::move(other.mount_point);
|
mount_point = std::move(other.mount_point);
|
||||||
max_blocks = other.max_blocks;
|
max_blocks = other.max_blocks;
|
||||||
@ -144,7 +141,8 @@ SaveInstance& SaveInstance::operator=(SaveInstance&& other) noexcept {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_corrupt) {
|
void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_corrupt,
|
||||||
|
bool dont_restore_backup) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
UNREACHABLE_MSG("Save instance is already mounted");
|
UNREACHABLE_MSG("Save instance is already mounted");
|
||||||
}
|
}
|
||||||
@ -163,25 +161,27 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
|
|||||||
}
|
}
|
||||||
exists = true;
|
exists = true;
|
||||||
} else {
|
} else {
|
||||||
|
std::optional<fs::filesystem_error> err;
|
||||||
if (!ignore_corrupt && fs::exists(corrupt_file_path)) {
|
if (!ignore_corrupt && fs::exists(corrupt_file_path)) {
|
||||||
throw std::filesystem::filesystem_error(
|
err = fs::filesystem_error("Corrupted save data", corrupt_file_path,
|
||||||
"Corrupted save data", corrupt_file_path,
|
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
} else if (!param_sfo.Open(param_sfo_path)) {
|
||||||
|
err = fs::filesystem_error("Failed to read param.sfo", param_sfo_path,
|
||||||
|
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||||
}
|
}
|
||||||
if (!param_sfo.Open(param_sfo_path)) {
|
if (err.has_value()) {
|
||||||
throw std::filesystem::filesystem_error(
|
if (dont_restore_backup) {
|
||||||
"Failed to read param.sfo", param_sfo_path,
|
throw err.value();
|
||||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
}
|
||||||
|
if (Backup::Restore(save_path)) {
|
||||||
|
return SetupAndMount(read_only, copy_icon, ignore_corrupt, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignore_corrupt && !read_only) {
|
if (!ignore_corrupt && !read_only) {
|
||||||
int err = corrupt_file.Open(corrupt_file_path, Common::FS::FileAccessMode::Write);
|
Common::FS::IOFile f(corrupt_file_path, Common::FS::FileAccessMode::Write);
|
||||||
if (err != 0) {
|
f.Close();
|
||||||
throw std::filesystem::filesystem_error(
|
|
||||||
"Failed to open corrupted file", corrupt_file_path,
|
|
||||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
|
max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
|
||||||
@ -199,12 +199,11 @@ void SaveInstance::Umount() {
|
|||||||
mounted = false;
|
mounted = false;
|
||||||
const bool ok = param_sfo.Encode(param_sfo_path);
|
const bool ok = param_sfo.Encode(param_sfo_path);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
throw fs::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||||
std::make_error_code(std::errc::permission_denied));
|
std::make_error_code(std::errc::permission_denied));
|
||||||
}
|
}
|
||||||
param_sfo = PSF();
|
param_sfo = PSF();
|
||||||
|
|
||||||
corrupt_file.Close();
|
|
||||||
fs::remove(corrupt_file_path);
|
fs::remove(corrupt_file_path);
|
||||||
g_mnt->Unmount(save_path, mount_point);
|
g_mnt->Unmount(save_path, mount_point);
|
||||||
}
|
}
|
||||||
@ -218,8 +217,8 @@ void SaveInstance::CreateFiles() {
|
|||||||
|
|
||||||
const bool ok = param_sfo.Encode(param_sfo_path);
|
const bool ok = param_sfo.Encode(param_sfo_path);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
throw fs::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||||
std::make_error_code(std::errc::permission_denied));
|
std::make_error_code(std::errc::permission_denied));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,6 @@ class SaveInstance {
|
|||||||
std::filesystem::path param_sfo_path;
|
std::filesystem::path param_sfo_path;
|
||||||
std::filesystem::path corrupt_file_path;
|
std::filesystem::path corrupt_file_path;
|
||||||
|
|
||||||
Common::FS::IOFile corrupt_file;
|
|
||||||
|
|
||||||
PSF param_sfo;
|
PSF param_sfo;
|
||||||
std::string mount_point;
|
std::string mount_point;
|
||||||
|
|
||||||
@ -80,7 +78,8 @@ public:
|
|||||||
SaveInstance& operator=(const SaveInstance& other) = delete;
|
SaveInstance& operator=(const SaveInstance& other) = delete;
|
||||||
SaveInstance& operator=(SaveInstance&& other) noexcept;
|
SaveInstance& operator=(SaveInstance&& other) noexcept;
|
||||||
|
|
||||||
void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false);
|
void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false,
|
||||||
|
bool dont_restore_backup = false);
|
||||||
|
|
||||||
void Umount();
|
void Umount();
|
||||||
|
|
||||||
|
@ -6,14 +6,16 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <core/libraries/system/msgdialog_ui.h>
|
#include <core/libraries/system/msgdialog_ui.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/elf_info.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/polyfill_thread.h"
|
#include "common/path_util.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
@ -23,265 +25,202 @@ using Common::FS::IOFile;
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
constexpr std::string_view sce_sys = "sce_sys"; // system folder inside save
|
constexpr std::string_view sce_sys = "sce_sys"; // system folder inside save
|
||||||
constexpr std::string_view DirnameSaveDataMemory = "sce_sdmemory";
|
constexpr std::string_view StandardDirnameSaveDataMemory = "sce_sdmemory";
|
||||||
constexpr std::string_view FilenameSaveDataMemory = "memory.dat";
|
constexpr std::string_view FilenameSaveDataMemory = "memory.dat";
|
||||||
|
constexpr std::string_view IconName = "icon0.png";
|
||||||
|
constexpr std::string_view CorruptFileName = "corrupted";
|
||||||
|
|
||||||
namespace Libraries::SaveData::SaveMemory {
|
namespace Libraries::SaveData::SaveMemory {
|
||||||
|
|
||||||
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
|
||||||
static OrbisUserServiceUserId g_user_id{};
|
struct SlotData {
|
||||||
static std::string g_game_serial{};
|
OrbisUserServiceUserId user_id;
|
||||||
static std::filesystem::path g_save_path{};
|
std::string game_serial;
|
||||||
static std::filesystem::path g_param_sfo_path{};
|
std::filesystem::path folder_path;
|
||||||
static PSF g_param_sfo;
|
PSF sfo;
|
||||||
|
std::vector<u8> memory_cache;
|
||||||
|
};
|
||||||
|
|
||||||
static bool g_save_memory_initialized = false;
|
static std::mutex g_slot_mtx;
|
||||||
static std::mutex g_saving_memory_mutex;
|
static std::unordered_map<u32, SlotData> g_attached_slots;
|
||||||
static std::vector<u8> g_save_memory;
|
|
||||||
|
|
||||||
static std::filesystem::path g_icon_path;
|
void PersistMemory(u32 slot_id, bool lock) {
|
||||||
static std::vector<u8> g_icon_memory;
|
std::unique_lock lck{g_slot_mtx, std::defer_lock};
|
||||||
|
if (lock) {
|
||||||
|
lck.lock();
|
||||||
|
}
|
||||||
|
auto& data = g_attached_slots[slot_id];
|
||||||
|
auto memoryPath = data.folder_path / FilenameSaveDataMemory;
|
||||||
|
fs::create_directories(memoryPath.parent_path());
|
||||||
|
|
||||||
static std::condition_variable g_trigger_save_memory;
|
int n = 0;
|
||||||
static std::atomic_bool g_saving_memory = false;
|
std::string errMsg;
|
||||||
static std::atomic_bool g_save_event = false;
|
while (n++ < 10) {
|
||||||
static std::jthread g_save_memory_thread;
|
|
||||||
|
|
||||||
static std::atomic_bool g_memory_dirty = false;
|
|
||||||
static std::atomic_bool g_param_dirty = false;
|
|
||||||
static std::atomic_bool g_icon_dirty = false;
|
|
||||||
|
|
||||||
static void SaveFileSafe(void* buf, size_t count, const std::filesystem::path& path) {
|
|
||||||
const auto& dir = path.parent_path();
|
|
||||||
const auto& name = path.filename();
|
|
||||||
const auto tmp_path = dir / (name.string() + ".tmp");
|
|
||||||
|
|
||||||
IOFile file(tmp_path, Common::FS::FileAccessMode::Write);
|
|
||||||
file.WriteRaw<u8>(buf, count);
|
|
||||||
file.Close();
|
|
||||||
|
|
||||||
fs::remove(path);
|
|
||||||
fs::rename(tmp_path, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void SaveThreadLoop() {
|
|
||||||
Common::SetCurrentThreadName("shadPS4:SaveData:SaveDataMemoryThread");
|
|
||||||
std::mutex mtx;
|
|
||||||
while (true) {
|
|
||||||
{
|
|
||||||
std::unique_lock lk{mtx};
|
|
||||||
g_trigger_save_memory.wait(lk);
|
|
||||||
}
|
|
||||||
// Save the memory
|
|
||||||
g_saving_memory = true;
|
|
||||||
std::scoped_lock lk{g_saving_memory_mutex};
|
|
||||||
try {
|
try {
|
||||||
LOG_DEBUG(Lib_SaveData, "Saving save data memory {}", fmt::UTF(g_save_path.u8string()));
|
IOFile f;
|
||||||
|
int r = f.Open(memoryPath, Common::FS::FileAccessMode::Write);
|
||||||
if (g_memory_dirty) {
|
if (f.IsOpen()) {
|
||||||
g_memory_dirty = false;
|
f.WriteRaw<u8>(data.memory_cache.data(), data.memory_cache.size());
|
||||||
SaveFileSafe(g_save_memory.data(), g_save_memory.size(),
|
f.Close();
|
||||||
g_save_path / FilenameSaveDataMemory);
|
return;
|
||||||
}
|
}
|
||||||
if (g_param_dirty) {
|
const auto err = std::error_code{r, std::iostream_category()};
|
||||||
g_param_dirty = false;
|
throw std::filesystem::filesystem_error{err.message(), err};
|
||||||
static std::vector<u8> buf;
|
} catch (const std::filesystem::filesystem_error& e) {
|
||||||
g_param_sfo.Encode(buf);
|
errMsg = std::string{e.what()};
|
||||||
SaveFileSafe(buf.data(), buf.size(), g_param_sfo_path);
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
}
|
|
||||||
if (g_icon_dirty) {
|
|
||||||
g_icon_dirty = false;
|
|
||||||
SaveFileSafe(g_icon_memory.data(), g_icon_memory.size(), g_icon_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_save_event) {
|
|
||||||
Backup::PushBackupEvent(Backup::BackupRequest{
|
|
||||||
.user_id = g_user_id,
|
|
||||||
.title_id = g_game_serial,
|
|
||||||
.dir_name = std::string{DirnameSaveDataMemory},
|
|
||||||
.origin = Backup::OrbisSaveDataEventType::SAVE_DATA_MEMORY_SYNC,
|
|
||||||
.save_path = g_save_path,
|
|
||||||
});
|
|
||||||
g_save_event = false;
|
|
||||||
}
|
|
||||||
} catch (const fs::filesystem_error& e) {
|
|
||||||
LOG_ERROR(Lib_SaveData, "Failed to save save data memory: {}", e.what());
|
|
||||||
MsgDialog::ShowMsgDialog(MsgDialog::MsgDialogState{
|
|
||||||
MsgDialog::MsgDialogState::UserState{
|
|
||||||
.type = MsgDialog::ButtonType::OK,
|
|
||||||
.msg = fmt::format("Failed to save save data memory.\nCode: <{}>\n{}",
|
|
||||||
e.code().message(), e.what()),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
g_saving_memory = false;
|
|
||||||
}
|
}
|
||||||
|
const MsgDialog::MsgDialogState dialog{MsgDialog::MsgDialogState::UserState{
|
||||||
|
.type = MsgDialog::ButtonType::OK,
|
||||||
|
.msg = "Failed to persist save memory:\n" + errMsg + "\nat " +
|
||||||
|
Common::FS::PathToUTF8String(memoryPath),
|
||||||
|
}};
|
||||||
|
MsgDialog::ShowMsgDialog(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDirectories(OrbisUserServiceUserId user_id, std::string _game_serial) {
|
std::string GetSaveDir(u32 slot_id) {
|
||||||
g_user_id = user_id;
|
std::string dir(StandardDirnameSaveDataMemory);
|
||||||
g_game_serial = std::move(_game_serial);
|
if (slot_id > 0) {
|
||||||
g_save_path = SaveInstance::MakeDirSavePath(user_id, g_game_serial, DirnameSaveDataMemory);
|
dir += std::to_string(slot_id);
|
||||||
g_param_sfo_path = SaveInstance::GetParamSFOPath(g_save_path);
|
}
|
||||||
g_param_sfo = PSF();
|
return dir;
|
||||||
g_icon_path = g_save_path / sce_sys / "icon0.png";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::filesystem::path& GetSavePath() {
|
std::filesystem::path GetSavePath(OrbisUserServiceUserId user_id, u32 slot_id,
|
||||||
return g_save_path;
|
std::string_view game_serial) {
|
||||||
|
std::string dir(StandardDirnameSaveDataMemory);
|
||||||
|
if (slot_id > 0) {
|
||||||
|
dir += std::to_string(slot_id);
|
||||||
|
}
|
||||||
|
return SaveInstance::MakeDirSavePath(user_id, Common::ElfInfo::Instance().GameSerial(), dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CreateSaveMemory(size_t memory_size) {
|
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial) {
|
||||||
size_t existed_size = 0;
|
std::lock_guard lck{g_slot_mtx};
|
||||||
|
|
||||||
static std::once_flag init_save_thread_flag;
|
const auto save_dir = GetSavePath(user_id, slot_id, game_serial);
|
||||||
std::call_once(init_save_thread_flag,
|
|
||||||
[] { g_save_memory_thread = std::jthread{SaveThreadLoop}; });
|
|
||||||
|
|
||||||
g_save_memory.resize(memory_size);
|
auto& data = g_attached_slots[slot_id];
|
||||||
SaveInstance::SetupDefaultParamSFO(g_param_sfo, std::string{DirnameSaveDataMemory},
|
data = SlotData{
|
||||||
g_game_serial);
|
.user_id = user_id,
|
||||||
|
.game_serial = std::string{game_serial},
|
||||||
|
.folder_path = save_dir,
|
||||||
|
.sfo = {},
|
||||||
|
.memory_cache = {},
|
||||||
|
};
|
||||||
|
|
||||||
g_save_memory_initialized = true;
|
SaveInstance::SetupDefaultParamSFO(data.sfo, GetSaveDir(slot_id), std::string{game_serial});
|
||||||
|
|
||||||
if (!fs::exists(g_param_sfo_path)) {
|
auto param_sfo_path = SaveInstance::GetParamSFOPath(save_dir);
|
||||||
// Create save memory
|
if (!fs::exists(param_sfo_path)) {
|
||||||
fs::create_directories(g_save_path / sce_sys);
|
return 0;
|
||||||
|
|
||||||
IOFile memory_file{g_save_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Write};
|
|
||||||
bool ok = memory_file.SetSize(memory_size);
|
|
||||||
if (!ok) {
|
|
||||||
LOG_ERROR(Lib_SaveData, "Failed to set memory size");
|
|
||||||
throw std::filesystem::filesystem_error(
|
|
||||||
"Failed to set save memory size", g_save_path / FilenameSaveDataMemory,
|
|
||||||
std::make_error_code(std::errc::no_space_on_device));
|
|
||||||
}
|
|
||||||
memory_file.Close();
|
|
||||||
} else {
|
|
||||||
// Load save memory
|
|
||||||
|
|
||||||
bool ok = g_param_sfo.Open(g_param_sfo_path);
|
|
||||||
if (!ok) {
|
|
||||||
LOG_ERROR(Lib_SaveData, "Failed to open SFO at {}",
|
|
||||||
fmt::UTF(g_param_sfo_path.u8string()));
|
|
||||||
throw std::filesystem::filesystem_error(
|
|
||||||
"failed to open SFO", g_param_sfo_path,
|
|
||||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
|
||||||
}
|
|
||||||
|
|
||||||
IOFile memory_file{g_save_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read};
|
|
||||||
if (!memory_file.IsOpen()) {
|
|
||||||
LOG_ERROR(Lib_SaveData, "Failed to open save memory");
|
|
||||||
throw std::filesystem::filesystem_error(
|
|
||||||
"failed to open save memory", g_save_path / FilenameSaveDataMemory,
|
|
||||||
std::make_error_code(std::errc::permission_denied));
|
|
||||||
}
|
|
||||||
size_t save_size = memory_file.GetSize();
|
|
||||||
existed_size = save_size;
|
|
||||||
memory_file.Seek(0);
|
|
||||||
memory_file.ReadRaw<u8>(g_save_memory.data(), std::min(save_size, memory_size));
|
|
||||||
memory_file.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return existed_size;
|
if (!data.sfo.Open(param_sfo_path) || fs::exists(save_dir / CorruptFileName)) {
|
||||||
|
if (!Backup::Restore(save_dir)) { // Could not restore the backup
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto memory = save_dir / FilenameSaveDataMemory;
|
||||||
|
if (fs::exists(memory)) {
|
||||||
|
return fs::file_size(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIcon(void* buf, size_t buf_size) {
|
void SetIcon(u32 slot_id, void* buf, size_t buf_size) {
|
||||||
|
std::lock_guard lck{g_slot_mtx};
|
||||||
|
const auto& data = g_attached_slots[slot_id];
|
||||||
|
const auto icon_path = data.folder_path / sce_sys / "icon0.png";
|
||||||
if (buf == nullptr) {
|
if (buf == nullptr) {
|
||||||
const auto& src_icon = g_mnt->GetHostPath("/app0/sce_sys/save_data.png");
|
const auto& src_icon = g_mnt->GetHostPath("/app0/sce_sys/save_data.png");
|
||||||
if (fs::exists(src_icon)) {
|
if (fs::exists(icon_path)) {
|
||||||
if (fs::exists(g_icon_path)) {
|
fs::remove(icon_path);
|
||||||
fs::remove(g_icon_path);
|
|
||||||
}
|
|
||||||
fs::copy_file(src_icon, g_icon_path);
|
|
||||||
}
|
}
|
||||||
if (fs::exists(g_icon_path)) {
|
if (fs::exists(src_icon)) {
|
||||||
IOFile file(g_icon_path, Common::FS::FileAccessMode::Read);
|
fs::create_directories(icon_path.parent_path());
|
||||||
size_t size = file.GetSize();
|
fs::copy_file(src_icon, icon_path);
|
||||||
file.Seek(0);
|
|
||||||
g_icon_memory.resize(size);
|
|
||||||
file.ReadRaw<u8>(g_icon_memory.data(), size);
|
|
||||||
file.Close();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_icon_memory.resize(buf_size);
|
IOFile file(icon_path, Common::FS::FileAccessMode::Write);
|
||||||
std::memcpy(g_icon_memory.data(), buf, buf_size);
|
file.WriteRaw<u8>(buf, buf_size);
|
||||||
IOFile file(g_icon_path, Common::FS::FileAccessMode::Write);
|
|
||||||
file.Seek(0);
|
|
||||||
file.WriteRaw<u8>(g_icon_memory.data(), buf_size);
|
|
||||||
file.Close();
|
file.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteIcon(void* buf, size_t buf_size) {
|
bool IsSaveMemoryInitialized(u32 slot_id) {
|
||||||
if (buf_size != g_icon_memory.size()) {
|
std::lock_guard lck{g_slot_mtx};
|
||||||
g_icon_memory.resize(buf_size);
|
return g_attached_slots.contains(slot_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
PSF& GetParamSFO(u32 slot_id) {
|
||||||
|
std::lock_guard lck{g_slot_mtx};
|
||||||
|
auto& data = g_attached_slots[slot_id];
|
||||||
|
return data.sfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> GetIcon(u32 slot_id) {
|
||||||
|
std::lock_guard lck{g_slot_mtx};
|
||||||
|
auto& data = g_attached_slots[slot_id];
|
||||||
|
const auto icon_path = data.folder_path / sce_sys / "icon0.png";
|
||||||
|
IOFile f{icon_path, Common::FS::FileAccessMode::Read};
|
||||||
|
if (!f.IsOpen()) {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
std::memcpy(g_icon_memory.data(), buf, buf_size);
|
const u64 size = f.GetSize();
|
||||||
g_icon_dirty = true;
|
std::vector<u8> ret;
|
||||||
|
ret.resize(size);
|
||||||
|
f.ReadSpan(std::span{ret});
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSaveMemoryInitialized() {
|
void SaveSFO(u32 slot_id) {
|
||||||
return g_save_memory_initialized;
|
std::lock_guard lck{g_slot_mtx};
|
||||||
}
|
const auto& data = g_attached_slots[slot_id];
|
||||||
|
const auto sfo_path = SaveInstance::GetParamSFOPath(data.folder_path);
|
||||||
PSF& GetParamSFO() {
|
fs::create_directories(sfo_path.parent_path());
|
||||||
return g_param_sfo;
|
const bool ok = data.sfo.Encode(sfo_path);
|
||||||
}
|
|
||||||
|
|
||||||
std::span<u8> GetIcon() {
|
|
||||||
return {g_icon_memory};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveSFO(bool sync) {
|
|
||||||
if (!sync) {
|
|
||||||
g_param_dirty = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const bool ok = g_param_sfo.Encode(g_param_sfo_path);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOG_ERROR(Lib_SaveData, "Failed to encode param.sfo");
|
LOG_ERROR(Lib_SaveData, "Failed to encode param.sfo");
|
||||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", g_param_sfo_path,
|
throw std::filesystem::filesystem_error("Failed to write param.sfo", sfo_path,
|
||||||
std::make_error_code(std::errc::permission_denied));
|
std::make_error_code(std::errc::permission_denied));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool IsSaving() {
|
|
||||||
return g_saving_memory;
|
void ReadMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
|
||||||
|
std::lock_guard lk{g_slot_mtx};
|
||||||
|
auto& data = g_attached_slots[slot_id];
|
||||||
|
auto& memory = data.memory_cache;
|
||||||
|
if (memory.empty()) { // Load file
|
||||||
|
IOFile f{data.folder_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read};
|
||||||
|
if (f.IsOpen()) {
|
||||||
|
memory.resize(f.GetSize());
|
||||||
|
f.Seek(0);
|
||||||
|
f.ReadSpan(std::span{memory});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s64 read_size = buf_size;
|
||||||
|
if (read_size + offset > memory.size()) {
|
||||||
|
read_size = memory.size() - offset;
|
||||||
|
}
|
||||||
|
std::memcpy(buf, memory.data() + offset, read_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TriggerSaveWithoutEvent() {
|
void WriteMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
|
||||||
if (g_saving_memory) {
|
std::lock_guard lk{g_slot_mtx};
|
||||||
return false;
|
auto& data = g_attached_slots[slot_id];
|
||||||
|
auto& memory = data.memory_cache;
|
||||||
|
if (offset + buf_size > memory.size()) {
|
||||||
|
memory.resize(offset + buf_size);
|
||||||
}
|
}
|
||||||
g_trigger_save_memory.notify_one();
|
std::memcpy(memory.data() + offset, buf, buf_size);
|
||||||
return true;
|
PersistMemory(slot_id, false);
|
||||||
}
|
Backup::NewRequest(data.user_id, data.game_serial, GetSaveDir(slot_id),
|
||||||
|
Backup::OrbisSaveDataEventType::__DO_NOT_SAVE);
|
||||||
bool TriggerSave() {
|
|
||||||
if (g_saving_memory) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
g_save_event = true;
|
|
||||||
g_trigger_save_memory.notify_one();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadMemory(void* buf, size_t buf_size, int64_t offset) {
|
|
||||||
std::scoped_lock lk{g_saving_memory_mutex};
|
|
||||||
if (offset + buf_size > g_save_memory.size()) {
|
|
||||||
UNREACHABLE_MSG("ReadMemory out of bounds");
|
|
||||||
}
|
|
||||||
std::memcpy(buf, g_save_memory.data() + offset, buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteMemory(void* buf, size_t buf_size, int64_t offset) {
|
|
||||||
std::scoped_lock lk{g_saving_memory_mutex};
|
|
||||||
if (offset + buf_size > g_save_memory.size()) {
|
|
||||||
g_save_memory.resize(offset + buf_size);
|
|
||||||
}
|
|
||||||
std::memcpy(g_save_memory.data() + offset, buf, buf_size);
|
|
||||||
g_memory_dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::SaveData::SaveMemory
|
} // namespace Libraries::SaveData::SaveMemory
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <span>
|
#include <vector>
|
||||||
#include "save_backup.h"
|
#include "save_backup.h"
|
||||||
|
|
||||||
class PSF;
|
class PSF;
|
||||||
@ -14,36 +14,30 @@ using OrbisUserServiceUserId = s32;
|
|||||||
|
|
||||||
namespace Libraries::SaveData::SaveMemory {
|
namespace Libraries::SaveData::SaveMemory {
|
||||||
|
|
||||||
void SetDirectories(OrbisUserServiceUserId user_id, std::string game_serial);
|
void PersistMemory(u32 slot_id, bool lock = true);
|
||||||
|
|
||||||
[[nodiscard]] const std::filesystem::path& GetSavePath();
|
[[nodiscard]] std::string GetSaveDir(u32 slot_id);
|
||||||
|
|
||||||
// returns the size of the existed save memory
|
[[nodiscard]] std::filesystem::path GetSavePath(OrbisUserServiceUserId user_id, u32 slot_id,
|
||||||
size_t CreateSaveMemory(size_t memory_size);
|
std::string_view game_serial);
|
||||||
|
|
||||||
// Initialize the icon. Set buf to null to read the standard icon.
|
// returns the size of the save memory if exists
|
||||||
void SetIcon(void* buf, size_t buf_size);
|
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial);
|
||||||
|
|
||||||
// Update the icon
|
// Write the icon. Set buf to null to read the standard icon.
|
||||||
void WriteIcon(void* buf, size_t buf_size);
|
void SetIcon(u32 slot_id, void* buf = nullptr, size_t buf_size = 0);
|
||||||
|
|
||||||
[[nodiscard]] bool IsSaveMemoryInitialized();
|
[[nodiscard]] bool IsSaveMemoryInitialized(u32 slot_id);
|
||||||
|
|
||||||
[[nodiscard]] PSF& GetParamSFO();
|
[[nodiscard]] PSF& GetParamSFO(u32 slot_id);
|
||||||
|
|
||||||
[[nodiscard]] std::span<u8> GetIcon();
|
[[nodiscard]] std::vector<u8> GetIcon(u32 slot_id);
|
||||||
|
|
||||||
// Save now or wait for the background thread to save
|
// Save now or wait for the background thread to save
|
||||||
void SaveSFO(bool sync = false);
|
void SaveSFO(u32 slot_id);
|
||||||
|
|
||||||
[[nodiscard]] bool IsSaving();
|
void ReadMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset);
|
||||||
|
|
||||||
bool TriggerSaveWithoutEvent();
|
void WriteMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset);
|
||||||
|
|
||||||
bool TriggerSave();
|
|
||||||
|
|
||||||
void ReadMemory(void* buf, size_t buf_size, int64_t offset);
|
|
||||||
|
|
||||||
void WriteMemory(void* buf, size_t buf_size, int64_t offset);
|
|
||||||
|
|
||||||
} // namespace Libraries::SaveData::SaveMemory
|
} // namespace Libraries::SaveData::SaveMemory
|
@ -177,7 +177,8 @@ struct OrbisSaveDataMemoryGet2 {
|
|||||||
OrbisSaveDataMemoryData* data;
|
OrbisSaveDataMemoryData* data;
|
||||||
OrbisSaveDataParam* param;
|
OrbisSaveDataParam* param;
|
||||||
OrbisSaveDataIcon* icon;
|
OrbisSaveDataIcon* icon;
|
||||||
std::array<u8, 32> _reserved;
|
u32 slotId;
|
||||||
|
std::array<u8, 28> _reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisSaveDataMemorySet2 {
|
struct OrbisSaveDataMemorySet2 {
|
||||||
@ -186,6 +187,8 @@ struct OrbisSaveDataMemorySet2 {
|
|||||||
const OrbisSaveDataMemoryData* data;
|
const OrbisSaveDataMemoryData* data;
|
||||||
const OrbisSaveDataParam* param;
|
const OrbisSaveDataParam* param;
|
||||||
const OrbisSaveDataIcon* icon;
|
const OrbisSaveDataIcon* icon;
|
||||||
|
u32 dataNum;
|
||||||
|
u32 slotId;
|
||||||
std::array<u8, 32> _reserved;
|
std::array<u8, 32> _reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -198,7 +201,8 @@ struct OrbisSaveDataMemorySetup2 {
|
|||||||
const OrbisSaveDataParam* initParam;
|
const OrbisSaveDataParam* initParam;
|
||||||
// +4.5
|
// +4.5
|
||||||
const OrbisSaveDataIcon* initIcon;
|
const OrbisSaveDataIcon* initIcon;
|
||||||
std::array<u8, 24> _reserved;
|
u32 slotId;
|
||||||
|
std::array<u8, 20> _reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisSaveDataMemorySetupResult {
|
struct OrbisSaveDataMemorySetupResult {
|
||||||
@ -206,9 +210,16 @@ struct OrbisSaveDataMemorySetupResult {
|
|||||||
std::array<u8, 16> _reserved;
|
std::array<u8, 16> _reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum OrbisSaveDataMemorySyncOption : u32 {
|
||||||
|
NONE = 0,
|
||||||
|
BLOCKING = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct OrbisSaveDataMemorySync {
|
struct OrbisSaveDataMemorySync {
|
||||||
OrbisUserServiceUserId userId;
|
OrbisUserServiceUserId userId;
|
||||||
std::array<u8, 36> _reserved;
|
u32 slotId;
|
||||||
|
OrbisSaveDataMemorySyncOption option;
|
||||||
|
std::array<u8, 28> _reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisSaveDataMount2 {
|
struct OrbisSaveDataMount2 {
|
||||||
@ -327,6 +338,7 @@ static void initialize() {
|
|||||||
g_initialized = true;
|
g_initialized = true;
|
||||||
g_game_serial = ElfInfo::Instance().GameSerial();
|
g_game_serial = ElfInfo::Instance().GameSerial();
|
||||||
g_fw_ver = ElfInfo::Instance().FirmwareVer();
|
g_fw_ver = ElfInfo::Instance().FirmwareVer();
|
||||||
|
Backup::StartThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
// game_00other | game*other
|
// game_00other | game*other
|
||||||
@ -558,7 +570,6 @@ Error PS4_SYSV_ABI sceSaveDataBackup(const OrbisSaveDataBackup* backup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Backup::StartThread();
|
|
||||||
Backup::NewRequest(backup->userId, title, dir_name, OrbisSaveDataEventType::BACKUP);
|
Backup::NewRequest(backup->userId, title, dir_name, OrbisSaveDataEventType::BACKUP);
|
||||||
|
|
||||||
return Error::OK;
|
return Error::OK;
|
||||||
@ -1136,22 +1147,27 @@ Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getPar
|
|||||||
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
||||||
return Error::PARAMETER;
|
return Error::PARAMETER;
|
||||||
}
|
}
|
||||||
if (!SaveMemory::IsSaveMemoryInitialized()) {
|
|
||||||
|
u32 slot_id = 0;
|
||||||
|
if (g_fw_ver > ElfInfo::FW_50) {
|
||||||
|
slot_id = getParam->slotId;
|
||||||
|
}
|
||||||
|
if (!SaveMemory::IsSaveMemoryInitialized(slot_id)) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(Lib_SaveData, "called");
|
LOG_DEBUG(Lib_SaveData, "called");
|
||||||
auto data = getParam->data;
|
auto data = getParam->data;
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
SaveMemory::ReadMemory(data->buf, data->bufSize, data->offset);
|
SaveMemory::ReadMemory(slot_id, data->buf, data->bufSize, data->offset);
|
||||||
}
|
}
|
||||||
auto param = getParam->param;
|
auto param = getParam->param;
|
||||||
if (param != nullptr) {
|
if (param != nullptr) {
|
||||||
param->FromSFO(SaveMemory::GetParamSFO());
|
param->FromSFO(SaveMemory::GetParamSFO(slot_id));
|
||||||
}
|
}
|
||||||
auto icon = getParam->icon;
|
auto icon = getParam->icon;
|
||||||
if (icon != nullptr) {
|
if (icon != nullptr) {
|
||||||
auto icon_mem = SaveMemory::GetIcon();
|
auto icon_mem = SaveMemory::GetIcon(slot_id);
|
||||||
size_t total = std::min(icon->bufSize, icon_mem.size());
|
size_t total = std::min(icon->bufSize, icon_mem.size());
|
||||||
std::memcpy(icon->buf, icon_mem.data(), total);
|
std::memcpy(icon->buf, icon_mem.data(), total);
|
||||||
icon->dataSize = total;
|
icon->dataSize = total;
|
||||||
@ -1494,36 +1510,37 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
|
|||||||
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
||||||
return Error::PARAMETER;
|
return Error::PARAMETER;
|
||||||
}
|
}
|
||||||
if (!SaveMemory::IsSaveMemoryInitialized()) {
|
u32 slot_id = 0;
|
||||||
|
u32 data_num = 1;
|
||||||
|
if (g_fw_ver > ElfInfo::FW_50) {
|
||||||
|
slot_id = setParam->slotId;
|
||||||
|
if (setParam->dataNum > 1) {
|
||||||
|
data_num = setParam->dataNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!SaveMemory::IsSaveMemoryInitialized(slot_id)) {
|
||||||
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()) {
|
|
||||||
LOG_TRACE(Lib_SaveData, "called while 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) {
|
||||||
SaveMemory::WriteMemory(data->buf, data->bufSize, data->offset);
|
for (int i = 0; i < data_num; i++) {
|
||||||
|
SaveMemory::WriteMemory(slot_id, data[i].buf, data[i].bufSize, data[i].offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto param = setParam->param;
|
auto param = setParam->param;
|
||||||
if (param != nullptr) {
|
if (param != nullptr) {
|
||||||
param->ToSFO(SaveMemory::GetParamSFO());
|
param->ToSFO(SaveMemory::GetParamSFO(slot_id));
|
||||||
SaveMemory::SaveSFO();
|
SaveMemory::SaveSFO(slot_id);
|
||||||
}
|
}
|
||||||
auto icon = setParam->icon;
|
|
||||||
if (icon != nullptr) {
|
auto icon = setParam->icon;
|
||||||
SaveMemory::WriteIcon(icon->buf, icon->bufSize);
|
if (icon != nullptr) {
|
||||||
|
SaveMemory::SetIcon(slot_id, icon->buf, icon->bufSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveMemory::TriggerSaveWithoutEvent();
|
|
||||||
return Error::OK;
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1563,9 +1580,12 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
|||||||
}
|
}
|
||||||
LOG_DEBUG(Lib_SaveData, "called");
|
LOG_DEBUG(Lib_SaveData, "called");
|
||||||
|
|
||||||
SaveMemory::SetDirectories(setupParam->userId, g_game_serial);
|
u32 slot_id = 0;
|
||||||
|
if (g_fw_ver > ElfInfo::FW_50) {
|
||||||
|
slot_id = setupParam->slotId;
|
||||||
|
}
|
||||||
|
|
||||||
const auto& save_path = SaveMemory::GetSavePath();
|
const auto& save_path = SaveMemory::GetSavePath(setupParam->userId, slot_id, g_game_serial);
|
||||||
for (const auto& instance : g_mount_slots) {
|
for (const auto& instance : g_mount_slots) {
|
||||||
if (instance.has_value() && instance->GetSavePath() == save_path) {
|
if (instance.has_value() && instance->GetSavePath() == save_path) {
|
||||||
return Error::BUSY;
|
return Error::BUSY;
|
||||||
@ -1573,21 +1593,21 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
size_t existed_size = SaveMemory::CreateSaveMemory(setupParam->memorySize);
|
size_t existed_size =
|
||||||
|
SaveMemory::SetupSaveMemory(setupParam->userId, slot_id, g_game_serial);
|
||||||
if (existed_size == 0) { // Just created
|
if (existed_size == 0) { // Just created
|
||||||
if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
|
if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
|
||||||
auto& sfo = SaveMemory::GetParamSFO();
|
auto& sfo = SaveMemory::GetParamSFO(slot_id);
|
||||||
setupParam->initParam->ToSFO(sfo);
|
setupParam->initParam->ToSFO(sfo);
|
||||||
}
|
}
|
||||||
SaveMemory::SaveSFO();
|
SaveMemory::SaveSFO(slot_id);
|
||||||
|
|
||||||
auto init_icon = setupParam->initIcon;
|
auto init_icon = setupParam->initIcon;
|
||||||
if (g_fw_ver >= ElfInfo::FW_45 && init_icon != nullptr) {
|
if (g_fw_ver >= ElfInfo::FW_45 && init_icon != nullptr) {
|
||||||
SaveMemory::SetIcon(init_icon->buf, init_icon->bufSize);
|
SaveMemory::SetIcon(slot_id, init_icon->buf, init_icon->bufSize);
|
||||||
} else {
|
} else {
|
||||||
SaveMemory::SetIcon(nullptr, 0);
|
SaveMemory::SetIcon(slot_id);
|
||||||
}
|
}
|
||||||
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;
|
||||||
@ -1631,15 +1651,23 @@ Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncPa
|
|||||||
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
||||||
return Error::PARAMETER;
|
return Error::PARAMETER;
|
||||||
}
|
}
|
||||||
if (!SaveMemory::IsSaveMemoryInitialized()) {
|
|
||||||
|
u32 slot_id = 0;
|
||||||
|
if (g_fw_ver > ElfInfo::FW_50) {
|
||||||
|
slot_id = syncParam->slotId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SaveMemory::IsSaveMemoryInitialized(slot_id)) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(Lib_SaveData, "called");
|
LOG_DEBUG(Lib_SaveData, "called");
|
||||||
bool ok = SaveMemory::TriggerSave();
|
|
||||||
if (!ok) {
|
SaveMemory::PersistMemory(slot_id);
|
||||||
return Error::BUSY_FOR_SAVING;
|
const auto& save_path = SaveMemory::GetSaveDir(slot_id);
|
||||||
}
|
Backup::NewRequest(syncParam->userId, g_game_serial, save_path,
|
||||||
|
OrbisSaveDataEventType::SAVE_DATA_MEMORY_SYNC);
|
||||||
|
|
||||||
return Error::OK;
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
namespace Libraries::SystemService {
|
namespace Libraries::SystemService {
|
||||||
|
|
||||||
bool g_splash_status{true};
|
bool g_splash_status{true};
|
||||||
|
std::queue<OrbisSystemServiceEvent> g_event_queue;
|
||||||
|
std::mutex g_event_queue_mutex;
|
||||||
|
|
||||||
bool IsSplashVisible() {
|
bool IsSplashVisible() {
|
||||||
return Config::showSplash() && g_splash_status;
|
return Config::showSplash() && g_splash_status;
|
||||||
@ -1772,7 +1774,9 @@ s32 PS4_SYSV_ABI sceSystemServiceGetStatus(OrbisSystemServiceStatus* status) {
|
|||||||
LOG_ERROR(Lib_SystemService, "OrbisSystemServiceStatus is null");
|
LOG_ERROR(Lib_SystemService, "OrbisSystemServiceStatus is null");
|
||||||
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
|
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
|
||||||
}
|
}
|
||||||
status->event_num = 0;
|
|
||||||
|
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
|
||||||
|
status->event_num = static_cast<s32>(g_event_queue.size());
|
||||||
status->is_system_ui_overlaid = false;
|
status->is_system_ui_overlaid = false;
|
||||||
status->is_in_background_execution = false;
|
status->is_in_background_execution = false;
|
||||||
status->is_cpu_mode7_cpu_normal = true;
|
status->is_cpu_mode7_cpu_normal = true;
|
||||||
@ -1940,11 +1944,19 @@ int PS4_SYSV_ABI sceSystemServiceRaiseExceptionLocalProcess() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceSystemServiceReceiveEvent(OrbisSystemServiceEvent* event) {
|
s32 PS4_SYSV_ABI sceSystemServiceReceiveEvent(OrbisSystemServiceEvent* event) {
|
||||||
LOG_ERROR(Lib_SystemService, "(STUBBED) called");
|
LOG_TRACE(Lib_SystemService, "called");
|
||||||
if (event == nullptr) {
|
if (event == nullptr) {
|
||||||
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
|
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
|
||||||
}
|
}
|
||||||
return ORBIS_SYSTEM_SERVICE_ERROR_NO_EVENT;
|
|
||||||
|
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
|
||||||
|
if (g_event_queue.empty()) {
|
||||||
|
return ORBIS_SYSTEM_SERVICE_ERROR_NO_EVENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*event = g_event_queue.front();
|
||||||
|
g_event_queue.pop();
|
||||||
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceSystemServiceReenableMusicPlayer() {
|
int PS4_SYSV_ABI sceSystemServiceReenableMusicPlayer() {
|
||||||
@ -2412,6 +2424,11 @@ int PS4_SYSV_ABI Func_CB5E885E225F69F0() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PushSystemServiceEvent(const OrbisSystemServiceEvent& event) {
|
||||||
|
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
|
||||||
|
g_event_queue.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym) {
|
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("alZfRdr2RP8", "libSceAppMessaging", 1, "libSceSystemService", 1, 1,
|
LIB_FUNCTION("alZfRdr2RP8", "libSceAppMessaging", 1, "libSceSystemService", 1, 1,
|
||||||
sceAppMessagingClearEventFlag);
|
sceAppMessagingClearEventFlag);
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
// https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/blob/master/include/orbis/_types/sys_service.h
|
// https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/blob/master/include/orbis/_types/sys_service.h
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
@ -603,5 +605,7 @@ int PS4_SYSV_ABI sceSystemServiceReenableVoiceRecognition();
|
|||||||
int PS4_SYSV_ABI Func_6B1CDB955F0EBD65();
|
int PS4_SYSV_ABI Func_6B1CDB955F0EBD65();
|
||||||
int PS4_SYSV_ABI Func_CB5E885E225F69F0();
|
int PS4_SYSV_ABI Func_CB5E885E225F69F0();
|
||||||
|
|
||||||
|
void PushSystemServiceEvent(const OrbisSystemServiceEvent& event);
|
||||||
|
|
||||||
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym);
|
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym);
|
||||||
} // namespace Libraries::SystemService
|
} // namespace Libraries::SystemService
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Libraries::Videodec {
|
namespace Libraries::Videodec {
|
||||||
|
|
||||||
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
|
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn,
|
int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn,
|
||||||
const OrbisVideodecResourceInfo* pRsrcInfoIn,
|
const OrbisVideodecResourceInfo* pRsrcInfoIn,
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Libraries::Vdec2 {
|
namespace Libraries::Vdec2 {
|
||||||
|
|
||||||
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
|
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI
|
s32 PS4_SYSV_ABI
|
||||||
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {
|
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {
|
||||||
|
112
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
Normal file
112
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 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 "core/libraries/web_browser_dialog/webbrowserdialog.h"
|
||||||
|
|
||||||
|
namespace Libraries::WebBrowserDialog {
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogClose() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogTerminate() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI Func_F2BE042771625F8C() {
|
||||||
|
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceWebBrowserDialog(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("PSK+Eik919Q", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogClose);
|
||||||
|
LIB_FUNCTION("Wit4LjeoeX4", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogGetEvent);
|
||||||
|
LIB_FUNCTION("vCaW0fgVQmc", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogGetResult);
|
||||||
|
LIB_FUNCTION("CFTG6a8TjOU", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogGetStatus);
|
||||||
|
LIB_FUNCTION("jqb7HntFQFc", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogInitialize);
|
||||||
|
LIB_FUNCTION("uYELOMVnmNQ", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogNavigate);
|
||||||
|
LIB_FUNCTION("FraP7debcdg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogOpen);
|
||||||
|
LIB_FUNCTION("O7dIZQrwVFY", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogOpenForPredeterminedContent);
|
||||||
|
LIB_FUNCTION("Cya+jvTtPqg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogResetCookie);
|
||||||
|
LIB_FUNCTION("TZnDVkP91Rg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogSetCookie);
|
||||||
|
LIB_FUNCTION("RLhKBOoNyXY", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogSetZoom);
|
||||||
|
LIB_FUNCTION("ocHtyBwHfys", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogTerminate);
|
||||||
|
LIB_FUNCTION("h1dR-t5ISgg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
sceWebBrowserDialogUpdateStatus);
|
||||||
|
LIB_FUNCTION("8r4EJ3FiX4w", "libSceWebBrowserDialogLimited", 1, "libSceWebBrowserDialog", 1, 1,
|
||||||
|
Func_F2BE042771625F8C);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::WebBrowserDialog
|
30
src/core/libraries/web_browser_dialog/webbrowserdialog.h
Normal file
30
src/core/libraries/web_browser_dialog/webbrowserdialog.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// 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::WebBrowserDialog {
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogClose();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogTerminate();
|
||||||
|
s32 PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus();
|
||||||
|
s32 PS4_SYSV_ABI Func_F2BE042771625F8C();
|
||||||
|
|
||||||
|
void RegisterlibSceWebBrowserDialog(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::WebBrowserDialog
|
183
src/core/libraries/zlib/zlib.cpp
Normal file
183
src/core/libraries/zlib/zlib.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <stop_token>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <queue>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/thread.h"
|
||||||
|
#include "core/libraries/kernel/threads.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/libraries/zlib/zlib_error.h"
|
||||||
|
#include "core/libraries/zlib/zlib_sce.h"
|
||||||
|
|
||||||
|
namespace Libraries::Zlib {
|
||||||
|
|
||||||
|
struct InflateTask {
|
||||||
|
u64 request_id;
|
||||||
|
const void* src;
|
||||||
|
u32 src_length;
|
||||||
|
void* dst;
|
||||||
|
u32 dst_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InflateResult {
|
||||||
|
u32 length;
|
||||||
|
s32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Kernel::Thread task_thread;
|
||||||
|
|
||||||
|
static std::mutex mutex;
|
||||||
|
static std::queue<InflateTask> task_queue;
|
||||||
|
static std::condition_variable_any task_queue_cv;
|
||||||
|
static std::queue<u64> done_queue;
|
||||||
|
static std::condition_variable_any done_queue_cv;
|
||||||
|
static std::unordered_map<u64, InflateResult> results;
|
||||||
|
static u64 next_request_id;
|
||||||
|
|
||||||
|
void ZlibTaskThread(const std::stop_token& stop) {
|
||||||
|
Common::SetCurrentThreadName("shadPS4:ZlibTaskThread");
|
||||||
|
|
||||||
|
while (!stop.stop_requested()) {
|
||||||
|
InflateTask task;
|
||||||
|
{
|
||||||
|
// Lock and pop from the task queue, unless stop has been requested.
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
if (!task_queue_cv.wait(lock, stop, [&] { return !task_queue.empty(); })) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
task = task_queue.back();
|
||||||
|
task_queue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
uLongf decompressed_length = task.dst_length;
|
||||||
|
const auto ret = uncompress(static_cast<Bytef*>(task.dst), &decompressed_length,
|
||||||
|
static_cast<const Bytef*>(task.src), task.src_length);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Lock, insert the new result, and push the finished request ID to the done queue.
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
results[task.request_id] = InflateResult{
|
||||||
|
.length = static_cast<u32>(decompressed_length),
|
||||||
|
.status = ret == Z_BUF_ERROR ? ORBIS_ZLIB_ERROR_NOSPACE
|
||||||
|
: ret == Z_OK ? ORBIS_OK
|
||||||
|
: ORBIS_ZLIB_ERROR_FATAL,
|
||||||
|
};
|
||||||
|
done_queue.push(task.request_id);
|
||||||
|
}
|
||||||
|
done_queue_cv.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceZlibInitialize(const void* buffer, u32 length) {
|
||||||
|
LOG_INFO(Lib_Zlib, "called");
|
||||||
|
if (task_thread.Joinable()) {
|
||||||
|
return ORBIS_ZLIB_ERROR_ALREADY_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with empty task data
|
||||||
|
task_queue = std::queue<InflateTask>();
|
||||||
|
done_queue = std::queue<u64>();
|
||||||
|
results.clear();
|
||||||
|
next_request_id = 1;
|
||||||
|
|
||||||
|
task_thread.Run([](const std::stop_token& stop) { ZlibTaskThread(stop); });
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceZlibInflate(const void* src, u32 src_len, void* dst, u32 dst_len,
|
||||||
|
u64* request_id) {
|
||||||
|
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
|
||||||
|
if (!task_thread.Joinable()) {
|
||||||
|
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (!src || !src_len || !dst || !dst_len || !request_id || dst_len > 64_KB ||
|
||||||
|
dst_len % 2_KB != 0) {
|
||||||
|
return ORBIS_ZLIB_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
*request_id = next_request_id++;
|
||||||
|
task_queue.emplace(InflateTask{
|
||||||
|
.request_id = *request_id,
|
||||||
|
.src = src,
|
||||||
|
.src_length = src_len,
|
||||||
|
.dst = dst,
|
||||||
|
.dst_length = dst_len,
|
||||||
|
});
|
||||||
|
task_queue_cv.notify_one();
|
||||||
|
}
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout) {
|
||||||
|
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
|
||||||
|
if (!task_thread.Joinable()) {
|
||||||
|
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (!request_id) {
|
||||||
|
return ORBIS_ZLIB_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Pop from the done queue, unless the timeout is reached.
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
const auto pred = [] { return !done_queue.empty(); };
|
||||||
|
if (timeout) {
|
||||||
|
if (!done_queue_cv.wait_for(lock, std::chrono::milliseconds(*timeout), pred)) {
|
||||||
|
return ORBIS_ZLIB_ERROR_TIMEDOUT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
done_queue_cv.wait(lock, pred);
|
||||||
|
}
|
||||||
|
*request_id = done_queue.back();
|
||||||
|
done_queue.pop();
|
||||||
|
}
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceZlibGetResult(const u64 request_id, u32* dst_length, s32* status) {
|
||||||
|
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
|
||||||
|
if (!task_thread.Joinable()) {
|
||||||
|
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (!dst_length || !status) {
|
||||||
|
return ORBIS_ZLIB_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
if (!results.contains(request_id)) {
|
||||||
|
return ORBIS_ZLIB_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
const auto result = results[request_id];
|
||||||
|
*dst_length = result.length;
|
||||||
|
*status = result.status;
|
||||||
|
}
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceZlibFinalize() {
|
||||||
|
LOG_INFO(Lib_Zlib, "called");
|
||||||
|
if (!task_thread.Joinable()) {
|
||||||
|
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
task_thread.Stop();
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceZlib(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("m1YErdIXCp4", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibInitialize);
|
||||||
|
LIB_FUNCTION("6na+Sa-B83w", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibFinalize);
|
||||||
|
LIB_FUNCTION("TLar1HULv1Q", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibInflate);
|
||||||
|
LIB_FUNCTION("uB8VlDD4e0s", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibWaitForDone);
|
||||||
|
LIB_FUNCTION("2eDcGHC0YaM", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibGetResult);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Zlib
|
18
src/core/libraries/zlib/zlib_error.h
Normal file
18
src/core/libraries/zlib/zlib_error.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
|
||||||
|
// Zlib library
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_NOT_FOUND = 0x81120002;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_BUSY = 0x8112000B;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_FAULT = 0x8112000E;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_INVALID = 0x81120016;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_NOSPACE = 0x8112001C;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_NOT_SUPPORTED = 0x81120025;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_TIMEDOUT = 0x81120027;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_NOT_INITIALIZED = 0x81120032;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_ALREADY_INITIALIZED = 0x81120033;
|
||||||
|
constexpr int ORBIS_ZLIB_ERROR_FATAL = 0x811200FF;
|
21
src/core/libraries/zlib/zlib_sce.h
Normal file
21
src/core/libraries/zlib/zlib_sce.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::Zlib {
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceZlibInitialize(const void* buffer, u32 length);
|
||||||
|
s32 PS4_SYSV_ABI sceZlibInflate(const void* src, u32 src_len, void* dst, u32 dst_len,
|
||||||
|
u64* request_id);
|
||||||
|
s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout);
|
||||||
|
s32 PS4_SYSV_ABI sceZlibGetResult(u64 request_id, u32* dst_length, s32* status);
|
||||||
|
s32 PS4_SYSV_ABI sceZlibFinalize();
|
||||||
|
|
||||||
|
void RegisterlibSceZlib(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Zlib
|
@ -52,7 +52,7 @@ Linker::Linker() : memory{Memory::Instance()} {}
|
|||||||
|
|
||||||
Linker::~Linker() = default;
|
Linker::~Linker() = default;
|
||||||
|
|
||||||
void Linker::Execute() {
|
void Linker::Execute(const std::vector<std::string> args) {
|
||||||
if (Config::debugDump()) {
|
if (Config::debugDump()) {
|
||||||
DebugDump();
|
DebugDump();
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ void Linker::Execute() {
|
|||||||
|
|
||||||
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
|
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
|
||||||
|
|
||||||
main_thread.Run([this, module](std::stop_token) {
|
main_thread.Run([this, module, args](std::stop_token) {
|
||||||
Common::SetCurrentThreadName("GAME_MainThread");
|
Common::SetCurrentThreadName("GAME_MainThread");
|
||||||
LoadSharedLibraries();
|
LoadSharedLibraries();
|
||||||
|
|
||||||
@ -109,6 +109,12 @@ void Linker::Execute() {
|
|||||||
EntryParams params{};
|
EntryParams params{};
|
||||||
params.argc = 1;
|
params.argc = 1;
|
||||||
params.argv[0] = "eboot.bin";
|
params.argv[0] = "eboot.bin";
|
||||||
|
if (!args.empty()) {
|
||||||
|
params.argc = args.size() + 1;
|
||||||
|
for (int i = 0; i < args.size() && i < 32; i++) {
|
||||||
|
params.argv[i + 1] = args[i].c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
params.entry_addr = module->GetEntryAddress();
|
params.entry_addr = module->GetEntryAddress();
|
||||||
RunMainEntry(¶ms);
|
RunMainEntry(¶ms);
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,7 @@ class Linker;
|
|||||||
struct EntryParams {
|
struct EntryParams {
|
||||||
int argc;
|
int argc;
|
||||||
u32 padding;
|
u32 padding;
|
||||||
const char* argv[3];
|
const char* argv[33];
|
||||||
VAddr entry_addr;
|
VAddr entry_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,10 +109,13 @@ public:
|
|||||||
|
|
||||||
void RelocateAnyImports(Module* m) {
|
void RelocateAnyImports(Module* m) {
|
||||||
Relocate(m);
|
Relocate(m);
|
||||||
for (auto& module : m_modules) {
|
const auto exports = m->GetExportModules();
|
||||||
const auto imports = module->GetImportModules();
|
for (auto& export_mod : exports) {
|
||||||
if (std::ranges::contains(imports, m->name, &ModuleInfo::name)) {
|
for (auto& module : m_modules) {
|
||||||
Relocate(module.get());
|
const auto imports = module->GetImportModules();
|
||||||
|
if (std::ranges::contains(imports, export_mod.name, &ModuleInfo::name)) {
|
||||||
|
Relocate(module.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,7 +146,7 @@ public:
|
|||||||
void Relocate(Module* module);
|
void Relocate(Module* module);
|
||||||
bool Resolve(const std::string& name, Loader::SymbolType type, Module* module,
|
bool Resolve(const std::string& name, Loader::SymbolType type, Module* module,
|
||||||
Loader::SymbolRecord* return_info);
|
Loader::SymbolRecord* return_info);
|
||||||
void Execute();
|
void Execute(const std::vector<std::string> args = {});
|
||||||
void DebugDump();
|
void DebugDump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -389,47 +389,57 @@ s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
|||||||
return UnmapMemoryImpl(virtual_addr, size);
|
return UnmapMemoryImpl(virtual_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
|
u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, u64 size) {
|
||||||
const auto it = FindVMA(virtual_addr);
|
|
||||||
const auto& vma_base = it->second;
|
|
||||||
ASSERT_MSG(vma_base.Contains(virtual_addr, size),
|
|
||||||
"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 type = vma_base.type;
|
||||||
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 adjusted_size =
|
||||||
|
vma_base_size - start_in_vma < size ? vma_base_size - start_in_vma : size;
|
||||||
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
||||||
|
|
||||||
|
if (type == VMAType::Free) {
|
||||||
|
return adjusted_size;
|
||||||
|
}
|
||||||
if (type == VMAType::Direct || type == VMAType::Pooled) {
|
if (type == VMAType::Direct || type == VMAType::Pooled) {
|
||||||
rasterizer->UnmapMemory(virtual_addr, size);
|
rasterizer->UnmapMemory(virtual_addr, adjusted_size);
|
||||||
}
|
}
|
||||||
if (type == VMAType::Flexible) {
|
if (type == VMAType::Flexible) {
|
||||||
flexible_usage -= size;
|
flexible_usage -= adjusted_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark region as free and attempt to coalesce it with neighbours.
|
// Mark region as free and attempt to coalesce it with neighbours.
|
||||||
const auto new_it = CarveVMA(virtual_addr, size);
|
const auto new_it = CarveVMA(virtual_addr, adjusted_size);
|
||||||
auto& vma = new_it->second;
|
auto& vma = new_it->second;
|
||||||
vma.type = VMAType::Free;
|
vma.type = VMAType::Free;
|
||||||
vma.prot = MemoryProt::NoAccess;
|
vma.prot = MemoryProt::NoAccess;
|
||||||
vma.phys_base = 0;
|
vma.phys_base = 0;
|
||||||
vma.disallow_merge = false;
|
vma.disallow_merge = false;
|
||||||
vma.name = "";
|
vma.name = "";
|
||||||
MergeAdjacent(vma_map, new_it);
|
const auto post_merge_it = MergeAdjacent(vma_map, new_it);
|
||||||
bool readonly_file = vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
auto& post_merge_vma = post_merge_it->second;
|
||||||
|
bool readonly_file = post_merge_vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
||||||
if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
|
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,
|
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + adjusted_size,
|
||||||
is_exec, has_backing, readonly_file);
|
phys_base, is_exec, has_backing, readonly_file);
|
||||||
TRACK_FREE(virtual_addr, "VMEM");
|
TRACK_FREE(virtual_addr, "VMEM");
|
||||||
}
|
}
|
||||||
|
return adjusted_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, u64 size) {
|
||||||
|
u64 unmapped_bytes = 0;
|
||||||
|
do {
|
||||||
|
auto it = FindVMA(virtual_addr + unmapped_bytes);
|
||||||
|
auto& vma_base = it->second;
|
||||||
|
auto unmapped =
|
||||||
|
UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes);
|
||||||
|
ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible");
|
||||||
|
unmapped_bytes += unmapped;
|
||||||
|
} while (unmapped_bytes < size);
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
@ -529,8 +539,8 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
|
|||||||
info->is_flexible.Assign(vma.type == VMAType::Flexible);
|
info->is_flexible.Assign(vma.type == VMAType::Flexible);
|
||||||
info->is_direct.Assign(vma.type == VMAType::Direct);
|
info->is_direct.Assign(vma.type == VMAType::Direct);
|
||||||
info->is_stack.Assign(vma.type == VMAType::Stack);
|
info->is_stack.Assign(vma.type == VMAType::Stack);
|
||||||
info->is_pooled.Assign(vma.type == VMAType::PoolReserved);
|
info->is_pooled.Assign(vma.type == VMAType::PoolReserved || vma.type == VMAType::Pooled);
|
||||||
info->is_committed.Assign(vma.type == VMAType::Pooled);
|
info->is_committed.Assign(vma.IsMapped());
|
||||||
vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size()));
|
vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size()));
|
||||||
if (vma.type == VMAType::Direct) {
|
if (vma.type == VMAType::Direct) {
|
||||||
const auto dmem_it = FindDmemArea(vma.phys_base);
|
const auto dmem_it = FindDmemArea(vma.phys_base);
|
||||||
@ -651,6 +661,12 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
|
|||||||
|
|
||||||
const VAddr start_in_vma = virtual_addr - vma.base;
|
const VAddr start_in_vma = virtual_addr - vma.base;
|
||||||
const VAddr end_in_vma = start_in_vma + size;
|
const VAddr end_in_vma = start_in_vma + size;
|
||||||
|
|
||||||
|
if (start_in_vma == 0 && size == vma.size) {
|
||||||
|
// if requsting the whole VMA, return it
|
||||||
|
return vma_handle;
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_MSG(end_in_vma <= vma.size, "Mapping cannot fit inside free region");
|
ASSERT_MSG(end_in_vma <= vma.size, "Mapping cannot fit inside free region");
|
||||||
|
|
||||||
if (end_in_vma != vma.size) {
|
if (end_in_vma != vma.size) {
|
||||||
|
@ -252,7 +252,9 @@ private:
|
|||||||
|
|
||||||
DMemHandle Split(DMemHandle dmem_handle, size_t offset_in_area);
|
DMemHandle Split(DMemHandle dmem_handle, size_t offset_in_area);
|
||||||
|
|
||||||
s32 UnmapMemoryImpl(VAddr virtual_addr, size_t size);
|
u64 UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, u64 size);
|
||||||
|
|
||||||
|
s32 UnmapMemoryImpl(VAddr virtual_addr, u64 size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AddressSpace impl;
|
AddressSpace impl;
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "core/libraries/ngs2/ngs2.h"
|
#include "core/libraries/ngs2/ngs2.h"
|
||||||
#include "core/libraries/np_trophy/np_trophy.h"
|
#include "core/libraries/np_trophy/np_trophy.h"
|
||||||
#include "core/libraries/rtc/rtc.h"
|
#include "core/libraries/rtc/rtc.h"
|
||||||
|
#include "core/libraries/save_data/save_backup.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
@ -66,9 +67,9 @@ Emulator::Emulator() {
|
|||||||
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
||||||
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
|
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
|
||||||
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
|
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
|
||||||
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled());
|
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::getVkCrashDiagnosticEnabled());
|
||||||
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::vkHostMarkersEnabled());
|
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::getVkHostMarkersEnabled());
|
||||||
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::vkGuestMarkersEnabled());
|
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::getVkGuestMarkersEnabled());
|
||||||
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
|
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
|
||||||
|
|
||||||
// Create stdin/stdout/stderr
|
// Create stdin/stdout/stderr
|
||||||
@ -99,10 +100,22 @@ Emulator::~Emulator() {
|
|||||||
Config::saveMainWindow(config_dir / "config.toml");
|
Config::saveMainWindow(config_dir / "config.toml");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::Run(const std::filesystem::path& file) {
|
void Emulator::Run(const std::filesystem::path& file, const std::vector<std::string> args) {
|
||||||
|
const auto eboot_name = file.filename().string();
|
||||||
|
auto game_folder = file.parent_path();
|
||||||
|
if (const auto game_folder_name = game_folder.filename().string();
|
||||||
|
game_folder_name.ends_with("-UPDATE")) {
|
||||||
|
// If an executable was launched from a separate update directory,
|
||||||
|
// use the base game directory as the game folder.
|
||||||
|
const auto base_name = game_folder_name.substr(0, game_folder_name.size() - 7);
|
||||||
|
const auto base_path = game_folder.parent_path() / base_name;
|
||||||
|
if (std::filesystem::is_directory(base_path)) {
|
||||||
|
game_folder = base_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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();
|
||||||
const auto game_folder = file.parent_path();
|
|
||||||
mnt->Mount(game_folder, "/app0");
|
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(game_folder, "/hostapp");
|
mnt->Mount(game_folder, "/hostapp");
|
||||||
@ -152,6 +165,15 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
if (const auto raw_attributes = param_sfo->GetInteger("ATTRIBUTE")) {
|
if (const auto raw_attributes = param_sfo->GetInteger("ATTRIBUTE")) {
|
||||||
psf_attributes.raw = *raw_attributes;
|
psf_attributes.raw = *raw_attributes;
|
||||||
}
|
}
|
||||||
|
if (!args.empty()) {
|
||||||
|
int argc = std::min<int>(args.size(), 32);
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
LOG_INFO(Loader, "Game argument {}: {}", i, args[i]);
|
||||||
|
}
|
||||||
|
if (args.size() > 32) {
|
||||||
|
LOG_ERROR(Loader, "Too many game arguments, only passing the first 32");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
|
const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
|
||||||
@ -214,7 +236,7 @@ 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());
|
const auto eboot_path = mnt->GetHostPath("/app0/" + eboot_name);
|
||||||
linker->LoadModule(eboot_path);
|
linker->LoadModule(eboot_path);
|
||||||
|
|
||||||
// check if we have system modules to load
|
// check if we have system modules to load
|
||||||
@ -239,7 +261,7 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
linker->Execute();
|
linker->Execute(args);
|
||||||
|
|
||||||
window->InitTimers();
|
window->InitTimers();
|
||||||
while (window->IsOpen()) {
|
while (window->IsOpen()) {
|
||||||
@ -250,7 +272,7 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
UpdatePlayTime(id);
|
UpdatePlayTime(id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::exit(0);
|
std::quick_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::LoadSystemModules(const std::string& game_serial) {
|
void Emulator::LoadSystemModules(const std::string& game_serial) {
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
Emulator();
|
Emulator();
|
||||||
~Emulator();
|
~Emulator();
|
||||||
|
|
||||||
void Run(const std::filesystem::path& file);
|
void Run(const std::filesystem::path& file, const std::vector<std::string> args = {});
|
||||||
void UpdatePlayTime(const std::string& serial);
|
void UpdatePlayTime(const std::string& serial);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -186,7 +186,8 @@ ImGuiID NewFrame(bool is_reusing_frame) {
|
|||||||
Sdl::NewFrame(is_reusing_frame);
|
Sdl::NewFrame(is_reusing_frame);
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
ImGuiWindowFlags flags = ImGuiDockNodeFlags_PassthruCentralNode;
|
ImGuiWindowFlags flags =
|
||||||
|
ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_AutoHideTabBar;
|
||||||
if (!DebugState.IsShowingDebugMenuBar()) {
|
if (!DebugState.IsShowingDebugMenuBar()) {
|
||||||
flags |= ImGuiDockNodeFlags_NoTabBar;
|
flags |= ImGuiDockNodeFlags_NoTabBar;
|
||||||
}
|
}
|
||||||
@ -207,7 +208,7 @@ void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config::vkHostMarkersEnabled()) {
|
if (Config::getVkHostMarkersEnabled()) {
|
||||||
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
|
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
|
||||||
.pLabelName = "ImGui Render",
|
.pLabelName = "ImGui Render",
|
||||||
});
|
});
|
||||||
@ -232,7 +233,7 @@ void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
|
|||||||
cmdbuf.beginRendering(render_info);
|
cmdbuf.beginRendering(render_info);
|
||||||
Vulkan::RenderDrawData(*draw_data, cmdbuf);
|
Vulkan::RenderDrawData(*draw_data, cmdbuf);
|
||||||
cmdbuf.endRendering();
|
cmdbuf.endRendering();
|
||||||
if (Config::vkHostMarkersEnabled()) {
|
if (Config::getVkHostMarkersEnabled()) {
|
||||||
cmdbuf.endDebugUtilsLabelEXT();
|
cmdbuf.endDebugUtilsLabelEXT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ void WorkerLoop() {
|
|||||||
g_job_list.pop_front();
|
g_job_list.pop_front();
|
||||||
g_job_list_mtx.unlock();
|
g_job_list_mtx.unlock();
|
||||||
|
|
||||||
if (Config::vkCrashDiagnosticEnabled()) {
|
if (Config::getVkCrashDiagnosticEnabled()) {
|
||||||
// FIXME: Crash diagnostic hangs when building the command buffer here
|
// FIXME: Crash diagnostic hangs when building the command buffer here
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,55 @@
|
|||||||
|
|
||||||
namespace Input {
|
namespace Input {
|
||||||
|
|
||||||
|
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||||
|
|
||||||
|
void State::OnButton(OrbisPadButtonDataOffset button, bool isPressed) {
|
||||||
|
if (isPressed) {
|
||||||
|
buttonsState |= button;
|
||||||
|
} else {
|
||||||
|
buttonsState &= ~button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::OnAxis(Axis axis, int value) {
|
||||||
|
const auto toggle = [&](const auto button) {
|
||||||
|
if (value > 0) {
|
||||||
|
buttonsState |= button;
|
||||||
|
} else {
|
||||||
|
buttonsState &= ~button;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
switch (axis) {
|
||||||
|
case Axis::TriggerLeft:
|
||||||
|
toggle(OrbisPadButtonDataOffset::L2);
|
||||||
|
break;
|
||||||
|
case Axis::TriggerRight:
|
||||||
|
toggle(OrbisPadButtonDataOffset::R2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
axes[static_cast<int>(axis)] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::OnTouchpad(int touchIndex, bool isDown, float x, float y) {
|
||||||
|
touchpad[touchIndex].state = isDown;
|
||||||
|
touchpad[touchIndex].x = static_cast<u16>(x * 1920);
|
||||||
|
touchpad[touchIndex].y = static_cast<u16>(y * 941);
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::OnGyro(const float gyro[3]) {
|
||||||
|
angularVelocity.x = gyro[0];
|
||||||
|
angularVelocity.y = gyro[1];
|
||||||
|
angularVelocity.z = gyro[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void State::OnAccel(const float accel[3]) {
|
||||||
|
acceleration.x = accel[0];
|
||||||
|
acceleration.y = accel[1];
|
||||||
|
acceleration.z = accel[2];
|
||||||
|
}
|
||||||
|
|
||||||
GameController::GameController() {
|
GameController::GameController() {
|
||||||
m_states_num = 0;
|
m_states_num = 0;
|
||||||
m_last_state = State();
|
m_last_state = State();
|
||||||
@ -75,45 +124,22 @@ void GameController::AddState(const State& state) {
|
|||||||
m_states_num++;
|
m_states_num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::CheckButton(int id, Libraries::Pad::OrbisPadButtonDataOffset button,
|
void GameController::CheckButton(int id, OrbisPadButtonDataOffset button, bool is_pressed) {
|
||||||
bool is_pressed) {
|
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
auto state = GetLastState();
|
auto state = GetLastState();
|
||||||
|
|
||||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
if (is_pressed) {
|
state.OnButton(button, is_pressed);
|
||||||
state.buttonsState |= button;
|
|
||||||
} else {
|
|
||||||
state.buttonsState &= ~button;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddState(state);
|
AddState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::Axis(int id, Input::Axis axis, int value) {
|
void GameController::Axis(int id, Input::Axis axis, int value) {
|
||||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
|
||||||
|
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
auto state = GetLastState();
|
auto state = GetLastState();
|
||||||
|
|
||||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
int axis_id = static_cast<int>(axis);
|
state.OnAxis(axis, value);
|
||||||
state.axes[axis_id] = value;
|
|
||||||
|
|
||||||
if (axis == Input::Axis::TriggerLeft) {
|
|
||||||
if (value > 0) {
|
|
||||||
state.buttonsState |= OrbisPadButtonDataOffset::L2;
|
|
||||||
} else {
|
|
||||||
state.buttonsState &= ~OrbisPadButtonDataOffset::L2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axis == Input::Axis::TriggerRight) {
|
|
||||||
if (value > 0) {
|
|
||||||
state.buttonsState |= OrbisPadButtonDataOffset::R2;
|
|
||||||
} else {
|
|
||||||
state.buttonsState &= ~OrbisPadButtonDataOffset::R2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AddState(state);
|
AddState(state);
|
||||||
}
|
}
|
||||||
@ -124,9 +150,7 @@ void GameController::Gyro(int id, const float gyro[3]) {
|
|||||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
|
|
||||||
// Update the angular velocity (gyro data)
|
// Update the angular velocity (gyro data)
|
||||||
state.angularVelocity.x = gyro[0]; // X-axis
|
state.OnGyro(gyro);
|
||||||
state.angularVelocity.y = gyro[1]; // Y-axis
|
|
||||||
state.angularVelocity.z = gyro[2]; // Z-axis
|
|
||||||
|
|
||||||
AddState(state);
|
AddState(state);
|
||||||
}
|
}
|
||||||
@ -136,9 +160,7 @@ void GameController::Acceleration(int id, const float acceleration[3]) {
|
|||||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
|
|
||||||
// Update the acceleration values
|
// Update the acceleration values
|
||||||
state.acceleration.x = acceleration[0]; // X-axis
|
state.OnAccel(acceleration);
|
||||||
state.acceleration.y = acceleration[1]; // Y-axis
|
|
||||||
state.acceleration.z = acceleration[2]; // Z-axis
|
|
||||||
|
|
||||||
AddState(state);
|
AddState(state);
|
||||||
}
|
}
|
||||||
@ -211,62 +233,48 @@ void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceler
|
|||||||
}
|
}
|
||||||
|
|
||||||
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_engine) {
|
||||||
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
|
return;
|
||||||
}
|
}
|
||||||
|
std::scoped_lock _{m_mutex};
|
||||||
|
m_engine->SetLightBarRGB(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameController::SetVibration(u8 smallMotor, u8 largeMotor) {
|
void GameController::SetVibration(u8 smallMotor, u8 largeMotor) {
|
||||||
if (m_sdl_gamepad != nullptr) {
|
if (!m_engine) {
|
||||||
return SDL_RumbleGamepad(m_sdl_gamepad, (smallMotor / 255.0f) * 0xFFFF,
|
return;
|
||||||
(largeMotor / 255.0f) * 0xFFFF, -1);
|
|
||||||
}
|
}
|
||||||
return true;
|
std::scoped_lock _{m_mutex};
|
||||||
|
m_engine->SetVibration(smallMotor, largeMotor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, float y) {
|
void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, float y) {
|
||||||
if (touchIndex < 2) {
|
if (touchIndex < 2) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
auto state = GetLastState();
|
auto state = GetLastState();
|
||||||
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
|
||||||
|
|
||||||
state.touchpad[touchIndex].state = touchDown;
|
state.time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
state.touchpad[touchIndex].x = static_cast<u16>(x * 1920);
|
state.OnTouchpad(touchIndex, touchDown, x, y);
|
||||||
state.touchpad[touchIndex].y = static_cast<u16>(y * 941);
|
|
||||||
|
|
||||||
AddState(state);
|
AddState(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::TryOpenSDLController() {
|
void GameController::SetEngine(std::unique_ptr<Engine> engine) {
|
||||||
if (m_sdl_gamepad == nullptr || !SDL_GamepadConnected(m_sdl_gamepad)) {
|
std::scoped_lock _{m_mutex};
|
||||||
int gamepad_count;
|
m_engine = std::move(engine);
|
||||||
SDL_JoystickID* gamepads = SDL_GetGamepads(&gamepad_count);
|
if (m_engine) {
|
||||||
m_sdl_gamepad = gamepad_count > 0 ? SDL_OpenGamepad(gamepads[0]) : nullptr;
|
m_engine->Init();
|
||||||
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);
|
|
||||||
|
|
||||||
SetLightBarRGB(0, 0, 255);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Engine* GameController::GetEngine() {
|
||||||
|
return m_engine.get();
|
||||||
|
}
|
||||||
|
|
||||||
u32 GameController::Poll() {
|
u32 GameController::Poll() {
|
||||||
std::scoped_lock lock{m_mutex};
|
|
||||||
if (m_connected) {
|
if (m_connected) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
auto time = Libraries::Kernel::sceKernelGetProcessTime();
|
auto time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
if (m_states_num == 0) {
|
if (m_states_num == 0) {
|
||||||
auto diff = (time - m_last_state.time) / 1000;
|
auto diff = (time - m_last_state.time) / 1000;
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "core/libraries/pad/pad.h"
|
#include "core/libraries/pad/pad.h"
|
||||||
|
|
||||||
struct SDL_Gamepad;
|
|
||||||
|
|
||||||
namespace Input {
|
namespace Input {
|
||||||
|
|
||||||
enum class Axis {
|
enum class Axis {
|
||||||
@ -28,7 +28,14 @@ struct TouchpadEntry {
|
|||||||
u16 y{};
|
u16 y{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct State {
|
class State {
|
||||||
|
public:
|
||||||
|
void OnButton(Libraries::Pad::OrbisPadButtonDataOffset, bool);
|
||||||
|
void OnAxis(Axis, int);
|
||||||
|
void OnTouchpad(int touchIndex, bool isDown, float x, float y);
|
||||||
|
void OnGyro(const float[3]);
|
||||||
|
void OnAccel(const float[3]);
|
||||||
|
|
||||||
Libraries::Pad::OrbisPadButtonDataOffset buttonsState{};
|
Libraries::Pad::OrbisPadButtonDataOffset buttonsState{};
|
||||||
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};
|
||||||
@ -38,9 +45,19 @@ struct State {
|
|||||||
Libraries::Pad::OrbisFQuaternion orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
Libraries::Pad::OrbisFQuaternion orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Engine {
|
||||||
|
public:
|
||||||
|
virtual ~Engine() = default;
|
||||||
|
virtual void Init() = 0;
|
||||||
|
virtual void SetLightBarRGB(u8 r, u8 g, u8 b) = 0;
|
||||||
|
virtual void SetVibration(u8 smallMotor, u8 largeMotor) = 0;
|
||||||
|
virtual State ReadState() = 0;
|
||||||
|
virtual float GetAccelPollRate() const = 0;
|
||||||
|
virtual float GetGyroPollRate() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
inline int GetAxis(int min, int max, int value) {
|
inline int GetAxis(int min, int max, int value) {
|
||||||
int v = (255 * (value - min)) / (max - min);
|
return std::clamp((255 * (value - min)) / (max - min), 0, 255);
|
||||||
return (v < 0 ? 0 : (v > 255 ? 255 : v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u32 MAX_STATES = 64;
|
constexpr u32 MAX_STATES = 64;
|
||||||
@ -59,13 +76,12 @@ public:
|
|||||||
void Gyro(int id, const float gyro[3]);
|
void Gyro(int id, const float gyro[3]);
|
||||||
void Acceleration(int id, const float acceleration[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);
|
void 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 SetEngine(std::unique_ptr<Engine>);
|
||||||
|
Engine* GetEngine();
|
||||||
u32 Poll();
|
u32 Poll();
|
||||||
|
|
||||||
float gyro_poll_rate;
|
|
||||||
float accel_poll_rate;
|
|
||||||
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||||
float deltaTime,
|
float deltaTime,
|
||||||
@ -85,7 +101,7 @@ private:
|
|||||||
std::array<State, MAX_STATES> m_states;
|
std::array<State, MAX_STATES> m_states;
|
||||||
std::array<StateInternal, MAX_STATES> m_private;
|
std::array<StateInternal, MAX_STATES> m_private;
|
||||||
|
|
||||||
SDL_Gamepad* m_sdl_gamepad = nullptr;
|
std::unique_ptr<Engine> m_engine = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Input
|
} // namespace Input
|
||||||
|
21
src/main.cpp
21
src/main.cpp
@ -29,6 +29,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
bool has_game_argument = false;
|
bool has_game_argument = false;
|
||||||
std::string game_path;
|
std::string game_path;
|
||||||
|
std::vector<std::string> game_args{};
|
||||||
|
|
||||||
// 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 = {
|
||||||
@ -37,6 +38,9 @@ int main(int argc, char* argv[]) {
|
|||||||
std::cout << "Usage: shadps4 [options] <elf or eboot.bin path>\n"
|
std::cout << "Usage: shadps4 [options] <elf or eboot.bin path>\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -g, --game <path|ID> Specify game path to launch\n"
|
" -g, --game <path|ID> Specify game path to launch\n"
|
||||||
|
" -- ... Parameters passed to the game ELF. "
|
||||||
|
"Needs to be at the end of the line, and everything after \"--\" is a "
|
||||||
|
"game argument.\n"
|
||||||
" -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"
|
||||||
@ -126,6 +130,21 @@ int main(int argc, char* argv[]) {
|
|||||||
// Assume the last argument is the game file if not specified via -g/--game
|
// Assume the last argument is the game file if not specified via -g/--game
|
||||||
game_path = argv[i];
|
game_path = argv[i];
|
||||||
has_game_argument = true;
|
has_game_argument = true;
|
||||||
|
} else if (std::string(argv[i]) == "--") {
|
||||||
|
if (i + 1 == argc) {
|
||||||
|
std::cerr << "Warning: -- is set, but no game arguments are added!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int j = i + 1; j < argc; j++) {
|
||||||
|
game_args.push_back(argv[j]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (i + 1 < argc && std::string(argv[i + 1]) == "--") {
|
||||||
|
if (!has_game_argument) {
|
||||||
|
game_path = argv[i];
|
||||||
|
has_game_argument = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
} 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;
|
||||||
@ -166,7 +185,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Run the emulator with the resolved eboot path
|
// Run the emulator with the resolved eboot path
|
||||||
Core::Emulator emulator;
|
Core::Emulator emulator;
|
||||||
emulator.Run(eboot_path);
|
emulator.Run(eboot_path, game_args);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -188,8 +188,12 @@ void CheatsPatches::setupUI() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QPushButton* closeButton = new QPushButton(tr("Close"));
|
||||||
|
connect(closeButton, &QPushButton::clicked, [this]() { QWidget::close(); });
|
||||||
|
|
||||||
controlLayout->addWidget(downloadButton);
|
controlLayout->addWidget(downloadButton);
|
||||||
controlLayout->addWidget(deleteCheatButton);
|
controlLayout->addWidget(deleteCheatButton);
|
||||||
|
controlLayout->addWidget(closeButton);
|
||||||
|
|
||||||
cheatsLayout->addLayout(controlLayout);
|
cheatsLayout->addLayout(controlLayout);
|
||||||
cheatsTab->setLayout(cheatsLayout);
|
cheatsTab->setLayout(cheatsLayout);
|
||||||
@ -464,6 +468,8 @@ void CheatsPatches::onSaveButtonClicked() {
|
|||||||
} else {
|
} else {
|
||||||
QMessageBox::information(this, tr("Success"), tr("Options saved successfully."));
|
QMessageBox::information(this, tr("Success"), tr("Options saved successfully."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
QCheckBox* CheatsPatches::findCheckBoxByName(const QString& name) {
|
QCheckBox* CheatsPatches::findCheckBoxByName(const QString& name) {
|
||||||
|
@ -146,14 +146,14 @@ void CheckUpdate::CheckForUpdates(const bool showMessage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString currentRev = (updateChannel == "Nightly")
|
QString currentRev = (updateChannel == "Nightly")
|
||||||
? QString::fromStdString(Common::g_scm_rev).left(7)
|
? QString::fromStdString(Common::g_scm_rev)
|
||||||
: "v." + QString::fromStdString(Common::VERSION);
|
: "v." + QString::fromStdString(Common::VERSION);
|
||||||
QString currentDate = Common::g_scm_date;
|
QString currentDate = Common::g_scm_date;
|
||||||
|
|
||||||
QDateTime dateTime = QDateTime::fromString(latestDate, Qt::ISODate);
|
QDateTime dateTime = QDateTime::fromString(latestDate, Qt::ISODate);
|
||||||
latestDate = dateTime.isValid() ? dateTime.toString("yyyy-MM-dd HH:mm:ss") : "Unknown date";
|
latestDate = dateTime.isValid() ? dateTime.toString("yyyy-MM-dd HH:mm:ss") : "Unknown date";
|
||||||
|
|
||||||
if (latestRev == currentRev) {
|
if (latestRev == currentRev.left(7)) {
|
||||||
if (showMessage) {
|
if (showMessage) {
|
||||||
QMessageBox::information(this, tr("Auto Updater"),
|
QMessageBox::information(this, tr("Auto Updater"),
|
||||||
tr("Your version is already up to date!"));
|
tr("Your version is already up to date!"));
|
||||||
@ -190,7 +190,7 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
|
|||||||
QString("<p><b><br>" + tr("Update Channel") + ": </b>" + updateChannel + "<br><b>" +
|
QString("<p><b><br>" + tr("Update Channel") + ": </b>" + updateChannel + "<br><b>" +
|
||||||
tr("Current Version") + ":</b> %1 (%2)<br><b>" + tr("Latest Version") +
|
tr("Current Version") + ":</b> %1 (%2)<br><b>" + tr("Latest Version") +
|
||||||
":</b> %3 (%4)</p><p>" + tr("Do you want to update?") + "</p>")
|
":</b> %3 (%4)</p><p>" + tr("Do you want to update?") + "</p>")
|
||||||
.arg(currentRev, currentDate, latestRev, latestDate);
|
.arg(currentRev.left(7), currentDate, latestRev, latestDate);
|
||||||
QLabel* updateLabel = new QLabel(updateText, this);
|
QLabel* updateLabel = new QLabel(updateText, this);
|
||||||
layout->addWidget(updateLabel);
|
layout->addWidget(updateLabel);
|
||||||
|
|
||||||
|
@ -38,17 +38,18 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
|||||||
|
|
||||||
void GameGridFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow,
|
void GameGridFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow,
|
||||||
int previousColumn) {
|
int previousColumn) {
|
||||||
cellClicked = true;
|
|
||||||
crtRow = currentRow;
|
crtRow = currentRow;
|
||||||
crtColumn = currentColumn;
|
crtColumn = currentColumn;
|
||||||
columnCnt = this->columnCount();
|
columnCnt = this->columnCount();
|
||||||
|
|
||||||
auto itemID = (crtRow * columnCnt) + currentColumn;
|
auto itemID = (crtRow * columnCnt) + currentColumn;
|
||||||
if (itemID > m_game_info->m_games.count() - 1) {
|
if (itemID > m_game_info->m_games.count() - 1) {
|
||||||
|
cellClicked = false;
|
||||||
validCellSelected = false;
|
validCellSelected = false;
|
||||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cellClicked = true;
|
||||||
validCellSelected = true;
|
validCellSelected = true;
|
||||||
SetGridBackgroundImage(crtRow, crtColumn);
|
SetGridBackgroundImage(crtRow, crtColumn);
|
||||||
auto snd0Path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path.string());
|
auto snd0Path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path.string());
|
||||||
|
@ -69,7 +69,7 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
|||||||
ListSortedAsc = true;
|
ListSortedAsc = true;
|
||||||
}
|
}
|
||||||
this->clearContents();
|
this->clearContents();
|
||||||
PopulateGameList();
|
PopulateGameList(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) {
|
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) {
|
||||||
@ -103,7 +103,7 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
|
|||||||
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
|
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListFrame::PopulateGameList() {
|
void GameListFrame::PopulateGameList(bool isInitialPopulation) {
|
||||||
// Do not show status column if it is not enabled
|
// Do not show status column if it is not enabled
|
||||||
this->setColumnHidden(2, !Config::getCompatibilityEnabled());
|
this->setColumnHidden(2, !Config::getCompatibilityEnabled());
|
||||||
this->setColumnHidden(6, !Config::GetLoadGameSizeEnabled());
|
this->setColumnHidden(6, !Config::GetLoadGameSizeEnabled());
|
||||||
@ -111,6 +111,11 @@ void GameListFrame::PopulateGameList() {
|
|||||||
this->setRowCount(m_game_info->m_games.size());
|
this->setRowCount(m_game_info->m_games.size());
|
||||||
ResizeIcons(icon_size);
|
ResizeIcons(icon_size);
|
||||||
|
|
||||||
|
if (isInitialPopulation) {
|
||||||
|
SortNameAscending(1); // Column 1 = Name
|
||||||
|
ResizeIcons(icon_size);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < m_game_info->m_games.size(); i++) {
|
for (int i = 0; i < m_game_info->m_games.size(); i++) {
|
||||||
SetTableItem(i, 1, QString::fromStdString(m_game_info->m_games[i].name));
|
SetTableItem(i, 1, QString::fromStdString(m_game_info->m_games[i].name));
|
||||||
SetTableItem(i, 3, QString::fromStdString(m_game_info->m_games[i].serial));
|
SetTableItem(i, 3, QString::fromStdString(m_game_info->m_games[i].serial));
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // std::transform
|
||||||
|
#include <cctype> // std::tolower
|
||||||
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
@ -43,7 +46,7 @@ private:
|
|||||||
bool ListSortedAsc = true;
|
bool ListSortedAsc = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void PopulateGameList();
|
void PopulateGameList(bool isInitialPopulation = true);
|
||||||
void ResizeIcons(int iconSize);
|
void ResizeIcons(int iconSize);
|
||||||
|
|
||||||
QImage backgroundImage;
|
QImage backgroundImage;
|
||||||
@ -65,8 +68,12 @@ public:
|
|||||||
|
|
||||||
static bool CompareStringsAscending(GameInfo a, GameInfo b, int columnIndex) {
|
static bool CompareStringsAscending(GameInfo a, GameInfo b, int columnIndex) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
case 1:
|
case 1: {
|
||||||
return a.name < b.name;
|
std::string name_a = a.name, name_b = b.name;
|
||||||
|
std::transform(name_a.begin(), name_a.end(), name_a.begin(), ::tolower);
|
||||||
|
std::transform(name_b.begin(), name_b.end(), name_b.begin(), ::tolower);
|
||||||
|
return name_a < name_b;
|
||||||
|
}
|
||||||
case 2:
|
case 2:
|
||||||
return a.compatibility.status < b.compatibility.status;
|
return a.compatibility.status < b.compatibility.status;
|
||||||
case 3:
|
case 3:
|
||||||
@ -90,8 +97,12 @@ public:
|
|||||||
|
|
||||||
static bool CompareStringsDescending(GameInfo a, GameInfo b, int columnIndex) {
|
static bool CompareStringsDescending(GameInfo a, GameInfo b, int columnIndex) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
case 1:
|
case 1: {
|
||||||
return a.name > b.name;
|
std::string name_a = a.name, name_b = b.name;
|
||||||
|
std::transform(name_a.begin(), name_a.end(), name_a.begin(), ::tolower);
|
||||||
|
std::transform(name_b.begin(), name_b.end(), name_b.begin(), ::tolower);
|
||||||
|
return name_a > name_b;
|
||||||
|
}
|
||||||
case 2:
|
case 2:
|
||||||
return a.compatibility.status > b.compatibility.status;
|
return a.compatibility.status > b.compatibility.status;
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -41,8 +41,8 @@ public:
|
|||||||
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
|
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not show the menu if an item is selected
|
// Do not show the menu if no item is selected
|
||||||
if (itemID == -1) {
|
if (itemID < 0 || itemID >= m_games.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +52,12 @@ public:
|
|||||||
// "Open Folder..." submenu
|
// "Open Folder..." submenu
|
||||||
QMenu* openFolderMenu = new QMenu(tr("Open Folder..."), widget);
|
QMenu* openFolderMenu = new QMenu(tr("Open Folder..."), widget);
|
||||||
QAction* openGameFolder = new QAction(tr("Open Game Folder"), widget);
|
QAction* openGameFolder = new QAction(tr("Open Game Folder"), widget);
|
||||||
|
QAction* openUpdateFolder = new QAction(tr("Open Update Folder"), widget);
|
||||||
QAction* openSaveDataFolder = new QAction(tr("Open Save Data Folder"), widget);
|
QAction* openSaveDataFolder = new QAction(tr("Open Save Data Folder"), widget);
|
||||||
QAction* openLogFolder = new QAction(tr("Open Log Folder"), widget);
|
QAction* openLogFolder = new QAction(tr("Open Log Folder"), widget);
|
||||||
|
|
||||||
openFolderMenu->addAction(openGameFolder);
|
openFolderMenu->addAction(openGameFolder);
|
||||||
|
openFolderMenu->addAction(openUpdateFolder);
|
||||||
openFolderMenu->addAction(openSaveDataFolder);
|
openFolderMenu->addAction(openSaveDataFolder);
|
||||||
openFolderMenu->addAction(openLogFolder);
|
openFolderMenu->addAction(openLogFolder);
|
||||||
|
|
||||||
@ -87,10 +89,12 @@ public:
|
|||||||
QMenu* deleteMenu = new QMenu(tr("Delete..."), widget);
|
QMenu* deleteMenu = new QMenu(tr("Delete..."), widget);
|
||||||
QAction* deleteGame = new QAction(tr("Delete Game"), widget);
|
QAction* deleteGame = new QAction(tr("Delete Game"), widget);
|
||||||
QAction* deleteUpdate = new QAction(tr("Delete Update"), widget);
|
QAction* deleteUpdate = new QAction(tr("Delete Update"), widget);
|
||||||
|
QAction* deleteSaveData = new QAction(tr("Delete Save Data"), widget);
|
||||||
QAction* deleteDLC = new QAction(tr("Delete DLC"), widget);
|
QAction* deleteDLC = new QAction(tr("Delete DLC"), widget);
|
||||||
|
|
||||||
deleteMenu->addAction(deleteGame);
|
deleteMenu->addAction(deleteGame);
|
||||||
deleteMenu->addAction(deleteUpdate);
|
deleteMenu->addAction(deleteUpdate);
|
||||||
|
deleteMenu->addAction(deleteSaveData);
|
||||||
deleteMenu->addAction(deleteDLC);
|
deleteMenu->addAction(deleteDLC);
|
||||||
|
|
||||||
menu.addMenu(deleteMenu);
|
menu.addMenu(deleteMenu);
|
||||||
@ -122,6 +126,18 @@ public:
|
|||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath));
|
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selected == openUpdateFolder) {
|
||||||
|
QString open_update_path;
|
||||||
|
Common::FS::PathToQString(open_update_path, m_games[itemID].path);
|
||||||
|
open_update_path += "-UPDATE";
|
||||||
|
if (!std::filesystem::exists(Common::FS::PathFromQString(open_update_path))) {
|
||||||
|
QMessageBox::critical(nullptr, tr("Error"),
|
||||||
|
QString(tr("This game has no update folder to open!")));
|
||||||
|
} else {
|
||||||
|
QDesktopServices::openUrl(QUrl::fromLocalFile(open_update_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (selected == openSaveDataFolder) {
|
if (selected == openSaveDataFolder) {
|
||||||
QString userPath;
|
QString userPath;
|
||||||
Common::FS::PathToQString(userPath,
|
Common::FS::PathToQString(userPath,
|
||||||
@ -143,7 +159,7 @@ public:
|
|||||||
PSF psf;
|
PSF psf;
|
||||||
std::filesystem::path game_folder_path = m_games[itemID].path;
|
std::filesystem::path game_folder_path = m_games[itemID].path;
|
||||||
std::filesystem::path game_update_path = game_folder_path;
|
std::filesystem::path game_update_path = game_folder_path;
|
||||||
game_update_path += "UPDATE";
|
game_update_path += "-UPDATE";
|
||||||
if (std::filesystem::exists(game_update_path)) {
|
if (std::filesystem::exists(game_update_path)) {
|
||||||
game_folder_path = game_update_path;
|
game_folder_path = game_update_path;
|
||||||
}
|
}
|
||||||
@ -238,6 +254,11 @@ public:
|
|||||||
QString trophyPath, gameTrpPath;
|
QString trophyPath, gameTrpPath;
|
||||||
Common::FS::PathToQString(trophyPath, m_games[itemID].serial);
|
Common::FS::PathToQString(trophyPath, m_games[itemID].serial);
|
||||||
Common::FS::PathToQString(gameTrpPath, m_games[itemID].path);
|
Common::FS::PathToQString(gameTrpPath, m_games[itemID].path);
|
||||||
|
auto game_update_path = Common::FS::PathFromQString(gameTrpPath);
|
||||||
|
game_update_path += "-UPDATE";
|
||||||
|
if (std::filesystem::exists(game_update_path)) {
|
||||||
|
Common::FS::PathToQString(gameTrpPath, game_update_path);
|
||||||
|
}
|
||||||
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
|
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
|
||||||
trophyViewer->show();
|
trophyViewer->show();
|
||||||
connect(widget->parent(), &QWidget::destroyed, trophyViewer,
|
connect(widget->parent(), &QWidget::destroyed, trophyViewer,
|
||||||
@ -335,14 +356,18 @@ public:
|
|||||||
clipboard->setText(combinedText);
|
clipboard->setText(combinedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC) {
|
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC ||
|
||||||
|
selected == deleteSaveData) {
|
||||||
bool error = false;
|
bool error = false;
|
||||||
QString folder_path, game_update_path, dlc_path;
|
QString folder_path, game_update_path, dlc_path, save_data_path;
|
||||||
Common::FS::PathToQString(folder_path, m_games[itemID].path);
|
Common::FS::PathToQString(folder_path, m_games[itemID].path);
|
||||||
game_update_path = folder_path + "-UPDATE";
|
game_update_path = folder_path + "-UPDATE";
|
||||||
Common::FS::PathToQString(
|
Common::FS::PathToQString(
|
||||||
dlc_path, Config::getAddonInstallDir() /
|
dlc_path, Config::getAddonInstallDir() /
|
||||||
Common::FS::PathFromQString(folder_path).parent_path().filename());
|
Common::FS::PathFromQString(folder_path).parent_path().filename());
|
||||||
|
Common::FS::PathToQString(save_data_path,
|
||||||
|
Common::FS::GetUserPath(Common::FS::PathType::UserDir) /
|
||||||
|
"savedata/1" / m_games[itemID].serial);
|
||||||
QString message_type = tr("Game");
|
QString message_type = tr("Game");
|
||||||
|
|
||||||
if (selected == deleteUpdate) {
|
if (selected == deleteUpdate) {
|
||||||
@ -363,6 +388,15 @@ public:
|
|||||||
folder_path = dlc_path;
|
folder_path = dlc_path;
|
||||||
message_type = tr("DLC");
|
message_type = tr("DLC");
|
||||||
}
|
}
|
||||||
|
} else if (selected == deleteSaveData) {
|
||||||
|
if (!std::filesystem::exists(Common::FS::PathFromQString(save_data_path))) {
|
||||||
|
QMessageBox::critical(nullptr, tr("Error"),
|
||||||
|
QString(tr("This game has no save data to delete!")));
|
||||||
|
error = true;
|
||||||
|
} else {
|
||||||
|
folder_path = save_data_path;
|
||||||
|
message_type = tr("Save Data");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!error) {
|
if (!error) {
|
||||||
QString gameName = QString::fromStdString(m_games[itemID].name);
|
QString gameName = QString::fromStdString(m_games[itemID].name);
|
||||||
@ -374,7 +408,10 @@ public:
|
|||||||
QMessageBox::Yes | QMessageBox::No);
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
if (reply == QMessageBox::Yes) {
|
if (reply == QMessageBox::Yes) {
|
||||||
dir.removeRecursively();
|
dir.removeRecursively();
|
||||||
widget->removeRow(itemID);
|
if (selected == deleteGame) {
|
||||||
|
widget->removeRow(itemID);
|
||||||
|
m_games.removeAt(itemID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 <QCheckBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
@ -15,10 +16,11 @@
|
|||||||
#include "install_dir_select.h"
|
#include "install_dir_select.h"
|
||||||
|
|
||||||
InstallDirSelect::InstallDirSelect() : selected_dir() {
|
InstallDirSelect::InstallDirSelect() : selected_dir() {
|
||||||
selected_dir = Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
|
auto install_dirs = Config::getGameInstallDirs();
|
||||||
|
selected_dir = install_dirs.empty() ? "" : install_dirs.front();
|
||||||
|
|
||||||
if (!Config::getGameInstallDirs().empty() && Config::getGameInstallDirs().size() == 1) {
|
if (!install_dirs.empty() && install_dirs.size() == 1) {
|
||||||
reject();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto layout = new QVBoxLayout(this);
|
auto layout = new QVBoxLayout(this);
|
||||||
@ -53,6 +55,14 @@ QWidget* InstallDirSelect::SetupInstallDirList() {
|
|||||||
|
|
||||||
vlayout->addWidget(m_path_list);
|
vlayout->addWidget(m_path_list);
|
||||||
|
|
||||||
|
auto checkbox = new QCheckBox(tr("Install All Queued to Selected Folder"));
|
||||||
|
connect(checkbox, &QCheckBox::toggled, this, &InstallDirSelect::setUseForAllQueued);
|
||||||
|
vlayout->addWidget(checkbox);
|
||||||
|
|
||||||
|
auto checkbox2 = new QCheckBox(tr("Delete PKG File on Install"));
|
||||||
|
connect(checkbox2, &QCheckBox::toggled, this, &InstallDirSelect::setDeleteFileOnInstall);
|
||||||
|
vlayout->addWidget(checkbox2);
|
||||||
|
|
||||||
group->setLayout(vlayout);
|
group->setLayout(vlayout);
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
@ -66,6 +76,14 @@ void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstallDirSelect::setUseForAllQueued(bool enabled) {
|
||||||
|
use_for_all_queued = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallDirSelect::setDeleteFileOnInstall(bool enabled) {
|
||||||
|
delete_file_on_install = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
QWidget* InstallDirSelect::SetupDialogActions() {
|
QWidget* InstallDirSelect::SetupDialogActions() {
|
||||||
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
|
||||||
|
@ -22,9 +22,21 @@ public:
|
|||||||
return selected_dir;
|
return selected_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool useForAllQueued() {
|
||||||
|
return use_for_all_queued;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool deleteFileOnInstall() {
|
||||||
|
return delete_file_on_install;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* SetupInstallDirList();
|
QWidget* SetupInstallDirList();
|
||||||
QWidget* SetupDialogActions();
|
QWidget* SetupDialogActions();
|
||||||
void setSelectedDirectory(QListWidgetItem* item);
|
void setSelectedDirectory(QListWidgetItem* item);
|
||||||
|
void setDeleteFileOnInstall(bool enabled);
|
||||||
|
void setUseForAllQueued(bool enabled);
|
||||||
std::filesystem::path selected_dir;
|
std::filesystem::path selected_dir;
|
||||||
|
bool delete_file_on_install = false;
|
||||||
|
bool use_for_all_queued = false;
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,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 game_path;
|
std::string game_path;
|
||||||
|
std::vector<std::string> game_args{};
|
||||||
|
|
||||||
// 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 = {
|
||||||
@ -43,6 +44,9 @@ int main(int argc, char* argv[]) {
|
|||||||
" No arguments: Opens the GUI.\n"
|
" No arguments: Opens the GUI.\n"
|
||||||
" -g, --game <path|ID> Specify <eboot.bin or elf path> or "
|
" -g, --game <path|ID> Specify <eboot.bin or elf path> or "
|
||||||
"<game ID (CUSAXXXXX)> to launch\n"
|
"<game ID (CUSAXXXXX)> to launch\n"
|
||||||
|
" -- ... Parameters passed to the game ELF. "
|
||||||
|
"Needs to be at the end of the line, and everything after \"--\" is a "
|
||||||
|
"game argument.\n"
|
||||||
" -p, --patch <patch_file> Apply specified patch file\n"
|
" -p, --patch <patch_file> Apply specified patch file\n"
|
||||||
" -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 "
|
||||||
@ -131,6 +135,20 @@ int main(int argc, char* argv[]) {
|
|||||||
// Assume the last argument is the game file if not specified via -g/--game
|
// Assume the last argument is the game file if not specified via -g/--game
|
||||||
game_path = argv[i];
|
game_path = argv[i];
|
||||||
has_game_argument = true;
|
has_game_argument = true;
|
||||||
|
} else if (std::string(argv[i]) == "--") {
|
||||||
|
if (i + 1 == argc) {
|
||||||
|
std::cerr << "Warning: -- is set, but no game arguments are added!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int j = i + 1; j < argc; j++) {
|
||||||
|
game_args.push_back(argv[j]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (i + 1 < argc && std::string(argv[i + 1]) == "--") {
|
||||||
|
if (!has_game_argument) {
|
||||||
|
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;
|
||||||
@ -181,7 +199,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Run the emulator with the resolved game path
|
// Run the emulator with the resolved game path
|
||||||
Core::Emulator emulator;
|
Core::Emulator emulator;
|
||||||
emulator.Run(game_file_path.string());
|
emulator.Run(game_file_path.string(), game_args);
|
||||||
if (!show_gui) {
|
if (!show_gui) {
|
||||||
return 0; // Exit after running the emulator without showing the GUI
|
return 0; // Exit after running the emulator without showing the GUI
|
||||||
}
|
}
|
||||||
|
@ -251,6 +251,12 @@ void MainWindow::CreateConnects() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->shadFolderAct, &QAction::triggered, this, [this]() {
|
||||||
|
QString userPath;
|
||||||
|
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
||||||
|
QDesktopServices::openUrl(QUrl::fromLocalFile(userPath));
|
||||||
|
});
|
||||||
|
|
||||||
connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame);
|
connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame);
|
||||||
connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this,
|
connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this,
|
||||||
&MainWindow::StartGame);
|
&MainWindow::StartGame);
|
||||||
@ -729,9 +735,20 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto category = psf.GetString("CATEGORY");
|
auto category = psf.GetString("CATEGORY");
|
||||||
InstallDirSelect ids;
|
|
||||||
ids.exec();
|
if (!use_for_all_queued || pkgNum == 1) {
|
||||||
auto game_install_dir = ids.getSelectedDirectory();
|
InstallDirSelect ids;
|
||||||
|
const auto selected = ids.exec();
|
||||||
|
if (selected == QDialog::Rejected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_install_dir = ids.getSelectedDirectory();
|
||||||
|
delete_file_on_install = ids.deleteFileOnInstall();
|
||||||
|
use_for_all_queued = ids.useForAllQueued();
|
||||||
|
}
|
||||||
|
std::filesystem::path game_install_dir = last_install_dir;
|
||||||
|
|
||||||
auto game_folder_path = game_install_dir / pkg.GetTitleID();
|
auto game_folder_path = game_install_dir / pkg.GetTitleID();
|
||||||
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
||||||
bool use_game_update = pkgType.contains("PATCH") && Config::getSeparateUpdateEnabled();
|
bool use_game_update = pkgType.contains("PATCH") && Config::getSeparateUpdateEnabled();
|
||||||
@ -883,8 +900,14 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||||||
if (pkgNum == nPkg) {
|
if (pkgNum == nPkg) {
|
||||||
QString path;
|
QString path;
|
||||||
Common::FS::PathToQString(path, game_install_dir);
|
Common::FS::PathToQString(path, game_install_dir);
|
||||||
|
QIcon windowIcon(
|
||||||
|
Common::FS::PathToUTF8String(game_folder_path / "sce_sys/icon0.png")
|
||||||
|
.c_str());
|
||||||
QMessageBox extractMsgBox(this);
|
QMessageBox extractMsgBox(this);
|
||||||
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
||||||
|
if (!windowIcon.isNull()) {
|
||||||
|
extractMsgBox.setWindowIcon(windowIcon);
|
||||||
|
}
|
||||||
extractMsgBox.setText(
|
extractMsgBox.setText(
|
||||||
QString(tr("Game successfully installed at %1")).arg(path));
|
QString(tr("Game successfully installed at %1")).arg(path));
|
||||||
extractMsgBox.addButton(QMessageBox::Ok);
|
extractMsgBox.addButton(QMessageBox::Ok);
|
||||||
@ -898,6 +921,9 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||||||
});
|
});
|
||||||
extractMsgBox.exec();
|
extractMsgBox.exec();
|
||||||
}
|
}
|
||||||
|
if (delete_file_on_install) {
|
||||||
|
std::filesystem::remove(file);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
connect(&dialog, &QProgressDialog::canceled, [&]() { futureWatcher.cancel(); });
|
connect(&dialog, &QProgressDialog::canceled, [&]() { futureWatcher.cancel(); });
|
||||||
connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
|
connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
|
||||||
@ -992,6 +1018,7 @@ QIcon MainWindow::RecolorIcon(const QIcon& icon, bool isWhite) {
|
|||||||
void MainWindow::SetUiIcons(bool isWhite) {
|
void MainWindow::SetUiIcons(bool isWhite) {
|
||||||
ui->bootInstallPkgAct->setIcon(RecolorIcon(ui->bootInstallPkgAct->icon(), isWhite));
|
ui->bootInstallPkgAct->setIcon(RecolorIcon(ui->bootInstallPkgAct->icon(), isWhite));
|
||||||
ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite));
|
ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite));
|
||||||
|
ui->shadFolderAct->setIcon(RecolorIcon(ui->shadFolderAct->icon(), isWhite));
|
||||||
ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite));
|
ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite));
|
||||||
#ifdef ENABLE_UPDATER
|
#ifdef ENABLE_UPDATER
|
||||||
ui->updaterAct->setIcon(RecolorIcon(ui->updaterAct->icon(), isWhite));
|
ui->updaterAct->setIcon(RecolorIcon(ui->updaterAct->icon(), isWhite));
|
||||||
|
@ -123,4 +123,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
|
std::filesystem::path last_install_dir = "";
|
||||||
|
bool delete_file_on_install = false;
|
||||||
|
bool use_for_all_queued = false;
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ public:
|
|||||||
QAction* bootInstallPkgAct;
|
QAction* bootInstallPkgAct;
|
||||||
QAction* bootGameAct;
|
QAction* bootGameAct;
|
||||||
QAction* addElfFolderAct;
|
QAction* addElfFolderAct;
|
||||||
|
QAction* shadFolderAct;
|
||||||
QAction* exitAct;
|
QAction* exitAct;
|
||||||
QAction* showGameListAct;
|
QAction* showGameListAct;
|
||||||
QAction* refreshGameListAct;
|
QAction* refreshGameListAct;
|
||||||
@ -89,6 +90,9 @@ public:
|
|||||||
addElfFolderAct = new QAction(MainWindow);
|
addElfFolderAct = new QAction(MainWindow);
|
||||||
addElfFolderAct->setObjectName("addElfFolderAct");
|
addElfFolderAct->setObjectName("addElfFolderAct");
|
||||||
addElfFolderAct->setIcon(QIcon(":images/folder_icon.png"));
|
addElfFolderAct->setIcon(QIcon(":images/folder_icon.png"));
|
||||||
|
shadFolderAct = new QAction(MainWindow);
|
||||||
|
shadFolderAct->setObjectName("shadFolderAct");
|
||||||
|
shadFolderAct->setIcon(QIcon(":images/folder_icon.png"));
|
||||||
exitAct = new QAction(MainWindow);
|
exitAct = new QAction(MainWindow);
|
||||||
exitAct->setObjectName("exitAct");
|
exitAct->setObjectName("exitAct");
|
||||||
exitAct->setIcon(QIcon(":images/exit_icon.png"));
|
exitAct->setIcon(QIcon(":images/exit_icon.png"));
|
||||||
@ -274,7 +278,9 @@ public:
|
|||||||
menuBar->addAction(menuHelp->menuAction());
|
menuBar->addAction(menuHelp->menuAction());
|
||||||
menuFile->addAction(bootInstallPkgAct);
|
menuFile->addAction(bootInstallPkgAct);
|
||||||
menuFile->addAction(bootGameAct);
|
menuFile->addAction(bootGameAct);
|
||||||
|
menuFile->addSeparator();
|
||||||
menuFile->addAction(addElfFolderAct);
|
menuFile->addAction(addElfFolderAct);
|
||||||
|
menuFile->addAction(shadFolderAct);
|
||||||
menuFile->addSeparator();
|
menuFile->addSeparator();
|
||||||
menuFile->addAction(menuRecent->menuAction());
|
menuFile->addAction(menuRecent->menuAction());
|
||||||
menuFile->addSeparator();
|
menuFile->addSeparator();
|
||||||
@ -333,6 +339,8 @@ public:
|
|||||||
"MainWindow", "Install application from a .pkg file", nullptr));
|
"MainWindow", "Install application from a .pkg file", nullptr));
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
menuRecent->setTitle(QCoreApplication::translate("MainWindow", "Recent Games", nullptr));
|
menuRecent->setTitle(QCoreApplication::translate("MainWindow", "Recent Games", nullptr));
|
||||||
|
shadFolderAct->setText(
|
||||||
|
QCoreApplication::translate("MainWindow", "Open shadPS4 Folder", nullptr));
|
||||||
exitAct->setText(QCoreApplication::translate("MainWindow", "Exit", nullptr));
|
exitAct->setText(QCoreApplication::translate("MainWindow", "Exit", nullptr));
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
exitAct->setToolTip(QCoreApplication::translate("MainWindow", "Exit shadPS4", nullptr));
|
exitAct->setToolTip(QCoreApplication::translate("MainWindow", "Exit shadPS4", nullptr));
|
||||||
|
@ -65,6 +65,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
: QDialog(parent), ui(new Ui::SettingsDialog) {
|
: QDialog(parent), ui(new Ui::SettingsDialog) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->tabWidgetSettings->setUsesScrollButtons(false);
|
ui->tabWidgetSettings->setUsesScrollButtons(false);
|
||||||
|
|
||||||
initialHeight = this->height();
|
initialHeight = this->height();
|
||||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
|
||||||
@ -150,7 +151,6 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
ui->updaterGroupBox->setVisible(false);
|
ui->updaterGroupBox->setVisible(false);
|
||||||
ui->GUIgroupBox->setMaximumSize(265, 16777215);
|
|
||||||
#endif
|
#endif
|
||||||
connect(ui->updateCompatibilityButton, &QPushButton::clicked, this,
|
connect(ui->updateCompatibilityButton, &QPushButton::clicked, this,
|
||||||
[this, parent, m_compat_info]() {
|
[this, parent, m_compat_info]() {
|
||||||
@ -169,6 +169,11 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gui TAB
|
||||||
|
{
|
||||||
|
connect(ui->chooseHomeTabComboBox, &QComboBox::currentTextChanged, this,
|
||||||
|
[](const QString& hometab) { Config::setChooseHomeTab(hometab.toStdString()); });
|
||||||
|
}
|
||||||
// Input TAB
|
// Input TAB
|
||||||
{
|
{
|
||||||
connect(ui->hideCursorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(ui->hideCursorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
@ -202,6 +207,21 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
delete selected_item;
|
delete selected_item;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->browseButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
const auto save_data_path = Config::GetSaveDataPath();
|
||||||
|
QString initial_path;
|
||||||
|
Common::FS::PathToQString(initial_path, save_data_path);
|
||||||
|
|
||||||
|
QString save_data_path_string =
|
||||||
|
QFileDialog::getExistingDirectory(this, tr("Directory to save data"), initial_path);
|
||||||
|
|
||||||
|
auto file_path = Common::FS::PathFromQString(save_data_path_string);
|
||||||
|
if (!file_path.empty()) {
|
||||||
|
Config::setSaveDataPath(file_path);
|
||||||
|
ui->currentSaveDataPath->setText(save_data_path_string);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG TAB
|
// DEBUG TAB
|
||||||
@ -231,7 +251,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
#ifdef ENABLE_UPDATER
|
#ifdef ENABLE_UPDATER
|
||||||
ui->updaterGroupBox->installEventFilter(this);
|
ui->updaterGroupBox->installEventFilter(this);
|
||||||
#endif
|
#endif
|
||||||
ui->GUIgroupBox->installEventFilter(this);
|
ui->GUIMusicGroupBox->installEventFilter(this);
|
||||||
ui->disableTrophycheckBox->installEventFilter(this);
|
ui->disableTrophycheckBox->installEventFilter(this);
|
||||||
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
||||||
ui->checkCompatibilityOnStartupCheckBox->installEventFilter(this);
|
ui->checkCompatibilityOnStartupCheckBox->installEventFilter(this);
|
||||||
@ -256,11 +276,20 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||||||
ui->addFolderButton->installEventFilter(this);
|
ui->addFolderButton->installEventFilter(this);
|
||||||
ui->removeFolderButton->installEventFilter(this);
|
ui->removeFolderButton->installEventFilter(this);
|
||||||
|
|
||||||
|
ui->saveDataGroupBox->installEventFilter(this);
|
||||||
|
ui->currentSaveDataPath->installEventFilter(this);
|
||||||
|
ui->browseButton->installEventFilter(this);
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
ui->debugDump->installEventFilter(this);
|
ui->debugDump->installEventFilter(this);
|
||||||
ui->vkValidationCheckBox->installEventFilter(this);
|
ui->vkValidationCheckBox->installEventFilter(this);
|
||||||
ui->vkSyncValidationCheckBox->installEventFilter(this);
|
ui->vkSyncValidationCheckBox->installEventFilter(this);
|
||||||
ui->rdocCheckBox->installEventFilter(this);
|
ui->rdocCheckBox->installEventFilter(this);
|
||||||
|
ui->crashDiagnosticsCheckBox->installEventFilter(this);
|
||||||
|
ui->guestMarkersCheckBox->installEventFilter(this);
|
||||||
|
ui->hostMarkersCheckBox->installEventFilter(this);
|
||||||
|
ui->collectShaderCheckBox->installEventFilter(this);
|
||||||
|
ui->copyGPUBuffersCheckBox->installEventFilter(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,6 +315,11 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
const QVector<int> languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 24, 29, 5, 0, 9,
|
const QVector<int> languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 24, 29, 5, 0, 9,
|
||||||
15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 30, 28};
|
15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 30, 28};
|
||||||
|
|
||||||
|
const auto save_data_path = Config::GetSaveDataPath();
|
||||||
|
QString save_data_path_string;
|
||||||
|
Common::FS::PathToQString(save_data_path_string, save_data_path);
|
||||||
|
ui->currentSaveDataPath->setText(save_data_path_string);
|
||||||
|
|
||||||
ui->consoleLanguageComboBox->setCurrentIndex(
|
ui->consoleLanguageComboBox->setCurrentIndex(
|
||||||
std::distance(languageIndexes.begin(),
|
std::distance(languageIndexes.begin(),
|
||||||
std::find(languageIndexes.begin(), languageIndexes.end(),
|
std::find(languageIndexes.begin(), languageIndexes.end(),
|
||||||
@ -331,6 +365,15 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
ui->vkSyncValidationCheckBox->setChecked(
|
ui->vkSyncValidationCheckBox->setChecked(
|
||||||
toml::find_or<bool>(data, "Vulkan", "validation_sync", false));
|
toml::find_or<bool>(data, "Vulkan", "validation_sync", false));
|
||||||
ui->rdocCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "rdocEnable", false));
|
ui->rdocCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "rdocEnable", false));
|
||||||
|
ui->crashDiagnosticsCheckBox->setChecked(
|
||||||
|
toml::find_or<bool>(data, "Vulkan", "crashDiagnostic", false));
|
||||||
|
ui->guestMarkersCheckBox->setChecked(
|
||||||
|
toml::find_or<bool>(data, "Vulkan", "guestMarkers", false));
|
||||||
|
ui->hostMarkersCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "hostMarkers", false));
|
||||||
|
ui->copyGPUBuffersCheckBox->setChecked(
|
||||||
|
toml::find_or<bool>(data, "GPU", "copyGPUBuffers", false));
|
||||||
|
ui->collectShaderCheckBox->setChecked(
|
||||||
|
toml::find_or<bool>(data, "Debug", "CollectShader", false));
|
||||||
ui->enableCompatibilityCheckBox->setChecked(
|
ui->enableCompatibilityCheckBox->setChecked(
|
||||||
toml::find_or<bool>(data, "General", "compatibilityEnabled", false));
|
toml::find_or<bool>(data, "General", "compatibilityEnabled", false));
|
||||||
ui->checkCompatibilityOnStartupCheckBox->setChecked(
|
ui->checkCompatibilityOnStartupCheckBox->setChecked(
|
||||||
@ -349,6 +392,15 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
ui->updateComboBox->setCurrentText(QString::fromStdString(updateChannel));
|
ui->updateComboBox->setCurrentText(QString::fromStdString(updateChannel));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::string chooseHomeTab = toml::find_or<std::string>(data, "General", "chooseHomeTab", "");
|
||||||
|
ui->chooseHomeTabComboBox->setCurrentText(QString::fromStdString(chooseHomeTab));
|
||||||
|
QStringList tabNames = {tr("General"), tr("GUI"), tr("Graphics"), tr("User"),
|
||||||
|
tr("Input"), tr("Paths"), tr("Debug")};
|
||||||
|
QString chooseHomeTabQString = QString::fromStdString(chooseHomeTab);
|
||||||
|
int indexTab = tabNames.indexOf(chooseHomeTabQString);
|
||||||
|
indexTab = (indexTab == -1) ? 0 : indexTab;
|
||||||
|
ui->tabWidgetSettings->setCurrentIndex(indexTab);
|
||||||
|
|
||||||
QString backButtonBehavior = QString::fromStdString(
|
QString backButtonBehavior = QString::fromStdString(
|
||||||
toml::find_or<std::string>(data, "Input", "backButtonBehavior", "left"));
|
toml::find_or<std::string>(data, "Input", "backButtonBehavior", "left"));
|
||||||
int index = ui->backButtonBehaviorComboBox->findData(backButtonBehavior);
|
int index = ui->backButtonBehaviorComboBox->findData(backButtonBehavior);
|
||||||
@ -452,8 +504,8 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
} else if (elementName == "updaterGroupBox") {
|
} else if (elementName == "updaterGroupBox") {
|
||||||
text = tr("updaterGroupBox");
|
text = tr("updaterGroupBox");
|
||||||
#endif
|
#endif
|
||||||
} else if (elementName == "GUIgroupBox") {
|
} else if (elementName == "GUIMusicGroupBox") {
|
||||||
text = tr("GUIgroupBox");
|
text = tr("GUIMusicGroupBox");
|
||||||
} else if (elementName == "disableTrophycheckBox") {
|
} else if (elementName == "disableTrophycheckBox") {
|
||||||
text = tr("disableTrophycheckBox");
|
text = tr("disableTrophycheckBox");
|
||||||
} else if (elementName == "enableCompatibilityCheckBox") {
|
} else if (elementName == "enableCompatibilityCheckBox") {
|
||||||
@ -497,6 +549,13 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
text = tr("removeFolderButton");
|
text = tr("removeFolderButton");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save Data
|
||||||
|
if (elementName == "saveDataGroupBox" || elementName == "currentSaveDataPath") {
|
||||||
|
text = tr("saveDataBox");
|
||||||
|
} else if (elementName == "browseButton") {
|
||||||
|
text = tr("browseButton");
|
||||||
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
if (elementName == "debugDump") {
|
if (elementName == "debugDump") {
|
||||||
text = tr("debugDump");
|
text = tr("debugDump");
|
||||||
@ -506,6 +565,16 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
text = tr("vkSyncValidationCheckBox");
|
text = tr("vkSyncValidationCheckBox");
|
||||||
} else if (elementName == "rdocCheckBox") {
|
} else if (elementName == "rdocCheckBox") {
|
||||||
text = tr("rdocCheckBox");
|
text = tr("rdocCheckBox");
|
||||||
|
} else if (elementName == "crashDiagnosticsCheckBox") {
|
||||||
|
text = tr("crashDiagnosticsCheckBox");
|
||||||
|
} else if (elementName == "guestMarkersCheckBox") {
|
||||||
|
text = tr("guestMarkersCheckBox");
|
||||||
|
} else if (elementName == "hostMarkersCheckBox") {
|
||||||
|
text = tr("hostMarkersCheckBox");
|
||||||
|
} else if (elementName == "copyGPUBuffersCheckBox") {
|
||||||
|
text = tr("copyGPUBuffersCheckBox");
|
||||||
|
} else if (elementName == "collectShaderCheckBox") {
|
||||||
|
text = tr("collectShaderCheckBox");
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->descriptionText->setText(text.replace("\\n", "\n"));
|
ui->descriptionText->setText(text.replace("\\n", "\n"));
|
||||||
@ -522,22 +591,6 @@ bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) {
|
|||||||
} else {
|
} else {
|
||||||
ui->descriptionText->setText(defaultTextEdit);
|
ui->descriptionText->setText(defaultTextEdit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the text exceeds the size of the box, it will increase the size
|
|
||||||
QRect currentGeometry = this->geometry();
|
|
||||||
int newWidth = currentGeometry.width();
|
|
||||||
|
|
||||||
int documentHeight = ui->descriptionText->document()->size().height();
|
|
||||||
int visibleHeight = ui->descriptionText->viewport()->height();
|
|
||||||
if (documentHeight > visibleHeight) {
|
|
||||||
ui->descriptionText->setMaximumSize(16777215, 110);
|
|
||||||
this->setGeometry(currentGeometry.x(), currentGeometry.y(), newWidth,
|
|
||||||
currentGeometry.height() + 40);
|
|
||||||
} else {
|
|
||||||
ui->descriptionText->setMaximumSize(16777215, 70);
|
|
||||||
this->setGeometry(currentGeometry.x(), currentGeometry.y(), newWidth,
|
|
||||||
initialHeight);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,8 +628,14 @@ void SettingsDialog::UpdateSettings() {
|
|||||||
Config::setVkValidation(ui->vkValidationCheckBox->isChecked());
|
Config::setVkValidation(ui->vkValidationCheckBox->isChecked());
|
||||||
Config::setVkSyncValidation(ui->vkSyncValidationCheckBox->isChecked());
|
Config::setVkSyncValidation(ui->vkSyncValidationCheckBox->isChecked());
|
||||||
Config::setRdocEnabled(ui->rdocCheckBox->isChecked());
|
Config::setRdocEnabled(ui->rdocCheckBox->isChecked());
|
||||||
|
Config::setVkHostMarkersEnabled(ui->hostMarkersCheckBox->isChecked());
|
||||||
|
Config::setVkGuestMarkersEnabled(ui->guestMarkersCheckBox->isChecked());
|
||||||
|
Config::setVkCrashDiagnosticEnabled(ui->crashDiagnosticsCheckBox->isChecked());
|
||||||
|
Config::setCollectShaderForDebug(ui->collectShaderCheckBox->isChecked());
|
||||||
|
Config::setCopyGPUCmdBuffers(ui->copyGPUBuffersCheckBox->isChecked());
|
||||||
Config::setAutoUpdate(ui->updateCheckBox->isChecked());
|
Config::setAutoUpdate(ui->updateCheckBox->isChecked());
|
||||||
Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString());
|
Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString());
|
||||||
|
Config::setChooseHomeTab(ui->chooseHomeTabComboBox->currentText().toStdString());
|
||||||
Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked());
|
Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked());
|
||||||
Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked());
|
Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked());
|
||||||
|
|
||||||
@ -619,4 +678,4 @@ void SettingsDialog::ResetInstallFolders() {
|
|||||||
}
|
}
|
||||||
Config::setGameInstallDirs(settings_install_dirs_config);
|
Config::setGameInstallDirs(settings_install_dirs_config);
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -247,6 +247,10 @@
|
|||||||
<source>Recent Games</source>
|
<source>Recent Games</source>
|
||||||
<translation>الألعاب الأخيرة</translation>
|
<translation>الألعاب الأخيرة</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open shadPS4 Folder</source>
|
||||||
|
<translation>Open shadPS4 Folder</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Exit</source>
|
<source>Exit</source>
|
||||||
<translation>خروج</translation>
|
<translation>خروج</translation>
|
||||||
@ -536,10 +540,18 @@
|
|||||||
<source>Enable Fullscreen</source>
|
<source>Enable Fullscreen</source>
|
||||||
<translation>تمكين ملء الشاشة</translation>
|
<translation>تمكين ملء الشاشة</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Fullscreen Mode</source>
|
||||||
|
<translation>وضع ملء الشاشة</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Enable Separate Update Folder</source>
|
<source>Enable Separate Update Folder</source>
|
||||||
<translation>Enable Separate Update Folder</translation>
|
<translation>Enable Separate Update Folder</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Default tab when opening settings</source>
|
||||||
|
<translation>علامة التبويب الافتراضية عند فتح الإعدادات</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Show Game Size In List</source>
|
<source>Show Game Size In List</source>
|
||||||
<translation>عرض حجم اللعبة في القائمة</translation>
|
<translation>عرض حجم اللعبة في القائمة</translation>
|
||||||
@ -616,6 +628,14 @@
|
|||||||
<source>Graphics</source>
|
<source>Graphics</source>
|
||||||
<translation>الرسومات</translation>
|
<translation>الرسومات</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Gui</source>
|
||||||
|
<translation>واجهة</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>User</source>
|
||||||
|
<translation>مستخدم</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Graphics Device</source>
|
<source>Graphics Device</source>
|
||||||
<translation>جهاز الرسومات</translation>
|
<translation>جهاز الرسومات</translation>
|
||||||
@ -680,6 +700,26 @@
|
|||||||
<source>Enable RenderDoc Debugging</source>
|
<source>Enable RenderDoc Debugging</source>
|
||||||
<translation>RenderDoc تمكين تصحيح أخطاء</translation>
|
<translation>RenderDoc تمكين تصحيح أخطاء</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enable Crash Diagnostics</source>
|
||||||
|
<translation>Enable Crash Diagnostics</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Collect Shaders</source>
|
||||||
|
<translation>Collect Shaders</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Copy GPU Buffers</source>
|
||||||
|
<translation>Copy GPU Buffers</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Host Debug Markers</source>
|
||||||
|
<translation>Host Debug Markers</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Guest Debug Markers</source>
|
||||||
|
<translation>Guest Debug Markers</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Update</source>
|
<source>Update</source>
|
||||||
<translation>تحديث</translation>
|
<translation>تحديث</translation>
|
||||||
@ -700,6 +740,10 @@
|
|||||||
<source>GUI Settings</source>
|
<source>GUI Settings</source>
|
||||||
<translation>إعدادات الواجهة</translation>
|
<translation>إعدادات الواجهة</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Title Music</source>
|
||||||
|
<translation>Title Music</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Disable Trophy Pop-ups</source>
|
<source>Disable Trophy Pop-ups</source>
|
||||||
<translation>Disable Trophy Pop-ups</translation>
|
<translation>Disable Trophy Pop-ups</translation>
|
||||||
@ -801,7 +845,7 @@
|
|||||||
<translation>تحديث: Release: إصدارات رسمية تصدر شهريًا، قد تكون قديمة بعض الشيء، لكنها أكثر استقرارًا واختبارًا. Nightly: إصدارات تطوير تحتوي على أحدث الميزات والإصلاحات، لكنها قد تحتوي على أخطاء وأقل استقرارًا.</translation>
|
<translation>تحديث: Release: إصدارات رسمية تصدر شهريًا، قد تكون قديمة بعض الشيء، لكنها أكثر استقرارًا واختبارًا. Nightly: إصدارات تطوير تحتوي على أحدث الميزات والإصلاحات، لكنها قد تحتوي على أخطاء وأقل استقرارًا.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>GUIgroupBox</source>
|
<source>GUIMusicGroupBox</source>
|
||||||
<translation>تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم.</translation>
|
<translation>تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@ -908,6 +952,26 @@
|
|||||||
<source>rdocCheckBox</source>
|
<source>rdocCheckBox</source>
|
||||||
<translation>تمكين تصحيح RenderDoc:\nإذا تم التمكين، سيوفر المحاكي توافقًا مع Renderdoc لالتقاط وتحليل الإطار الذي يتم عرضه حاليًا.</translation>
|
<translation>تمكين تصحيح RenderDoc:\nإذا تم التمكين، سيوفر المحاكي توافقًا مع Renderdoc لالتقاط وتحليل الإطار الذي يتم عرضه حاليًا.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>collectShaderCheckBox</source>
|
||||||
|
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>crashDiagnosticsCheckBox</source>
|
||||||
|
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>copyGPUBuffersCheckBox</source>
|
||||||
|
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>hostMarkersCheckBox</source>
|
||||||
|
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>guestMarkersCheckBox</source>
|
||||||
|
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheatsPatches</name>
|
<name>CheatsPatches</name>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user