mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 08:22:32 +00:00
Merge branch 'shadps4-emu:main' into sceSystemServiceReceiveEvent
This commit is contained in:
commit
f02b575d85
2
.github/linux-appimage-qt.sh
vendored
2
.github/linux-appimage-qt.sh
vendored
@ -9,6 +9,8 @@ fi
|
|||||||
|
|
||||||
export Qt6_DIR="/usr/lib/qt6"
|
export Qt6_DIR="/usr/lib/qt6"
|
||||||
export PATH="$Qt6_DIR/bin:$PATH"
|
export PATH="$Qt6_DIR/bin:$PATH"
|
||||||
|
export EXTRA_QT_PLUGINS="waylandcompositor"
|
||||||
|
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
|
||||||
|
|
||||||
# Prepare Tools for building the AppImage
|
# Prepare Tools for building the AppImage
|
||||||
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||||
|
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -3,11 +3,7 @@
|
|||||||
|
|
||||||
name: Build and Release
|
name: Build and Release
|
||||||
|
|
||||||
on:
|
on: [push, pull_request]
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "*" ]
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ci-${{ github.event_name }}-${{ github.ref }}
|
group: ci-${{ github.event_name }}-${{ github.ref }}
|
||||||
@ -291,7 +287,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev
|
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev
|
||||||
|
|
||||||
- name: Cache CMake Configuration
|
- name: Cache CMake Configuration
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@ -347,7 +343,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev
|
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev
|
||||||
|
|
||||||
- name: Cache CMake Configuration
|
- name: Cache CMake Configuration
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@ -386,7 +382,7 @@ jobs:
|
|||||||
path: Shadps4-qt.AppImage
|
path: Shadps4-qt.AppImage
|
||||||
|
|
||||||
pre-release:
|
pre-release:
|
||||||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/main' && github.repository == 'shadps4-emu/shadPS4' && github.event_name == 'push'
|
||||||
needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
|
needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -95,3 +95,7 @@
|
|||||||
path = externals/pugixml
|
path = externals/pugixml
|
||||||
url = https://github.com/zeux/pugixml.git
|
url = https://github.com/zeux/pugixml.git
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "externals/discord-rpc"]
|
||||||
|
path = externals/discord-rpc
|
||||||
|
url = https://github.com/shadps4-emu/ext-discord-rpc.git
|
||||||
|
shallow = true
|
45
CMakeLists.txt
Normal file → Executable file
45
CMakeLists.txt
Normal file → Executable file
@ -282,6 +282,14 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
|||||||
src/core/libraries/audio3d/audio3d_error.h
|
src/core/libraries/audio3d/audio3d_error.h
|
||||||
src/core/libraries/audio3d/audio3d_impl.cpp
|
src/core/libraries/audio3d/audio3d_impl.cpp
|
||||||
src/core/libraries/audio3d/audio3d_impl.h
|
src/core/libraries/audio3d/audio3d_impl.h
|
||||||
|
src/core/libraries/ime/ime.cpp
|
||||||
|
src/core/libraries/ime/ime.h
|
||||||
|
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
|
||||||
|
src/core/libraries/game_live_streaming/gamelivestreaming.h
|
||||||
|
src/core/libraries/remote_play/remoteplay.cpp
|
||||||
|
src/core/libraries/remote_play/remoteplay.h
|
||||||
|
src/core/libraries/share_play/shareplay.cpp
|
||||||
|
src/core/libraries/share_play/shareplay.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
||||||
@ -297,6 +305,8 @@ set(LIBC_SOURCES src/core/libraries/libc_internal/libc_internal.cpp
|
|||||||
|
|
||||||
set(DIALOGS_LIB src/core/libraries/dialogs/error_dialog.cpp
|
set(DIALOGS_LIB src/core/libraries/dialogs/error_dialog.cpp
|
||||||
src/core/libraries/dialogs/error_dialog.h
|
src/core/libraries/dialogs/error_dialog.h
|
||||||
|
src/core/libraries/dialogs/ime_dialog_ui.cpp
|
||||||
|
src/core/libraries/dialogs/ime_dialog_ui.h
|
||||||
src/core/libraries/dialogs/ime_dialog.cpp
|
src/core/libraries/dialogs/ime_dialog.cpp
|
||||||
src/core/libraries/dialogs/ime_dialog.h
|
src/core/libraries/dialogs/ime_dialog.h
|
||||||
src/core/libraries/dialogs/error_codes.h
|
src/core/libraries/dialogs/error_codes.h
|
||||||
@ -324,6 +334,10 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp
|
|||||||
src/core/libraries/usbd/usbd.h
|
src/core/libraries/usbd/usbd.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(FIBER_LIB src/core/libraries/fiber/fiber.cpp
|
||||||
|
src/core/libraries/fiber/fiber.h
|
||||||
|
)
|
||||||
|
|
||||||
set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
||||||
src/core/libraries/np_manager/np_manager.h
|
src/core/libraries/np_manager/np_manager.h
|
||||||
src/core/libraries/np_score/np_score.cpp
|
src/core/libraries/np_score/np_score.cpp
|
||||||
@ -340,15 +354,25 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
|||||||
|
|
||||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||||
src/core/devtools/layer.h
|
src/core/devtools/layer.h
|
||||||
|
src/core/devtools/options.cpp
|
||||||
|
src/core/devtools/options.h
|
||||||
src/core/devtools/gcn/gcn_context_regs.cpp
|
src/core/devtools/gcn/gcn_context_regs.cpp
|
||||||
src/core/devtools/gcn/gcn_op_names.cpp
|
src/core/devtools/gcn/gcn_op_names.cpp
|
||||||
src/core/devtools/gcn/gcn_shader_regs.cpp
|
src/core/devtools/gcn/gcn_shader_regs.cpp
|
||||||
src/core/devtools/widget/cmd_list.cpp
|
src/core/devtools/widget/cmd_list.cpp
|
||||||
src/core/devtools/widget/cmd_list.h
|
src/core/devtools/widget/cmd_list.h
|
||||||
|
src/core/devtools/widget/common.h
|
||||||
src/core/devtools/widget/frame_dump.cpp
|
src/core/devtools/widget/frame_dump.cpp
|
||||||
src/core/devtools/widget/frame_dump.h
|
src/core/devtools/widget/frame_dump.h
|
||||||
src/core/devtools/widget/frame_graph.cpp
|
src/core/devtools/widget/frame_graph.cpp
|
||||||
src/core/devtools/widget/frame_graph.h
|
src/core/devtools/widget/frame_graph.h
|
||||||
|
src/core/devtools/widget/imgui_memory_editor.h
|
||||||
|
src/core/devtools/widget/reg_popup.cpp
|
||||||
|
src/core/devtools/widget/reg_popup.h
|
||||||
|
src/core/devtools/widget/reg_view.cpp
|
||||||
|
src/core/devtools/widget/reg_view.h
|
||||||
|
src/core/devtools/widget/text_editor.cpp
|
||||||
|
src/core/devtools/widget/text_editor.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(COMMON src/common/logging/backend.cpp
|
set(COMMON src/common/logging/backend.cpp
|
||||||
@ -374,6 +398,8 @@ set(COMMON src/common/logging/backend.cpp
|
|||||||
src/common/debug.h
|
src/common/debug.h
|
||||||
src/common/decoder.cpp
|
src/common/decoder.cpp
|
||||||
src/common/decoder.h
|
src/common/decoder.h
|
||||||
|
src/common/discord_rpc_handler.cpp
|
||||||
|
src/common/discord_rpc_handler.h
|
||||||
src/common/elf_info.h
|
src/common/elf_info.h
|
||||||
src/common/endian.h
|
src/common/endian.h
|
||||||
src/common/enum.h
|
src/common/enum.h
|
||||||
@ -462,6 +488,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||||||
${USBD_LIB}
|
${USBD_LIB}
|
||||||
${MISC_LIBS}
|
${MISC_LIBS}
|
||||||
${DIALOGS_LIB}
|
${DIALOGS_LIB}
|
||||||
|
${FIBER_LIB}
|
||||||
${DEV_TOOLS}
|
${DEV_TOOLS}
|
||||||
src/core/debug_state.cpp
|
src/core/debug_state.cpp
|
||||||
src/core/debug_state.h
|
src/core/debug_state.h
|
||||||
@ -518,6 +545,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||||||
src/shader_recompiler/frontend/translate/data_share.cpp
|
src/shader_recompiler/frontend/translate/data_share.cpp
|
||||||
src/shader_recompiler/frontend/translate/export.cpp
|
src/shader_recompiler/frontend/translate/export.cpp
|
||||||
src/shader_recompiler/frontend/translate/scalar_alu.cpp
|
src/shader_recompiler/frontend/translate/scalar_alu.cpp
|
||||||
|
src/shader_recompiler/frontend/translate/scalar_flow.cpp
|
||||||
src/shader_recompiler/frontend/translate/scalar_memory.cpp
|
src/shader_recompiler/frontend/translate/scalar_memory.cpp
|
||||||
src/shader_recompiler/frontend/translate/translate.cpp
|
src/shader_recompiler/frontend/translate/translate.cpp
|
||||||
src/shader_recompiler/frontend/translate/translate.h
|
src/shader_recompiler/frontend/translate/translate.h
|
||||||
@ -526,6 +554,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||||||
src/shader_recompiler/frontend/translate/vector_memory.cpp
|
src/shader_recompiler/frontend/translate/vector_memory.cpp
|
||||||
src/shader_recompiler/frontend/control_flow_graph.cpp
|
src/shader_recompiler/frontend/control_flow_graph.cpp
|
||||||
src/shader_recompiler/frontend/control_flow_graph.h
|
src/shader_recompiler/frontend/control_flow_graph.h
|
||||||
|
src/shader_recompiler/frontend/copy_shader.cpp
|
||||||
|
src/shader_recompiler/frontend/copy_shader.h
|
||||||
src/shader_recompiler/frontend/decode.cpp
|
src/shader_recompiler/frontend/decode.cpp
|
||||||
src/shader_recompiler/frontend/decode.h
|
src/shader_recompiler/frontend/decode.h
|
||||||
src/shader_recompiler/frontend/fetch_shader.cpp
|
src/shader_recompiler/frontend/fetch_shader.cpp
|
||||||
@ -542,6 +572,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||||||
src/shader_recompiler/ir/passes/ir_passes.h
|
src/shader_recompiler/ir/passes/ir_passes.h
|
||||||
src/shader_recompiler/ir/passes/lower_shared_mem_to_registers.cpp
|
src/shader_recompiler/ir/passes/lower_shared_mem_to_registers.cpp
|
||||||
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
|
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
|
||||||
|
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
|
||||||
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
|
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
|
||||||
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
|
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
|
||||||
src/shader_recompiler/ir/abstract_syntax_list.h
|
src/shader_recompiler/ir/abstract_syntax_list.h
|
||||||
@ -574,6 +605,7 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
|||||||
src/video_core/amdgpu/pm4_cmds.h
|
src/video_core/amdgpu/pm4_cmds.h
|
||||||
src/video_core/amdgpu/pm4_opcodes.h
|
src/video_core/amdgpu/pm4_opcodes.h
|
||||||
src/video_core/amdgpu/resource.h
|
src/video_core/amdgpu/resource.h
|
||||||
|
src/video_core/amdgpu/types.h
|
||||||
src/video_core/amdgpu/default_context.cpp
|
src/video_core/amdgpu/default_context.cpp
|
||||||
src/video_core/buffer_cache/buffer.cpp
|
src/video_core/buffer_cache/buffer.cpp
|
||||||
src/video_core/buffer_cache/buffer.h
|
src/video_core/buffer_cache/buffer.h
|
||||||
@ -686,6 +718,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
|||||||
src/qt_gui/game_grid_frame.h
|
src/qt_gui/game_grid_frame.h
|
||||||
src/qt_gui/game_install_dialog.cpp
|
src/qt_gui/game_install_dialog.cpp
|
||||||
src/qt_gui/game_install_dialog.h
|
src/qt_gui/game_install_dialog.h
|
||||||
|
src/qt_gui/install_dir_select.cpp
|
||||||
|
src/qt_gui/install_dir_select.h
|
||||||
src/qt_gui/pkg_viewer.cpp
|
src/qt_gui/pkg_viewer.cpp
|
||||||
src/qt_gui/pkg_viewer.h
|
src/qt_gui/pkg_viewer.h
|
||||||
src/qt_gui/trophy_viewer.cpp
|
src/qt_gui/trophy_viewer.cpp
|
||||||
@ -853,3 +887,14 @@ if (UNIX AND NOT APPLE)
|
|||||||
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
|
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Discord RPC
|
||||||
|
target_link_libraries(shadps4 PRIVATE discord-rpc)
|
||||||
|
|
||||||
|
# Install rules
|
||||||
|
install(TARGETS shadps4 BUNDLE DESTINATION .)
|
||||||
|
|
||||||
|
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
install(FILES ".github/shadps4.desktop" DESTINATION "share/applications")
|
||||||
|
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps")
|
||||||
|
endif()
|
||||||
|
19
README.md
19
README.md
@ -36,14 +36,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
|
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
|
||||||
|
|
||||||
If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md).
|
If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md).\
|
||||||
|
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).\
|
||||||
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).
|
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
|
||||||
|
To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\
|
||||||
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).
|
|
||||||
|
|
||||||
To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).
|
|
||||||
|
|
||||||
For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)!
|
For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)!
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
@ -51,7 +47,7 @@ For those who'd like to donate to the project, we now have a [**Kofi page**](htt
|
|||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> shadPS4 is early in development, don't expect a flawless experience.
|
> shadPS4 is early in development, don't expect a flawless experience.
|
||||||
|
|
||||||
Currently, the emulator successfully runs small games like [**Sonic Mania**](https://www.youtube.com/watch?v=AAHoNzhHyCU), [**Undertale**](https://youtu.be/5zIvdy65Ro4) and it can even run [**Bloodborne**](https://www.youtube.com/watch?v=wC6s0avpQRE).
|
Currently, the emulator can successfully run games like [**Bloodborne**](https://www.youtube.com/watch?v=wC6s0avpQRE), [**Dark Souls Remastered**](https://www.youtube.com/watch?v=-3PA-Xwszts), [**Red Dead Redemption**](https://www.youtube.com/watch?v=Al7yz_5nLag) and many other games.
|
||||||
|
|
||||||
# Why
|
# Why
|
||||||
|
|
||||||
@ -102,7 +98,7 @@ PAD DOWN | DOWN |
|
|||||||
PAD LEFT | LEFT |
|
PAD LEFT | LEFT |
|
||||||
PAD RIGHT | RIGHT |
|
PAD RIGHT | RIGHT |
|
||||||
OPTIONS | RETURN |
|
OPTIONS | RETURN |
|
||||||
TOUCH PAD | SPACE |
|
BACK BUTTON / TOUCH PAD | SPACE |
|
||||||
L1 | Q |
|
L1 | Q |
|
||||||
R1 | U |
|
R1 | U |
|
||||||
L2 | E |
|
L2 | E |
|
||||||
@ -123,8 +119,7 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
|
|||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.
|
If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
|
||||||
|
|
||||||
Open a PR and we'll check it :)
|
Open a PR and we'll check it :)
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
|
@ -7,21 +7,22 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
- [PC Requirements](#pc-requirements)
|
- [**PC Requirements**](#minimum-pc-requirements)
|
||||||
- [CPU](#cpu)
|
- [**CPU**](#cpu)
|
||||||
- [GPU](#gpu)
|
- [**GPU**](#gpu)
|
||||||
- [RAM](#ram)
|
- [**RAM**](#ram)
|
||||||
- [OS](#os)
|
- [**OS**](#os)
|
||||||
- [Have the latest WIP version](#have-the-latest-wip-version)
|
- [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4)
|
||||||
- [Install PKG files (Games and Updates)](#install-pkg-files)
|
- [**Install PKG files (Games and Updates)**](#install-pkg-files)
|
||||||
- [Configure the emulator](#configure-the-emulator)
|
- [**Configure the emulator**](#configure-the-emulator)
|
||||||
|
|
||||||
## PC Requirements
|
## Minimum PC requirements
|
||||||
|
|
||||||
### CPU
|
### CPU
|
||||||
|
|
||||||
- A processor with at least 4 cores and 6 threads
|
- A processor with at least 4 cores and 6 threads
|
||||||
- Above 2.5 GHz frequency
|
- Above 2.5 GHz frequency
|
||||||
|
- required support AVX2 extension or Rosetta 2 on ARM
|
||||||
|
|
||||||
### GPU
|
### GPU
|
||||||
|
|
||||||
@ -37,41 +38,25 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
- Windows 10 or Ubuntu 22.04
|
- Windows 10 or Ubuntu 22.04
|
||||||
|
|
||||||
## How to run the latest Work-in-Progress builds of ShadPS4
|
## How to run the latest Work-in-Progress builds of shadPS4
|
||||||
|
|
||||||
1. Go to <https://github.com/shadps4-emu/shadPS4/releases> In the release identified as 'pre-release' click on the down arrow(Assets), select your operating system of choice (the "**qt**" versions have a user interface, which is probably the one you want. The others are SDL versions, which can only be run via command line).
|
1. Go to <https://github.com/shadps4-emu/shadPS4/releases> In the release identified as 'pre-release' click on the down arrow(Assets), select your operating system of choice (the "**qt**" versions have a user interface, which is probably the one you want. The others are SDL versions, which can only be run via command line).
|
||||||

|

|
||||||
|
|
||||||
2. Once downloaded, extract to its own folder, and run ShadPS4's executable from the extracted folder.
|
2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder.
|
||||||
|
|
||||||
3. Upon first launch, ShadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that ShadPS4 can use to install your PKG files to.
|
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that shadPS4 can use to install your PKG files to.
|
||||||
|
|
||||||
## Install PKG files
|
## Install PKG files
|
||||||
|
|
||||||
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
|
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
|
||||||
|
|
||||||
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800"></a>
|
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800">
|
||||||
|
|
||||||
## Configure the emulator
|
## Configure the emulator
|
||||||
|
|
||||||
You can configure the emulator by editing the `config.toml` file found in the `user` folder created after starting the application.\
|
To configure the emulator, you can go through the interface and go to "settings".
|
||||||
Some settings may be related to more technical development and debugging. For more information on those, see [Debugging](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
|
|
||||||
|
|
||||||
Here's a list of configuration entries that are worth changing:
|
You can also configure the emulator by editing the `config.toml` file located in the `user` folder created after the application is started (Mostly useful if you are using the SDL version).
|
||||||
|
Some settings may be related to more technical development and debugging.\
|
||||||
- `[General]`
|
For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
|
||||||
|
|
||||||
- `Fullscreen`: Display the game in a full screen borderless window.
|
|
||||||
|
|
||||||
- `logType`: Configures logging synchronization (`sync`/`async`)
|
|
||||||
- It can be beneficial to set this to `sync` in order for the log to accurately maintain message order, at the cost of performance.
|
|
||||||
- Use when sending logs to developers. See more about [reporting issues](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#reporting-and-communicating-about-issues).
|
|
||||||
- `logFilter`: Sets the logging category for various logging classes.
|
|
||||||
- Format: `<class>:<level> ...`, `<class.*>:<level> <*:level> ...`
|
|
||||||
- Valid log levels: `Trace, Debug, Info, Warning, Error, Critical` - in this order, setting a level silences all levels preceding it and logs every level after it.
|
|
||||||
- Examples:
|
|
||||||
- If the log is being spammed with messages coming from Lib.Pad, you can use `Lib.Pad:Critical` to only log critical-level messages.
|
|
||||||
- If you'd like to mute everything, but still want to receive messages from Vulkan rendering: `*:Error Render.Vulkan:Info`
|
|
||||||
|
|
||||||
- `[GPU]`
|
|
||||||
- `screenWidth` and `screenHeight`: Configures the game window width and height.
|
|
@ -6,7 +6,7 @@ v0.3.0 23/09/2024 - codename broamic
|
|||||||
- New translations support (26 languages)
|
- New translations support (26 languages)
|
||||||
- Support for unlocking trophies
|
- Support for unlocking trophies
|
||||||
- Support for more controllers (Dualshock and Xbox)
|
- Support for more controllers (Dualshock and Xbox)
|
||||||
- Many GUI imporovements
|
- Many GUI improvements
|
||||||
- AVplayer
|
- AVplayer
|
||||||
|
|
||||||
v0.2.0 15/08/2024 - codename validptr
|
v0.2.0 15/08/2024 - codename validptr
|
||||||
|
17
externals/CMakeLists.txt
vendored
17
externals/CMakeLists.txt
vendored
@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
set(BUILD_TESTING OFF)
|
set(BUILD_TESTING OFF)
|
||||||
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
|
set_directory_properties(PROPERTIES
|
||||||
|
EXCLUDE_FROM_ALL ON
|
||||||
|
SYSTEM ON
|
||||||
|
)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Silence "deprecation" warnings
|
# Silence "deprecation" warnings
|
||||||
@ -13,11 +16,8 @@ endif()
|
|||||||
# Boost
|
# Boost
|
||||||
if (NOT TARGET Boost::headers)
|
if (NOT TARGET Boost::headers)
|
||||||
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
||||||
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
|
||||||
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
||||||
add_library(boost INTERFACE)
|
add_subdirectory(ext-boost)
|
||||||
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
|
|
||||||
add_library(Boost::headers ALIAS boost)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# fmtlib
|
# fmtlib
|
||||||
@ -77,7 +77,7 @@ endif()
|
|||||||
# RenderDoc
|
# RenderDoc
|
||||||
if (NOT TARGET RenderDoc::API)
|
if (NOT TARGET RenderDoc::API)
|
||||||
add_library(renderdoc INTERFACE)
|
add_library(renderdoc INTERFACE)
|
||||||
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
target_include_directories(renderdoc INTERFACE ./renderdoc)
|
||||||
add_library(RenderDoc::API ALIAS renderdoc)
|
add_library(RenderDoc::API ALIAS renderdoc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -184,5 +184,10 @@ if (NOT TARGET pugixml::pugixml)
|
|||||||
add_subdirectory(pugixml)
|
add_subdirectory(pugixml)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Discord RPC
|
||||||
|
set(BUILD_EXAMPLES OFF)
|
||||||
|
add_subdirectory(discord-rpc/)
|
||||||
|
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
|
||||||
|
|
||||||
# GCN Headers
|
# GCN Headers
|
||||||
add_subdirectory(gcn)
|
add_subdirectory(gcn)
|
2
externals/date
vendored
2
externals/date
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 51ce7e131079c061533d741be5fe7cca57f2faac
|
Subproject commit dd8affc6de5755e07638bf0a14382d29549d6ee9
|
1
externals/discord-rpc
vendored
Submodule
1
externals/discord-rpc
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4ec218155d73bcb8022f8f7ca72305d801f84beb
|
2
externals/ext-boost
vendored
2
externals/ext-boost
vendored
@ -1 +1 @@
|
|||||||
Subproject commit a04136add1e469f46d8ae8d3e8307779240a5c53
|
Subproject commit f2474e1b584fb7a3ed6f85ba875e6eacd742ec8a
|
2
externals/glslang
vendored
2
externals/glslang
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 46ef757e048e760b46601e6e77ae0cb72c97bd2f
|
Subproject commit e61d7bb3006f451968714e2f653412081871e1ee
|
2
externals/sdl3
vendored
2
externals/sdl3
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 0548050fc5a4edf1f47c3633c2cd06d8762b5532
|
Subproject commit 54e622c2e6af456bfef382fae44c17682d5ac88a
|
2
externals/sirit
vendored
2
externals/sirit
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 37090c74cc6e680f2bc334cac8fd182f7634a1f6
|
Subproject commit 6cecb95d679c82c413d1f989e0b7ad9af130600d
|
2
externals/toml11
vendored
2
externals/toml11
vendored
@ -1 +1 @@
|
|||||||
Subproject commit d050c6b137199666cae75c2628a75d63b49b1c22
|
Subproject commit f925e7f287c0008813c2294798cf9ca167fd9ffd
|
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 29f979ee5aa58b7b005f805ea8df7a855c39ff37
|
Subproject commit d91597a82f881d473887b560a03a7edf2720b72c
|
2
externals/xbyak
vendored
2
externals/xbyak
vendored
@ -1 +1 @@
|
|||||||
Subproject commit ccdf68421bc8eb85693f573080fc0a5faad862db
|
Subproject commit d067f0d3f55696ae8bc9a25ad7012ee80f221d54
|
2
externals/xxhash
vendored
2
externals/xxhash
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 3e321b4407318ac1348c0b80fb6fbae8c81ad5fa
|
Subproject commit d4ad85e4afaad5c780f54db1dc967fff5a869ffd
|
2
externals/zydis
vendored
2
externals/zydis
vendored
@ -1 +1 @@
|
|||||||
Subproject commit bd73bc03b0aacaa89c9c203b9b43cd08f1b1843b
|
Subproject commit 9d298eb8067ff62a237203d1e1470785033e185c
|
@ -103,7 +103,7 @@ s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
|
|||||||
|
|
||||||
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
||||||
|
|
||||||
SDL_bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
|
bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
|
||||||
|
|
||||||
lock.unlock(); // Unlock only after necessary operations
|
lock.unlock(); // Unlock only after necessary operations
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ static bool isNeo = false;
|
|||||||
static bool isFullscreen = false;
|
static bool isFullscreen = false;
|
||||||
static bool playBGM = false;
|
static bool playBGM = false;
|
||||||
static int BGMvolume = 50;
|
static int BGMvolume = 50;
|
||||||
|
static bool enableDiscordRPC = false;
|
||||||
static u32 screenWidth = 1280;
|
static u32 screenWidth = 1280;
|
||||||
static u32 screenHeight = 720;
|
static u32 screenHeight = 720;
|
||||||
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
||||||
@ -41,6 +42,7 @@ 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 backButtonBehavior = "left";
|
||||||
static bool useSpecialPad = false;
|
static bool useSpecialPad = false;
|
||||||
static int specialPadClass = 1;
|
static int specialPadClass = 1;
|
||||||
static bool isDebugDump = false;
|
static bool isDebugDump = false;
|
||||||
@ -56,9 +58,11 @@ static bool vkValidationGpu = false;
|
|||||||
static bool rdocEnable = false;
|
static bool rdocEnable = false;
|
||||||
static bool vkMarkers = false;
|
static bool vkMarkers = false;
|
||||||
static bool vkCrashDiagnostic = false;
|
static bool vkCrashDiagnostic = false;
|
||||||
|
static s16 cursorState = HideCursorState::Idle;
|
||||||
|
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||||
|
|
||||||
// Gui
|
// Gui
|
||||||
std::filesystem::path settings_install_dir = {};
|
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||||
std::filesystem::path settings_addon_install_dir = {};
|
std::filesystem::path settings_addon_install_dir = {};
|
||||||
u32 main_window_geometry_x = 400;
|
u32 main_window_geometry_x = 400;
|
||||||
u32 main_window_geometry_y = 400;
|
u32 main_window_geometry_y = 400;
|
||||||
@ -95,6 +99,18 @@ int getBGMvolume() {
|
|||||||
return BGMvolume;
|
return BGMvolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getEnableDiscordRPC() {
|
||||||
|
return enableDiscordRPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 getCursorState() {
|
||||||
|
return cursorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getCursorHideTimeout() {
|
||||||
|
return cursorHideTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
u32 getScreenWidth() {
|
u32 getScreenWidth() {
|
||||||
return screenWidth;
|
return screenWidth;
|
||||||
}
|
}
|
||||||
@ -123,6 +139,10 @@ std::string getUpdateChannel() {
|
|||||||
return updateChannel;
|
return updateChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getBackButtonBehavior() {
|
||||||
|
return backButtonBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
bool getUseSpecialPad() {
|
bool getUseSpecialPad() {
|
||||||
return useSpecialPad;
|
return useSpecialPad;
|
||||||
}
|
}
|
||||||
@ -251,6 +271,18 @@ void setBGMvolume(int volume) {
|
|||||||
BGMvolume = volume;
|
BGMvolume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setEnableDiscordRPC(bool enable) {
|
||||||
|
enableDiscordRPC = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCursorState(s16 newCursorState) {
|
||||||
|
cursorState = newCursorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCursorHideTimeout(int newcursorHideTimeout) {
|
||||||
|
cursorHideTimeout = newcursorHideTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
void setLanguage(u32 language) {
|
void setLanguage(u32 language) {
|
||||||
m_language = language;
|
m_language = language;
|
||||||
}
|
}
|
||||||
@ -275,6 +307,10 @@ void setUpdateChannel(const std::string& type) {
|
|||||||
updateChannel = type;
|
updateChannel = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBackButtonBehavior(const std::string& type) {
|
||||||
|
backButtonBehavior = type;
|
||||||
|
}
|
||||||
|
|
||||||
void setUseSpecialPad(bool use) {
|
void setUseSpecialPad(bool use) {
|
||||||
useSpecialPad = use;
|
useSpecialPad = use;
|
||||||
}
|
}
|
||||||
@ -289,8 +325,19 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
|
|||||||
main_window_geometry_w = w;
|
main_window_geometry_w = w;
|
||||||
main_window_geometry_h = h;
|
main_window_geometry_h = h;
|
||||||
}
|
}
|
||||||
void setGameInstallDir(const std::filesystem::path& dir) {
|
bool addGameInstallDir(const std::filesystem::path& dir) {
|
||||||
settings_install_dir = dir;
|
if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
|
||||||
|
settings_install_dirs.end()) {
|
||||||
|
settings_install_dirs.push_back(dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void removeGameInstallDir(const std::filesystem::path& dir) {
|
||||||
|
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir);
|
||||||
|
if (iterator != settings_install_dirs.end()) {
|
||||||
|
settings_install_dirs.erase(iterator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void setAddonInstallDir(const std::filesystem::path& dir) {
|
void setAddonInstallDir(const std::filesystem::path& dir) {
|
||||||
settings_addon_install_dir = dir;
|
settings_addon_install_dir = dir;
|
||||||
@ -348,8 +395,8 @@ u32 getMainWindowGeometryW() {
|
|||||||
u32 getMainWindowGeometryH() {
|
u32 getMainWindowGeometryH() {
|
||||||
return main_window_geometry_h;
|
return main_window_geometry_h;
|
||||||
}
|
}
|
||||||
std::filesystem::path getGameInstallDir() {
|
const std::vector<std::filesystem::path>& getGameInstallDirs() {
|
||||||
return settings_install_dir;
|
return settings_install_dirs;
|
||||||
}
|
}
|
||||||
std::filesystem::path getAddonInstallDir() {
|
std::filesystem::path getAddonInstallDir() {
|
||||||
if (settings_addon_install_dir.empty()) {
|
if (settings_addon_install_dir.empty()) {
|
||||||
@ -425,6 +472,7 @@ void load(const std::filesystem::path& path) {
|
|||||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
||||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||||
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
||||||
|
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
|
||||||
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
||||||
logType = toml::find_or<std::string>(general, "logType", "sync");
|
logType = toml::find_or<std::string>(general, "logType", "sync");
|
||||||
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
||||||
@ -440,6 +488,9 @@ void load(const std::filesystem::path& path) {
|
|||||||
if (data.contains("Input")) {
|
if (data.contains("Input")) {
|
||||||
const toml::value& input = data.at("Input");
|
const toml::value& input = data.at("Input");
|
||||||
|
|
||||||
|
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
||||||
|
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
||||||
|
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
||||||
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
||||||
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
||||||
}
|
}
|
||||||
@ -483,7 +534,19 @@ void load(const std::filesystem::path& path) {
|
|||||||
mw_themes = toml::find_or<int>(gui, "theme", 0);
|
mw_themes = toml::find_or<int>(gui, "theme", 0);
|
||||||
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
|
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
|
||||||
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
|
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
|
||||||
settings_install_dir = toml::find_fs_path_or(gui, "installDir", {});
|
|
||||||
|
// TODO Migration code, after a major release this should be removed.
|
||||||
|
auto old_game_install_dir = toml::find_fs_path_or(gui, "installDir", {});
|
||||||
|
if (!old_game_install_dir.empty()) {
|
||||||
|
addGameInstallDir(std::filesystem::path{old_game_install_dir});
|
||||||
|
} else {
|
||||||
|
const auto install_dir_array =
|
||||||
|
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
|
||||||
|
for (const auto& dir : install_dir_array) {
|
||||||
|
addGameInstallDir(std::filesystem::path{dir});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
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);
|
||||||
@ -527,12 +590,16 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["General"]["Fullscreen"] = isFullscreen;
|
data["General"]["Fullscreen"] = isFullscreen;
|
||||||
data["General"]["playBGM"] = playBGM;
|
data["General"]["playBGM"] = playBGM;
|
||||||
data["General"]["BGMvolume"] = BGMvolume;
|
data["General"]["BGMvolume"] = BGMvolume;
|
||||||
|
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
|
||||||
data["General"]["logFilter"] = logFilter;
|
data["General"]["logFilter"] = logFilter;
|
||||||
data["General"]["logType"] = logType;
|
data["General"]["logType"] = logType;
|
||||||
data["General"]["userName"] = userName;
|
data["General"]["userName"] = userName;
|
||||||
data["General"]["updateChannel"] = updateChannel;
|
data["General"]["updateChannel"] = updateChannel;
|
||||||
data["General"]["showSplash"] = isShowSplash;
|
data["General"]["showSplash"] = isShowSplash;
|
||||||
data["General"]["autoUpdate"] = isAutoUpdate;
|
data["General"]["autoUpdate"] = isAutoUpdate;
|
||||||
|
data["Input"]["cursorState"] = cursorState;
|
||||||
|
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||||
|
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||||
data["Input"]["useSpecialPad"] = useSpecialPad;
|
data["Input"]["useSpecialPad"] = useSpecialPad;
|
||||||
data["Input"]["specialPadClass"] = specialPadClass;
|
data["Input"]["specialPadClass"] = specialPadClass;
|
||||||
data["GPU"]["screenWidth"] = screenWidth;
|
data["GPU"]["screenWidth"] = screenWidth;
|
||||||
@ -557,7 +624,13 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["GUI"]["gameTableMode"] = m_table_mode;
|
data["GUI"]["gameTableMode"] = m_table_mode;
|
||||||
data["GUI"]["mw_width"] = m_window_size_W;
|
data["GUI"]["mw_width"] = m_window_size_W;
|
||||||
data["GUI"]["mw_height"] = m_window_size_H;
|
data["GUI"]["mw_height"] = m_window_size_H;
|
||||||
data["GUI"]["installDir"] = std::string{fmt::UTF(settings_install_dir.u8string()).data};
|
|
||||||
|
std::vector<std::string> install_dirs;
|
||||||
|
for (const auto& dirString : settings_install_dirs) {
|
||||||
|
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||||
|
}
|
||||||
|
data["GUI"]["installDirs"] = install_dirs;
|
||||||
|
|
||||||
data["GUI"]["addonInstallDir"] =
|
data["GUI"]["addonInstallDir"] =
|
||||||
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
||||||
data["GUI"]["geometry_x"] = main_window_geometry_x;
|
data["GUI"]["geometry_x"] = main_window_geometry_x;
|
||||||
@ -571,6 +644,9 @@ void save(const std::filesystem::path& path) {
|
|||||||
|
|
||||||
data["Settings"]["consoleLanguage"] = m_language;
|
data["Settings"]["consoleLanguage"] = m_language;
|
||||||
|
|
||||||
|
// TODO Migration code, after a major release this should be removed.
|
||||||
|
data.at("GUI").as_table().erase("installDir");
|
||||||
|
|
||||||
std::ofstream file(path, std::ios::out);
|
std::ofstream file(path, std::ios::out);
|
||||||
file << data;
|
file << data;
|
||||||
file.close();
|
file.close();
|
||||||
@ -581,6 +657,7 @@ void setDefaultValues() {
|
|||||||
isFullscreen = false;
|
isFullscreen = false;
|
||||||
playBGM = false;
|
playBGM = false;
|
||||||
BGMvolume = 50;
|
BGMvolume = 50;
|
||||||
|
enableDiscordRPC = true;
|
||||||
screenWidth = 1280;
|
screenWidth = 1280;
|
||||||
screenHeight = 720;
|
screenHeight = 720;
|
||||||
logFilter = "";
|
logFilter = "";
|
||||||
@ -591,6 +668,9 @@ void setDefaultValues() {
|
|||||||
} else {
|
} else {
|
||||||
updateChannel = "Nightly";
|
updateChannel = "Nightly";
|
||||||
}
|
}
|
||||||
|
cursorState = HideCursorState::Idle;
|
||||||
|
cursorHideTimeout = 5;
|
||||||
|
backButtonBehavior = "left";
|
||||||
useSpecialPad = false;
|
useSpecialPad = false;
|
||||||
specialPadClass = 1;
|
specialPadClass = 1;
|
||||||
isDebugDump = false;
|
isDebugDump = false;
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace Config {
|
namespace Config {
|
||||||
|
|
||||||
|
enum HideCursorState : s16 { Never, Idle, Always };
|
||||||
|
|
||||||
void load(const std::filesystem::path& path);
|
void load(const std::filesystem::path& path);
|
||||||
void save(const std::filesystem::path& path);
|
void save(const std::filesystem::path& path);
|
||||||
|
|
||||||
@ -15,12 +18,16 @@ bool isNeoMode();
|
|||||||
bool isFullscreenMode();
|
bool isFullscreenMode();
|
||||||
bool getPlayBGM();
|
bool getPlayBGM();
|
||||||
int getBGMvolume();
|
int getBGMvolume();
|
||||||
|
bool getEnableDiscordRPC();
|
||||||
|
|
||||||
std::string getLogFilter();
|
std::string getLogFilter();
|
||||||
std::string getLogType();
|
std::string getLogType();
|
||||||
std::string getUserName();
|
std::string getUserName();
|
||||||
std::string getUpdateChannel();
|
std::string getUpdateChannel();
|
||||||
|
|
||||||
|
s16 getCursorState();
|
||||||
|
int getCursorHideTimeout();
|
||||||
|
std::string getBackButtonBehavior();
|
||||||
bool getUseSpecialPad();
|
bool getUseSpecialPad();
|
||||||
int getSpecialPadClass();
|
int getSpecialPadClass();
|
||||||
|
|
||||||
@ -50,11 +57,15 @@ void setScreenHeight(u32 height);
|
|||||||
void setFullscreenMode(bool enable);
|
void setFullscreenMode(bool enable);
|
||||||
void setPlayBGM(bool enable);
|
void setPlayBGM(bool enable);
|
||||||
void setBGMvolume(int volume);
|
void setBGMvolume(int volume);
|
||||||
|
void setEnableDiscordRPC(bool enable);
|
||||||
void setLanguage(u32 language);
|
void setLanguage(u32 language);
|
||||||
void setNeoMode(bool enable);
|
void setNeoMode(bool enable);
|
||||||
void setUserName(const std::string& type);
|
void setUserName(const std::string& type);
|
||||||
void setUpdateChannel(const std::string& type);
|
void setUpdateChannel(const std::string& type);
|
||||||
|
|
||||||
|
void setCursorState(s16 cursorState);
|
||||||
|
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||||
|
void setBackButtonBehavior(const std::string& type);
|
||||||
void setUseSpecialPad(bool use);
|
void setUseSpecialPad(bool use);
|
||||||
void setSpecialPadClass(int type);
|
void setSpecialPadClass(int type);
|
||||||
|
|
||||||
@ -73,7 +84,8 @@ bool vkCrashDiagnosticEnabled();
|
|||||||
|
|
||||||
// Gui
|
// Gui
|
||||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||||
void setGameInstallDir(const std::filesystem::path& dir);
|
bool addGameInstallDir(const std::filesystem::path& dir);
|
||||||
|
void removeGameInstallDir(const std::filesystem::path& dir);
|
||||||
void setAddonInstallDir(const std::filesystem::path& dir);
|
void setAddonInstallDir(const std::filesystem::path& dir);
|
||||||
void setMainWindowTheme(u32 theme);
|
void setMainWindowTheme(u32 theme);
|
||||||
void setIconSize(u32 size);
|
void setIconSize(u32 size);
|
||||||
@ -92,7 +104,7 @@ u32 getMainWindowGeometryX();
|
|||||||
u32 getMainWindowGeometryY();
|
u32 getMainWindowGeometryY();
|
||||||
u32 getMainWindowGeometryW();
|
u32 getMainWindowGeometryW();
|
||||||
u32 getMainWindowGeometryH();
|
u32 getMainWindowGeometryH();
|
||||||
std::filesystem::path getGameInstallDir();
|
const std::vector<std::filesystem::path>& getGameInstallDirs();
|
||||||
std::filesystem::path getAddonInstallDir();
|
std::filesystem::path getAddonInstallDir();
|
||||||
u32 getMainWindowTheme();
|
u32 getMainWindowTheme();
|
||||||
u32 getIconSize();
|
u32 getIconSize();
|
||||||
|
@ -81,34 +81,42 @@ public:
|
|||||||
return std::basic_string_view<T>{data};
|
return std::basic_string_view<T>{data};
|
||||||
}
|
}
|
||||||
|
|
||||||
char* begin() {
|
T* begin() {
|
||||||
if (this == nullptr) {
|
if (this == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* begin() const {
|
const T* begin() const {
|
||||||
if (this == nullptr) {
|
if (this == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* end() {
|
T* end() {
|
||||||
if (this == nullptr) {
|
if (this == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return data + N;
|
return data + N;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* end() const {
|
const T* end() const {
|
||||||
if (this == nullptr) {
|
if (this == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return data + N;
|
return data + N;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t capacity() const {
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const {
|
||||||
|
return std::char_traits<T>::length(data);
|
||||||
|
}
|
||||||
|
|
||||||
T& operator[](size_t idx) {
|
T& operator[](size_t idx) {
|
||||||
return data[idx];
|
return data[idx];
|
||||||
}
|
}
|
||||||
@ -152,6 +160,12 @@ public:
|
|||||||
static_assert(sizeof(CString<13>) == sizeof(char[13])); // Ensure size still matches a simple array
|
static_assert(sizeof(CString<13>) == sizeof(char[13])); // Ensure size still matches a simple array
|
||||||
static_assert(std::weakly_incrementable<CString<13>::Iterator>);
|
static_assert(std::weakly_incrementable<CString<13>::Iterator>);
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
using CWString = CString<N, wchar_t>;
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
using CU16String = CString<N, char16_t>;
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
@ -1,43 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include "common/discord.h"
|
|
||||||
|
|
||||||
namespace Discord {
|
|
||||||
|
|
||||||
void RPC::init() {
|
|
||||||
DiscordEventHandlers handlers{};
|
|
||||||
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
|
||||||
|
|
||||||
startTimestamp = time(nullptr);
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::update(Discord::RPCStatus status, const std::string& game) {
|
|
||||||
DiscordRichPresence rpc{};
|
|
||||||
|
|
||||||
if (status == Discord::RPCStatus::Playing) {
|
|
||||||
rpc.details = "Playing a game";
|
|
||||||
rpc.state = game.c_str();
|
|
||||||
} else {
|
|
||||||
rpc.details = "Idle";
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.largeImageKey = "shadps4";
|
|
||||||
rpc.largeImageText = "ShadPS4 is a PS4 emulator";
|
|
||||||
rpc.startTimestamp = startTimestamp;
|
|
||||||
|
|
||||||
Discord_UpdatePresence(&rpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::stop() {
|
|
||||||
if (enabled) {
|
|
||||||
enabled = false;
|
|
||||||
Discord_ClearPresence();
|
|
||||||
Discord_Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Discord
|
|
57
src/common/discord_rpc_handler.cpp
Normal file
57
src/common/discord_rpc_handler.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include "src/common/discord_rpc_handler.h"
|
||||||
|
|
||||||
|
namespace DiscordRPCHandler {
|
||||||
|
|
||||||
|
void RPC::init() {
|
||||||
|
DiscordEventHandlers handlers{};
|
||||||
|
|
||||||
|
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
||||||
|
startTimestamp = time(nullptr);
|
||||||
|
rpcEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setStatusIdling() {
|
||||||
|
DiscordRichPresence rpc{};
|
||||||
|
rpc.largeImageKey = "https://github.com/shadps4-emu/shadPS4/raw/main/.github/shadps4.png";
|
||||||
|
rpc.largeImageText = "shadPS4 is a PS4 emulator";
|
||||||
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
rpc.details = "Idle";
|
||||||
|
|
||||||
|
status = RPCStatus::Idling;
|
||||||
|
Discord_UpdatePresence(&rpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setStatusPlaying(const std::string& game_name, const std::string& game_id) {
|
||||||
|
DiscordRichPresence rpc{};
|
||||||
|
|
||||||
|
rpc.details = "Playing";
|
||||||
|
rpc.state = game_name.c_str();
|
||||||
|
std::string largeImageUrl =
|
||||||
|
"https://store.playstation.com/store/api/chihiro/00_09_000/titlecontainer/US/en/999/" +
|
||||||
|
game_id + "_00/image";
|
||||||
|
rpc.largeImageKey = largeImageUrl.c_str();
|
||||||
|
rpc.largeImageText = game_name.c_str();
|
||||||
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
|
||||||
|
status = RPCStatus::Playing;
|
||||||
|
Discord_UpdatePresence(&rpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::shutdown() {
|
||||||
|
if (rpcEnabled) {
|
||||||
|
rpcEnabled = false;
|
||||||
|
Discord_ClearPresence();
|
||||||
|
Discord_Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RPC::getRPCEnabled() {
|
||||||
|
return rpcEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace DiscordRPCHandler
|
@ -7,7 +7,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <discord_rpc.h>
|
#include <discord_rpc.h>
|
||||||
|
|
||||||
namespace Discord {
|
namespace DiscordRPCHandler {
|
||||||
|
|
||||||
enum class RPCStatus {
|
enum class RPCStatus {
|
||||||
Idling,
|
Idling,
|
||||||
@ -16,12 +16,15 @@ enum class RPCStatus {
|
|||||||
|
|
||||||
class RPC {
|
class RPC {
|
||||||
std::uint64_t startTimestamp;
|
std::uint64_t startTimestamp;
|
||||||
bool enabled = false;
|
bool rpcEnabled = false;
|
||||||
|
RPCStatus status;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void update(RPCStatus status, const std::string& title);
|
void setStatusIdling();
|
||||||
void stop();
|
void setStatusPlaying(const std::string& game_name, const std::string& game_id);
|
||||||
|
void shutdown();
|
||||||
|
bool getRPCEnabled();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Discord
|
} // namespace DiscordRPCHandler
|
@ -231,7 +231,7 @@ void IOFile::Unlink() {
|
|||||||
|
|
||||||
// Mark the file for deletion
|
// Mark the file for deletion
|
||||||
// TODO: Also remove the file path?
|
// TODO: Also remove the file path?
|
||||||
#if _WIN64
|
#ifdef _WIN64
|
||||||
FILE_DISPOSITION_INFORMATION disposition;
|
FILE_DISPOSITION_INFORMATION disposition;
|
||||||
IO_STATUS_BLOCK iosb;
|
IO_STATUS_BLOCK iosb;
|
||||||
|
|
||||||
@ -242,7 +242,11 @@ void IOFile::Unlink() {
|
|||||||
NtSetInformationFile(hfile, &iosb, &disposition, sizeof(disposition),
|
NtSetInformationFile(hfile, &iosb, &disposition, sizeof(disposition),
|
||||||
FileDispositionInformation);
|
FileDispositionInformation);
|
||||||
#else
|
#else
|
||||||
UNREACHABLE_MSG("Missing Linux implementation");
|
if (unlink(file_path.c_str()) != 0) {
|
||||||
|
const auto ec = std::error_code{errno, std::generic_category()};
|
||||||
|
LOG_ERROR(Common_Filesystem, "Failed to unlink the file at path={}, ec_message={}",
|
||||||
|
PathToUTF8String(file_path), ec.message());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,11 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||||||
SUB(Lib, AvPlayer) \
|
SUB(Lib, AvPlayer) \
|
||||||
SUB(Lib, Ngs2) \
|
SUB(Lib, Ngs2) \
|
||||||
SUB(Lib, Audio3d) \
|
SUB(Lib, Audio3d) \
|
||||||
|
SUB(Lib, Ime) \
|
||||||
|
SUB(Lib, GameLiveStreaming) \
|
||||||
|
SUB(Lib, Remoteplay) \
|
||||||
|
SUB(Lib, SharePlay) \
|
||||||
|
SUB(Lib, Fiber) \
|
||||||
CLS(Frontend) \
|
CLS(Frontend) \
|
||||||
CLS(Render) \
|
CLS(Render) \
|
||||||
SUB(Render, Vulkan) \
|
SUB(Render, Vulkan) \
|
||||||
|
@ -81,6 +81,11 @@ enum class Class : u8 {
|
|||||||
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
||||||
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
||||||
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
||||||
|
Lib_Ime, ///< The LibSceIme implementation
|
||||||
|
Lib_GameLiveStreaming, ///< The LibSceGameLiveStreaming implementation
|
||||||
|
Lib_Remoteplay, ///< The LibSceRemotePlay implementation
|
||||||
|
Lib_SharePlay, ///< The LibSceSharePlay implemenation
|
||||||
|
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||||
Frontend, ///< Emulator UI
|
Frontend, ///< Emulator UI
|
||||||
Render, ///< Video Core
|
Render, ///< Video Core
|
||||||
Render_Vulkan, ///< Vulkan backend
|
Render_Vulkan, ///< Vulkan backend
|
||||||
|
@ -95,6 +95,18 @@ static auto UserPaths = [] {
|
|||||||
user_dir =
|
user_dir =
|
||||||
std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4";
|
std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4";
|
||||||
}
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
||||||
|
// Check if the "user" directory exists in the current path:
|
||||||
|
if (!std::filesystem::exists(user_dir)) {
|
||||||
|
// If it doesn't exist, use XDG_DATA_HOME if it is set, and provide a standard default
|
||||||
|
const char* xdg_data_home = getenv("XDG_DATA_HOME");
|
||||||
|
if (xdg_data_home != nullptr && strlen(xdg_data_home) > 0) {
|
||||||
|
user_dir = std::filesystem::path(xdg_data_home) / "shadPS4";
|
||||||
|
} else {
|
||||||
|
user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,19 +25,18 @@ asm(".zerofill GUEST_SYSTEM,GUEST_SYSTEM,__guest_system,0xFBFC00000");
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE;
|
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE_PRO;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
[[nodiscard]] constexpr u64 ToWindowsProt(Core::MemoryProt prot) {
|
[[nodiscard]] constexpr u64 ToWindowsProt(Core::MemoryProt prot) {
|
||||||
switch (prot) {
|
if (True(prot & Core::MemoryProt::CpuReadWrite) ||
|
||||||
case Core::MemoryProt::NoAccess:
|
True(prot & Core::MemoryProt::GpuReadWrite)) {
|
||||||
default:
|
|
||||||
return PAGE_NOACCESS;
|
|
||||||
case Core::MemoryProt::CpuRead:
|
|
||||||
return PAGE_READONLY;
|
|
||||||
case Core::MemoryProt::CpuReadWrite:
|
|
||||||
return PAGE_READWRITE;
|
return PAGE_READWRITE;
|
||||||
|
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
|
||||||
|
return PAGE_READONLY;
|
||||||
|
} else {
|
||||||
|
return PAGE_NOACCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,14 +289,13 @@ enum PosixPageProtection {
|
|||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] constexpr PosixPageProtection ToPosixProt(Core::MemoryProt prot) {
|
[[nodiscard]] constexpr PosixPageProtection ToPosixProt(Core::MemoryProt prot) {
|
||||||
switch (prot) {
|
if (True(prot & Core::MemoryProt::CpuReadWrite) ||
|
||||||
case Core::MemoryProt::NoAccess:
|
True(prot & Core::MemoryProt::GpuReadWrite)) {
|
||||||
default:
|
|
||||||
return PAGE_NOACCESS;
|
|
||||||
case Core::MemoryProt::CpuRead:
|
|
||||||
return PAGE_READONLY;
|
|
||||||
case Core::MemoryProt::CpuReadWrite:
|
|
||||||
return PAGE_READWRITE;
|
return PAGE_READWRITE;
|
||||||
|
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
|
||||||
|
return PAGE_READONLY;
|
||||||
|
} else {
|
||||||
|
return PAGE_NOACCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
// 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 <imgui.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/native_clock.h"
|
#include "common/native_clock.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "debug_state.h"
|
#include "debug_state.h"
|
||||||
#include "libraries/kernel/event_queues.h"
|
#include "devtools/widget/common.h"
|
||||||
#include "libraries/kernel/time_management.h"
|
#include "libraries/kernel/time_management.h"
|
||||||
#include "libraries/system/msgdialog.h"
|
#include "libraries/system/msgdialog.h"
|
||||||
|
#include "video_core/amdgpu/pm4_cmds.h"
|
||||||
|
|
||||||
using namespace DebugStateType;
|
using namespace DebugStateType;
|
||||||
|
|
||||||
@ -95,8 +98,68 @@ void DebugStateImpl::ResumeGuestThreads() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugStateImpl::RequestFrameDump(s32 count) {
|
void DebugStateImpl::RequestFrameDump(s32 count) {
|
||||||
|
ASSERT(!DumpingCurrentFrame());
|
||||||
gnm_frame_dump_request_count = count;
|
gnm_frame_dump_request_count = count;
|
||||||
frame_dump_list.clear();
|
frame_dump_list.clear();
|
||||||
frame_dump_list.resize(count);
|
frame_dump_list.resize(count);
|
||||||
waiting_submit_pause = true;
|
waiting_submit_pause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::PushQueueDump(QueueDump dump) {
|
||||||
|
ASSERT(DumpingCurrentFrame());
|
||||||
|
std::unique_lock lock{frame_dump_list_mutex};
|
||||||
|
auto& frame = GetFrameDump();
|
||||||
|
{ // Find draw calls
|
||||||
|
auto data = std::span{dump.data};
|
||||||
|
auto initial_data = data.data();
|
||||||
|
while (!data.empty()) {
|
||||||
|
const auto* header = reinterpret_cast<const AmdGpu::PM4Type3Header*>(data.data());
|
||||||
|
const auto type = header->type;
|
||||||
|
if (type == 2) {
|
||||||
|
data = data.subspan(1);
|
||||||
|
} else if (type != 3) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
const AmdGpu::PM4ItOpcode opcode = header->opcode;
|
||||||
|
if (Core::Devtools::Widget::IsDrawCall(opcode)) {
|
||||||
|
const auto offset =
|
||||||
|
reinterpret_cast<uintptr_t>(header) - reinterpret_cast<uintptr_t>(initial_data);
|
||||||
|
const auto addr = dump.base_addr + offset;
|
||||||
|
waiting_reg_dumps.emplace(addr, &frame);
|
||||||
|
waiting_reg_dumps_dbg.emplace(
|
||||||
|
addr,
|
||||||
|
fmt::format("#{} h({}) queue {} {} {}",
|
||||||
|
frame_dump_list.size() - gnm_frame_dump_request_count, addr,
|
||||||
|
magic_enum::enum_name(dump.type), dump.submit_num, dump.num2));
|
||||||
|
}
|
||||||
|
data = data.subspan(header->NumWords() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.queues.push_back(std::move(dump));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
|
const AmdGpu::Liverpool::Regs& regs) {
|
||||||
|
std::scoped_lock lock{frame_dump_list_mutex};
|
||||||
|
const auto it = waiting_reg_dumps.find(header_addr);
|
||||||
|
if (it == waiting_reg_dumps.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& frame = *it->second;
|
||||||
|
waiting_reg_dumps.erase(it);
|
||||||
|
waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr));
|
||||||
|
auto& dump = frame.regs[header_addr - base_addr];
|
||||||
|
dump.regs = regs;
|
||||||
|
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
||||||
|
if (regs.stage_enable.IsStageEnabled(i)) {
|
||||||
|
auto stage = regs.ProgramForStage(i);
|
||||||
|
if (stage->address_lo != 0) {
|
||||||
|
auto code = stage->Code();
|
||||||
|
dump.stages[i] = ShaderDump{
|
||||||
|
.user_data = *stage,
|
||||||
|
.code = std::vector<u32>{code.begin(), code.end()},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,10 +5,14 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "video_core/amdgpu/liverpool.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
@ -42,10 +46,23 @@ struct QueueDump {
|
|||||||
u32 submit_num;
|
u32 submit_num;
|
||||||
u32 num2; // acb: queue_num; else: buffer_in_submit
|
u32 num2; // acb: queue_num; else: buffer_in_submit
|
||||||
std::vector<u32> data;
|
std::vector<u32> data;
|
||||||
|
uintptr_t base_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderDump {
|
||||||
|
Vulkan::Liverpool::ShaderProgram user_data{};
|
||||||
|
std::vector<u32> code{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RegDump {
|
||||||
|
static constexpr size_t MaxShaderStages = 5;
|
||||||
|
Vulkan::Liverpool::Regs regs{};
|
||||||
|
std::array<ShaderDump, MaxShaderStages> stages{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameDump {
|
struct FrameDump {
|
||||||
std::vector<QueueDump> queues;
|
std::vector<QueueDump> queues;
|
||||||
|
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
||||||
};
|
};
|
||||||
|
|
||||||
class DebugStateImpl {
|
class DebugStateImpl {
|
||||||
@ -61,15 +78,24 @@ class DebugStateImpl {
|
|||||||
std::atomic_int32_t gnm_frame_count = 0;
|
std::atomic_int32_t gnm_frame_count = 0;
|
||||||
|
|
||||||
s32 gnm_frame_dump_request_count = -1;
|
s32 gnm_frame_dump_request_count = -1;
|
||||||
|
std::unordered_map<size_t, FrameDump*> waiting_reg_dumps;
|
||||||
|
std::unordered_map<size_t, std::string> waiting_reg_dumps_dbg;
|
||||||
bool waiting_submit_pause = false;
|
bool waiting_submit_pause = false;
|
||||||
bool should_show_frame_dump = false;
|
bool should_show_frame_dump = false;
|
||||||
|
|
||||||
std::mutex frame_dump_list_mutex;
|
std::shared_mutex frame_dump_list_mutex;
|
||||||
std::vector<FrameDump> frame_dump_list{};
|
std::vector<FrameDump> frame_dump_list{};
|
||||||
|
|
||||||
std::queue<std::string> debug_message_popup;
|
std::queue<std::string> debug_message_popup;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void ShowDebugMessage(std::string message) {
|
||||||
|
if (message.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug_message_popup.push(std::move(message));
|
||||||
|
}
|
||||||
|
|
||||||
void AddCurrentThreadToGuestList();
|
void AddCurrentThreadToGuestList();
|
||||||
|
|
||||||
void RemoveCurrentThreadFromGuestList();
|
void RemoveCurrentThreadFromGuestList();
|
||||||
@ -99,6 +125,11 @@ public:
|
|||||||
return gnm_frame_dump_request_count > 0;
|
return gnm_frame_dump_request_count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DumpingCurrentReg() {
|
||||||
|
std::shared_lock lock{frame_dump_list_mutex};
|
||||||
|
return !waiting_reg_dumps.empty();
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldPauseInSubmit() const {
|
bool ShouldPauseInSubmit() const {
|
||||||
return waiting_submit_pause && gnm_frame_dump_request_count == 0;
|
return waiting_submit_pause && gnm_frame_dump_request_count == 0;
|
||||||
}
|
}
|
||||||
@ -109,17 +140,10 @@ public:
|
|||||||
return frame_dump_list[frame_dump_list.size() - gnm_frame_dump_request_count];
|
return frame_dump_list[frame_dump_list.size() - gnm_frame_dump_request_count];
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushQueueDump(QueueDump dump) {
|
void PushQueueDump(QueueDump dump);
|
||||||
std::unique_lock lock{frame_dump_list_mutex};
|
|
||||||
GetFrameDump().queues.push_back(std::move(dump));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShowDebugMessage(std::string message) {
|
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
if (message.empty()) {
|
const AmdGpu::Liverpool::Regs& regs);
|
||||||
return;
|
|
||||||
}
|
|
||||||
debug_message_popup.push(std::move(message));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // namespace DebugStateType
|
} // namespace DebugStateType
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "imgui/imgui_std.h"
|
#include "imgui/imgui_std.h"
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "layer.h"
|
#include "layer.h"
|
||||||
|
#include "options.h"
|
||||||
#include "widget/frame_dump.h"
|
#include "widget/frame_dump.h"
|
||||||
#include "widget/frame_graph.h"
|
#include "widget/frame_graph.h"
|
||||||
|
|
||||||
@ -18,10 +19,9 @@ using namespace Core::Devtools;
|
|||||||
using L = Core::Devtools::Layer;
|
using L = Core::Devtools::Layer;
|
||||||
|
|
||||||
static bool show_simple_fps = false;
|
static bool show_simple_fps = false;
|
||||||
|
|
||||||
static float fps_scale = 1.0f;
|
static float fps_scale = 1.0f;
|
||||||
|
|
||||||
static bool show_advanced_debug = false;
|
static bool show_advanced_debug = false;
|
||||||
|
|
||||||
static int dump_frame_count = 1;
|
static int dump_frame_count = 1;
|
||||||
|
|
||||||
static Widget::FrameGraph frame_graph;
|
static Widget::FrameGraph frame_graph;
|
||||||
@ -29,12 +29,16 @@ static std::vector<Widget::FrameDumpViewer> frame_viewers;
|
|||||||
|
|
||||||
static float debug_popup_timing = 3.0f;
|
static float debug_popup_timing = 3.0f;
|
||||||
|
|
||||||
|
static bool just_opened_options = false;
|
||||||
|
|
||||||
void L::DrawMenuBar() {
|
void L::DrawMenuBar() {
|
||||||
const auto& ctx = *GImGui;
|
const auto& ctx = *GImGui;
|
||||||
const auto& io = ctx.IO;
|
const auto& io = ctx.IO;
|
||||||
|
|
||||||
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
||||||
|
|
||||||
|
bool open_popup_options = false;
|
||||||
|
|
||||||
if (BeginMainMenuBar()) {
|
if (BeginMainMenuBar()) {
|
||||||
if (BeginMenu("Options")) {
|
if (BeginMenu("Options")) {
|
||||||
if (MenuItemEx("Emulator Paused", nullptr, nullptr, isSystemPaused)) {
|
if (MenuItemEx("Emulator Paused", nullptr, nullptr, isSystemPaused)) {
|
||||||
@ -55,6 +59,7 @@ void L::DrawMenuBar() {
|
|||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
open_popup_options = MenuItem("Options");
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
EndMainMenuBar();
|
EndMainMenuBar();
|
||||||
@ -74,6 +79,11 @@ void L::DrawMenuBar() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (open_popup_options) {
|
||||||
|
OpenPopup("GPU Tools Options");
|
||||||
|
just_opened_options = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawAdvanced() {
|
void L::DrawAdvanced() {
|
||||||
@ -91,13 +101,19 @@ void L::DrawAdvanced() {
|
|||||||
->AddText({10.0f, io.DisplaySize.y - 40.0f}, IM_COL32_WHITE, "Emulator paused");
|
->AddText({10.0f, io.DisplaySize.y - 40.0f}, IM_COL32_WHITE, "Emulator paused");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DebugState.should_show_frame_dump) {
|
if (DebugState.should_show_frame_dump && DebugState.waiting_reg_dumps.empty()) {
|
||||||
DebugState.should_show_frame_dump = false;
|
DebugState.should_show_frame_dump = false;
|
||||||
std::unique_lock lock{DebugState.frame_dump_list_mutex};
|
std::unique_lock lock{DebugState.frame_dump_list_mutex};
|
||||||
while (!DebugState.frame_dump_list.empty()) {
|
while (!DebugState.frame_dump_list.empty()) {
|
||||||
auto frame_dump = std::move(DebugState.frame_dump_list.back());
|
const auto& frame_dump = DebugState.frame_dump_list.back();
|
||||||
DebugState.frame_dump_list.pop_back();
|
|
||||||
frame_viewers.emplace_back(frame_dump);
|
frame_viewers.emplace_back(frame_dump);
|
||||||
|
DebugState.frame_dump_list.pop_back();
|
||||||
|
}
|
||||||
|
static bool first_time = true;
|
||||||
|
if (first_time) {
|
||||||
|
first_time = false;
|
||||||
|
DebugState.ShowDebugMessage("Tip: You can shift+click any\n"
|
||||||
|
"popup to open a new window");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +149,30 @@ void L::DrawAdvanced() {
|
|||||||
debug_popup_timing = 3.0f;
|
debug_popup_timing = 3.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool close_popup_options = true;
|
||||||
|
if (BeginPopupModal("GPU Tools Options", &close_popup_options,
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
static char disassembly_cli[512];
|
||||||
|
|
||||||
|
if (just_opened_options) {
|
||||||
|
just_opened_options = false;
|
||||||
|
auto s = Options.disassembly_cli.copy(disassembly_cli, sizeof(disassembly_cli) - 1);
|
||||||
|
disassembly_cli[s] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
|
||||||
|
if (IsItemHovered()) {
|
||||||
|
SetTooltip(R"(Command to disassemble shaders. Example "dis.exe" --raw "{src}")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Button("Save")) {
|
||||||
|
Options.disassembly_cli = disassembly_cli;
|
||||||
|
SaveIniSettingsToDisk(io.IniFilename);
|
||||||
|
CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawSimple() {
|
void L::DrawSimple() {
|
||||||
@ -140,26 +180,54 @@ void L::DrawSimple() {
|
|||||||
Text("Frame time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
Text("Frame time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LoadSettings(const char* line) {
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
if (sscanf(line, "fps_scale=%f", &f) == 1) {
|
||||||
|
fps_scale = f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "show_advanced_debug=%d", &i) == 1) {
|
||||||
|
show_advanced_debug = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "show_frame_graph=%d", &i) == 1) {
|
||||||
|
frame_graph.is_open = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "dump_frame_count=%d", &i) == 1) {
|
||||||
|
dump_frame_count = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void L::SetupSettings() {
|
void L::SetupSettings() {
|
||||||
frame_graph.is_open = true;
|
frame_graph.is_open = true;
|
||||||
|
|
||||||
|
using SettingLoader = void (*)(const char*);
|
||||||
|
|
||||||
ImGuiSettingsHandler handler{};
|
ImGuiSettingsHandler handler{};
|
||||||
handler.TypeName = "DevtoolsLayer";
|
handler.TypeName = "DevtoolsLayer";
|
||||||
handler.TypeHash = ImHashStr(handler.TypeName);
|
handler.TypeHash = ImHashStr(handler.TypeName);
|
||||||
handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler*, const char* name) {
|
handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler*, const char* name) {
|
||||||
return std::string_view("Data") == name ? (void*)1 : nullptr;
|
if (std::string_view("Data") == name) {
|
||||||
|
static_assert(std::is_same_v<decltype(&LoadSettings), SettingLoader>);
|
||||||
|
return (void*)&LoadSettings;
|
||||||
|
}
|
||||||
|
if (std::string_view("CmdList") == name) {
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<decltype(&Widget::CmdListViewer::LoadConfig), SettingLoader>);
|
||||||
|
return (void*)&Widget::CmdListViewer::LoadConfig;
|
||||||
|
}
|
||||||
|
if (std::string_view("Options") == name) {
|
||||||
|
static_assert(std::is_same_v<decltype(&LoadOptionsConfig), SettingLoader>);
|
||||||
|
return (void*)&LoadOptionsConfig;
|
||||||
|
}
|
||||||
|
return (void*)nullptr;
|
||||||
};
|
};
|
||||||
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void*, const char* line) {
|
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void* handle, const char* line) {
|
||||||
int v;
|
if (handle != nullptr) {
|
||||||
float f;
|
reinterpret_cast<SettingLoader>(handle)(line);
|
||||||
if (sscanf(line, "fps_scale=%f", &f) == 1) {
|
|
||||||
fps_scale = f;
|
|
||||||
} else if (sscanf(line, "show_advanced_debug=%d", &v) == 1) {
|
|
||||||
show_advanced_debug = v != 0;
|
|
||||||
} else if (sscanf(line, "show_frame_graph=%d", &v) == 1) {
|
|
||||||
frame_graph.is_open = v != 0;
|
|
||||||
} else if (sscanf(line, "dump_frame_count=%d", &v) == 1) {
|
|
||||||
dump_frame_count = v;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) {
|
handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) {
|
||||||
@ -169,12 +237,19 @@ void L::SetupSettings() {
|
|||||||
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
|
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
|
||||||
buf->appendf("dump_frame_count=%d\n", dump_frame_count);
|
buf->appendf("dump_frame_count=%d\n", dump_frame_count);
|
||||||
buf->append("\n");
|
buf->append("\n");
|
||||||
|
buf->appendf("[%s][CmdList]\n", handler->TypeName);
|
||||||
|
Widget::CmdListViewer::SerializeConfig(buf);
|
||||||
|
buf->append("\n");
|
||||||
|
buf->appendf("[%s][Options]\n", handler->TypeName);
|
||||||
|
SerializeOptionsConfig(buf);
|
||||||
|
buf->append("\n");
|
||||||
};
|
};
|
||||||
AddSettingsHandler(&handler);
|
AddSettingsHandler(&handler);
|
||||||
|
|
||||||
const ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
const ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
||||||
DockBuilderAddNode(dock_id, 0);
|
DockBuilderAddNode(dock_id, 0);
|
||||||
DockBuilderSetNodePos(dock_id, ImVec2{50.0, 50.0});
|
DockBuilderSetNodePos(dock_id, ImVec2{450.0, 150.0});
|
||||||
|
DockBuilderSetNodeSize(dock_id, ImVec2{400.0, 500.0});
|
||||||
DockBuilderFinish(dock_id);
|
DockBuilderFinish(dock_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
src/core/devtools/options.cpp
Normal file
24
src/core/devtools/options.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools {
|
||||||
|
|
||||||
|
TOptions Options;
|
||||||
|
|
||||||
|
void LoadOptionsConfig(const char* line) {
|
||||||
|
char str[512];
|
||||||
|
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
|
||||||
|
Options.disassembly_cli = str;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
||||||
|
buf->appendf("disassembly_cli=%s\n", Options.disassembly_cli.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools
|
21
src/core/devtools/options.h
Normal file
21
src/core/devtools/options.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 <string>
|
||||||
|
|
||||||
|
struct ImGuiTextBuffer;
|
||||||
|
|
||||||
|
namespace Core::Devtools {
|
||||||
|
|
||||||
|
struct TOptions {
|
||||||
|
std::string disassembly_cli;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TOptions Options;
|
||||||
|
|
||||||
|
void LoadOptionsConfig(const char* line);
|
||||||
|
void SerializeOptionsConfig(ImGuiTextBuffer* buf);
|
||||||
|
|
||||||
|
} // namespace Core::Devtools
|
@ -32,6 +32,26 @@ const char* GetOpCodeName(u32 op);
|
|||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
static bool group_batches = true;
|
||||||
|
static bool show_markers = false;
|
||||||
|
|
||||||
|
void CmdListViewer::LoadConfig(const char* line) {
|
||||||
|
int i;
|
||||||
|
if (sscanf(line, "group_batches=%d", &i) == 1) {
|
||||||
|
group_batches = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "show_markers=%d", &i) == 1) {
|
||||||
|
show_markers = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdListViewer::SerializeConfig(ImGuiTextBuffer* buf) {
|
||||||
|
buf->appendf("group_batches=%d\n", group_batches);
|
||||||
|
buf->appendf("show_markers=%d\n", show_markers);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename HdrType>
|
template <typename HdrType>
|
||||||
static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
||||||
HdrType curr_pm4 = this_pm4;
|
HdrType curr_pm4 = this_pm4;
|
||||||
@ -43,10 +63,11 @@ static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
|||||||
return curr_pm4;
|
return curr_pm4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ParsePolygonControl(u32 value) {
|
void ParsePolygonControl(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<AmdGpu::Liverpool::PolygonControl const&>(value);
|
auto const reg = reinterpret_cast<AmdGpu::Liverpool::PolygonControl const&>(value);
|
||||||
|
|
||||||
if (BeginTable("PA_SU_SC_MODE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("PA_SU_SC_MODE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("CULL_FRONT");
|
Text("CULL_FRONT");
|
||||||
@ -126,14 +147,17 @@ static void ParsePolygonControl(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.multi_prim_ib_ena.Value());
|
Text("%X", reg.multi_prim_ib_ena.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseAaConfig(u32 value) {
|
void ParseAaConfig(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::AaConfig const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::AaConfig const&>(value);
|
||||||
|
|
||||||
if (BeginTable("PA_SC_AA_CONFIG", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("PA_SC_AA_CONFIG", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("MSAA_NUM_SAMPLES");
|
Text("MSAA_NUM_SAMPLES");
|
||||||
@ -164,14 +188,17 @@ static void ParseAaConfig(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.detail_to_exposed_mode.Value());
|
Text("%X", reg.detail_to_exposed_mode.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseViewportControl(u32 value) {
|
void ParseViewportControl(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::ViewportControl const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::ViewportControl const&>(value);
|
||||||
|
|
||||||
if (BeginTable("PA_CL_VTE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("PA_CL_VTE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("VPORT_X_SCALE_ENA");
|
Text("VPORT_X_SCALE_ENA");
|
||||||
@ -232,14 +259,17 @@ static void ParseViewportControl(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.perfcounter_ref.Value());
|
Text("%X", reg.perfcounter_ref.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseColorControl(u32 value) {
|
void ParseColorControl(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::ColorControl const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::ColorControl const&>(value);
|
||||||
|
|
||||||
if (BeginTable("CB_COLOR_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("CB_COLOR_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("DISABLE_DUAL_QUAD__VI");
|
Text("DISABLE_DUAL_QUAD__VI");
|
||||||
@ -264,14 +294,17 @@ static void ParseColorControl(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.rop3.Value());
|
Text("%X", reg.rop3.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseColor0Info(u32 value) {
|
void ParseColor0Info(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Info const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Info const&>(value);
|
||||||
|
|
||||||
if (BeginTable("CB_COLOR_INFO", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("CB_COLOR_INFO", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("ENDIAN");
|
Text("ENDIAN");
|
||||||
@ -380,14 +413,17 @@ static void ParseColor0Info(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.cmask_addr_type.Value());
|
Text("%X", reg.cmask_addr_type.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseColor0Attrib(u32 value) {
|
void ParseColor0Attrib(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Attrib const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Attrib const&>(value);
|
||||||
|
|
||||||
if (BeginTable("CB_COLOR_ATTRIB", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("CB_COLOR_ATTRIB", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("TILE_MODE_INDEX");
|
Text("TILE_MODE_INDEX");
|
||||||
@ -424,14 +460,17 @@ static void ParseColor0Attrib(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.force_dst_alpha_1.Value());
|
Text("%X", reg.force_dst_alpha_1.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseBlendControl(u32 value) {
|
void ParseBlendControl(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::BlendControl const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::BlendControl const&>(value);
|
||||||
|
|
||||||
if (BeginTable("CB_BLEND_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("CB_BLEND_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("COLOR_SRCBLEND");
|
Text("COLOR_SRCBLEND");
|
||||||
@ -490,14 +529,17 @@ static void ParseBlendControl(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.disable_rop3.Value());
|
Text("%X", reg.disable_rop3.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseDepthRenderControl(u32 value) {
|
void ParseDepthRenderControl(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::DepthRenderControl const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::DepthRenderControl const&>(value);
|
||||||
|
|
||||||
if (BeginTable("DB_RENDER_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("DB_RENDER_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("DEPTH_CLEAR_ENABLE");
|
Text("DEPTH_CLEAR_ENABLE");
|
||||||
@ -558,14 +600,17 @@ static void ParseDepthRenderControl(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.decompress_enable.Value());
|
Text("%X", reg.decompress_enable.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseDepthControl(u32 value) {
|
void ParseDepthControl(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::DepthControl const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::DepthControl const&>(value);
|
||||||
|
|
||||||
if (BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("STENCIL_ENABLE");
|
Text("STENCIL_ENABLE");
|
||||||
@ -628,14 +673,17 @@ static void ParseDepthControl(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.disable_color_writes_on_depth_pass.Value());
|
Text("%X", reg.disable_color_writes_on_depth_pass.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseEqaa(u32 value) {
|
void ParseEqaa(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::Eqaa const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::Eqaa const&>(value);
|
||||||
|
|
||||||
if (BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("MAX_ANCHOR_SAMPLES");
|
Text("MAX_ANCHOR_SAMPLES");
|
||||||
@ -708,14 +756,17 @@ static void ParseEqaa(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.enable_postz_overrasterization.Value());
|
Text("%X", reg.enable_postz_overrasterization.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ParseZInfo(u32 value) {
|
void ParseZInfo(u32 value, bool begin_table) {
|
||||||
auto const reg = reinterpret_cast<Liverpool::DepthBuffer::ZInfo const&>(value);
|
auto const reg = reinterpret_cast<Liverpool::DepthBuffer::ZInfo const&>(value);
|
||||||
|
|
||||||
if (BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (!begin_table ||
|
||||||
|
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
TableSetColumnIndex(0);
|
TableSetColumnIndex(0);
|
||||||
Text("FORMAT");
|
Text("FORMAT");
|
||||||
@ -776,40 +827,41 @@ static void ParseZInfo(u32 value) {
|
|||||||
TableSetColumnIndex(1);
|
TableSetColumnIndex(1);
|
||||||
Text("%X", reg.zrange_precision.Value());
|
Text("%X", reg.zrange_precision.Value());
|
||||||
|
|
||||||
|
if (begin_table) {
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CmdListViewer::OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body) {
|
void CmdListViewer::OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body) {
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
enum class NOP_PAYLOAD : u32 {
|
#define NOP_PAYLOAD \
|
||||||
ACB_SUBMIT_MRK = 0x68750013,
|
P(PUSH_MARKER, 0x68750001) \
|
||||||
ALLOC_ALIGN8 = 0x68753000,
|
P(POP_MARKER, 0x68750002) \
|
||||||
PUSH_MARKER = 0x68750001,
|
P(SET_MARKER, 0x68750003) \
|
||||||
SET_VSHARP = 0x68750004,
|
P(SET_VSHARP, 0x68750004) \
|
||||||
SET_TSHARP = 0x68750005,
|
P(SET_TSHARP, 0x68750005) \
|
||||||
SET_SSHARP = 0x68750006,
|
P(SET_SSHARP, 0x68750006) \
|
||||||
SET_USER_DATA = 0x6875000d,
|
P(ACB_SUBMIT_MRK, 0x68750013) \
|
||||||
};
|
P(SET_USER_DATA, 0x6875000D) \
|
||||||
auto get_noppayload_text = [](NOP_PAYLOAD const nop_payload) {
|
P(PATCHED_FLIP, 0x68750776) \
|
||||||
|
P(PREPARE_FLIP, 0x68750777) \
|
||||||
|
P(PREPARE_FLIP_LABEL, 0x68750778) \
|
||||||
|
P(PREPARE_FLIP_INTERRUPT, 0x68750780) \
|
||||||
|
P(PREPARE_FLIP_INTERRUPT_LABEL, 0x68750781) \
|
||||||
|
P(ALLOC_ALIGN8, 0x68753000)
|
||||||
|
|
||||||
|
auto get_nop_payload_text = [](u32 const nop_payload) {
|
||||||
switch (nop_payload) {
|
switch (nop_payload) {
|
||||||
case NOP_PAYLOAD::ACB_SUBMIT_MRK:
|
#define P(name, value) \
|
||||||
return "ACB_SUBMIT_MRK"sv;
|
case value: \
|
||||||
case NOP_PAYLOAD::ALLOC_ALIGN8:
|
return #name##sv;
|
||||||
return "ALLOC_ALIGN8"sv;
|
NOP_PAYLOAD
|
||||||
case NOP_PAYLOAD::PUSH_MARKER:
|
#undef P
|
||||||
return "PUSH_MARKER"sv;
|
default:
|
||||||
case NOP_PAYLOAD::SET_VSHARP:
|
|
||||||
return "SET_VSHARP"sv;
|
|
||||||
case NOP_PAYLOAD::SET_TSHARP:
|
|
||||||
return "SET_TSHARP"sv;
|
|
||||||
case NOP_PAYLOAD::SET_SSHARP:
|
|
||||||
return "SET_SSHARP"sv;
|
|
||||||
case NOP_PAYLOAD::SET_USER_DATA:
|
|
||||||
return "SET_USER_DATA"sv;
|
|
||||||
}
|
|
||||||
return ""sv;
|
return ""sv;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Separator();
|
Separator();
|
||||||
@ -822,7 +874,7 @@ void CmdListViewer::OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body)
|
|||||||
for (unsigned i = 0; i < pkt->header.count + 1; ++i) {
|
for (unsigned i = 0; i < pkt->header.count + 1; ++i) {
|
||||||
Text("%02X: %08X", i, payload[i]);
|
Text("%02X: %08X", i, payload[i]);
|
||||||
if ((payload[i] & 0xffff0000) == 0x68750000) {
|
if ((payload[i] & 0xffff0000) == 0x68750000) {
|
||||||
const auto& e = get_noppayload_text((NOP_PAYLOAD)payload[i]);
|
const auto& e = get_nop_payload_text(payload[i]);
|
||||||
if (!e.empty()) {
|
if (!e.empty()) {
|
||||||
SameLine();
|
SameLine();
|
||||||
Text("(%s)", e.data());
|
Text("(%s)", e.data());
|
||||||
@ -836,7 +888,7 @@ void CmdListViewer::OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* b
|
|||||||
Separator();
|
Separator();
|
||||||
BeginGroup();
|
BeginGroup();
|
||||||
|
|
||||||
auto const* pkt = reinterpret_cast<AmdGpu::PM4CmdSetBase const*>(header);
|
// auto const* pkt = reinterpret_cast<AmdGpu::PM4CmdSetBase const*>(header);
|
||||||
Text("BASE_INDEX: %08X", body[0]);
|
Text("BASE_INDEX: %08X", body[0]);
|
||||||
Text("ADDRESS0 : %08X", body[1]);
|
Text("ADDRESS0 : %08X", body[1]);
|
||||||
Text("ADDRESS1 : %08X", body[2]);
|
Text("ADDRESS1 : %08X", body[2]);
|
||||||
@ -1025,20 +1077,31 @@ void CmdListViewer::OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const*
|
|||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cmd_list)
|
CmdListViewer::CmdListViewer(DebugStateType::FrameDump* _frame_dump,
|
||||||
: parent(parent) {
|
const std::vector<u32>& cmd_list, uintptr_t _base_addr,
|
||||||
|
std::string _name)
|
||||||
|
: frame_dump(_frame_dump), base_addr(_base_addr), name(std::move(_name)) {
|
||||||
using namespace AmdGpu;
|
using namespace AmdGpu;
|
||||||
|
|
||||||
cmdb_addr = (uintptr_t)cmd_list.data();
|
cmdb_addr = (uintptr_t)cmd_list.data();
|
||||||
cmdb_size = cmd_list.size() * sizeof(u32);
|
cmdb_size = cmd_list.size() * sizeof(u32);
|
||||||
|
|
||||||
|
cmdb_view_name = fmt::format("[GFX] Command buffer {}###cmdview_hex_{}", this->name, cmdb_addr);
|
||||||
|
cmdb_view.Open = false;
|
||||||
|
cmdb_view.ReadOnly = true;
|
||||||
|
|
||||||
auto const* pm4_hdr = reinterpret_cast<PM4Header const*>(cmdb_addr);
|
auto const* pm4_hdr = reinterpret_cast<PM4Header const*>(cmdb_addr);
|
||||||
|
|
||||||
size_t processed_size = 0;
|
size_t processed_size = 0;
|
||||||
size_t prev_offset = 0;
|
size_t prev_offset = 0;
|
||||||
|
u32 batch_id = 0;
|
||||||
|
|
||||||
std::string marker{};
|
std::string marker{};
|
||||||
|
|
||||||
|
if (cmdb_size > 0) {
|
||||||
|
events.emplace_back(BatchBegin{.id = 0});
|
||||||
|
}
|
||||||
|
|
||||||
while (processed_size < cmdb_size) {
|
while (processed_size < cmdb_size) {
|
||||||
auto* next_pm4_hdr = GetNext(pm4_hdr, 1);
|
auto* next_pm4_hdr = GetNext(pm4_hdr, 1);
|
||||||
auto processed_len =
|
auto processed_len =
|
||||||
@ -1048,22 +1111,28 @@ CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cm
|
|||||||
if (pm4_hdr->type == PM4Type3Header::TYPE) {
|
if (pm4_hdr->type == PM4Type3Header::TYPE) {
|
||||||
|
|
||||||
auto const* pm4_t3 = reinterpret_cast<PM4Type3Header const*>(pm4_hdr);
|
auto const* pm4_t3 = reinterpret_cast<PM4Type3Header const*>(pm4_hdr);
|
||||||
|
auto opcode = pm4_t3->opcode;
|
||||||
|
|
||||||
if (pm4_t3->opcode == PM4ItOpcode::Nop) {
|
if (opcode == PM4ItOpcode::Nop) {
|
||||||
auto const* it_body = reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
auto const* it_body = reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
||||||
if (it_body[0] == 0x68750001) {
|
switch (it_body[0]) {
|
||||||
|
case PM4CmdNop::PayloadType::DebugSetMarker:
|
||||||
marker = std::string{(char*)&it_body[1]};
|
marker = std::string{(char*)&it_body[1]};
|
||||||
|
break;
|
||||||
|
case PM4CmdNop::PayloadType::DebugMarkerPush:
|
||||||
|
events.emplace_back(PushMarker{
|
||||||
|
.name = std::string{(char*)&it_body[1]},
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case PM4CmdNop::PayloadType::DebugMarkerPop:
|
||||||
|
events.emplace_back(PopMarker{});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pm4_t3->opcode == PM4ItOpcode::DispatchDirect ||
|
if (IsDrawCall(opcode)) {
|
||||||
pm4_t3->opcode == PM4ItOpcode::DispatchIndirect ||
|
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndex2 ||
|
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndexAuto ||
|
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndexOffset2 ||
|
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndexIndirect
|
|
||||||
// ...
|
|
||||||
) {
|
|
||||||
// All these commands are terminated by NOP at the end, so
|
// All these commands are terminated by NOP at the end, so
|
||||||
// it is safe to skip it to be even with CP
|
// it is safe to skip it to be even with CP
|
||||||
// next_pm4_hdr = get_next(next_pm4_hdr, 1);
|
// next_pm4_hdr = get_next(next_pm4_hdr, 1);
|
||||||
@ -1071,15 +1140,17 @@ CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cm
|
|||||||
// processed_len += nop_len;
|
// processed_len += nop_len;
|
||||||
// processed_size += nop_len;
|
// processed_size += nop_len;
|
||||||
|
|
||||||
batches.emplace_back(BatchInfo{
|
events.emplace_back(BatchInfo{
|
||||||
marker,
|
.id = batch_id++,
|
||||||
prev_offset,
|
.marker = marker,
|
||||||
processed_size,
|
.start_addr = prev_offset,
|
||||||
processed_size - processed_len,
|
.end_addr = processed_size,
|
||||||
pm4_t3->opcode,
|
.command_addr = processed_size - processed_len,
|
||||||
|
.type = opcode,
|
||||||
});
|
});
|
||||||
prev_offset = processed_size;
|
prev_offset = processed_size;
|
||||||
marker.clear();
|
marker.clear();
|
||||||
|
events.emplace_back(BatchBegin{.id = batch_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,18 +1159,58 @@ CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cm
|
|||||||
|
|
||||||
// state batch (last)
|
// state batch (last)
|
||||||
if (processed_size - prev_offset > 0) {
|
if (processed_size - prev_offset > 0) {
|
||||||
batches.emplace_back(BatchInfo{
|
events.emplace_back(BatchInfo{
|
||||||
marker,
|
.id = batch_id++,
|
||||||
prev_offset,
|
.marker = marker,
|
||||||
processed_size,
|
.start_addr = prev_offset,
|
||||||
0,
|
.end_addr = processed_size,
|
||||||
static_cast<PM4ItOpcode>(0xFF),
|
.command_addr = 0,
|
||||||
|
.type = static_cast<PM4ItOpcode>(0xFF),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!events.empty() && std::holds_alternative<BatchBegin>(events.back())) {
|
||||||
|
events.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdListViewer::Draw() {
|
void CmdListViewer::Draw() {
|
||||||
|
const auto& ctx = *GetCurrentContext();
|
||||||
|
|
||||||
|
if (batch_view.open) {
|
||||||
|
batch_view.Draw();
|
||||||
|
}
|
||||||
|
for (auto it = extra_batch_view.begin(); it != extra_batch_view.end();) {
|
||||||
|
if (!it->open) {
|
||||||
|
it = extra_batch_view.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it->Draw();
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdb_view.Open) {
|
||||||
|
MemoryEditor::Sizes s;
|
||||||
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
|
SetNextWindowSize({s.WindowWidth, s.WindowWidth * 0.6f}, ImGuiCond_FirstUseEver);
|
||||||
|
SetNextWindowSizeConstraints({0.0f}, {s.WindowWidth, FLT_MAX});
|
||||||
|
if (Begin(cmdb_view_name.c_str(), &cmdb_view.Open,
|
||||||
|
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
cmdb_view.DrawContents((void*)cmdb_addr, cmdb_size, base_addr);
|
||||||
|
if (cmdb_view.ContentsWidthChanged) {
|
||||||
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
|
SetWindowSize({s.WindowWidth, s.WindowWidth * 0.6f});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
PushID(name.c_str());
|
||||||
if (BeginChild("cmd_queue", {})) {
|
if (BeginChild("cmd_queue", {})) {
|
||||||
|
|
||||||
|
Checkbox("Group batches", &group_batches);
|
||||||
|
SameLine();
|
||||||
|
Checkbox("Show markers", &show_markers);
|
||||||
|
|
||||||
char queue_name[32]{};
|
char queue_name[32]{};
|
||||||
if (vqid < 254) {
|
if (vqid < 254) {
|
||||||
std::snprintf(queue_name, sizeof(queue_name), "%s %d", vqid > 254 ? "GFX" : "ASC",
|
std::snprintf(queue_name, sizeof(queue_name), "%s %d", vqid > 254 ? "GFX" : "ASC",
|
||||||
@ -1111,28 +1222,121 @@ void CmdListViewer::Draw() {
|
|||||||
Text("queue : %s", queue_name);
|
Text("queue : %s", queue_name);
|
||||||
Text("base addr: %08llX", cmdb_addr);
|
Text("base addr: %08llX", cmdb_addr);
|
||||||
SameLine();
|
SameLine();
|
||||||
if (SmallButton(">")) {
|
if (SmallButton("Memory >")) {
|
||||||
parent->cmdb_view.Open ^= true;
|
cmdb_view.Open ^= true;
|
||||||
}
|
}
|
||||||
Text("size : %04llX", cmdb_size);
|
Text("size : %04llX", cmdb_size);
|
||||||
Separator();
|
Separator();
|
||||||
|
|
||||||
char batch_hdr[128];
|
if (TreeNode("Batches")) {
|
||||||
for (int batch_id = 0; batch_id < batches.size(); ++batch_id) {
|
int tree_depth = 0;
|
||||||
auto processed_size = 0ull;
|
int tree_depth_show = 0;
|
||||||
auto const* pm4_hdr =
|
|
||||||
reinterpret_cast<PM4Header const*>(cmdb_addr + batches[batch_id].start_addr);
|
|
||||||
|
|
||||||
sprintf(batch_hdr, "%08llX: batch-%03d | %s", cmdb_addr + batches[batch_id].start_addr,
|
u32 last_batch_id = ~0u;
|
||||||
batch_id, batches[batch_id].marker.c_str());
|
if (!events.empty() && std::holds_alternative<BatchInfo>(events.back())) {
|
||||||
|
last_batch_id = std::get<BatchInfo>(events.back()).id;
|
||||||
if (batch_id == batch_bp) { // highlight batch at breakpoint
|
|
||||||
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batches[batch_id].type == static_cast<AmdGpu::PM4ItOpcode>(0xFF) ||
|
u32 batch_id = ~0u;
|
||||||
CollapsingHeader(batch_hdr)) {
|
u32 current_highlight_batch = ~0u;
|
||||||
auto const batch_sz = batches[batch_id].end_addr - batches[batch_id].start_addr;
|
|
||||||
|
int id = 0;
|
||||||
|
PushID(0);
|
||||||
|
for (const auto& event : events) {
|
||||||
|
PopID();
|
||||||
|
PushID(id++);
|
||||||
|
|
||||||
|
if (std::holds_alternative<BatchBegin>(event)) {
|
||||||
|
batch_id = std::get<BatchBegin>(event).id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_markers) {
|
||||||
|
if (std::holds_alternative<PushMarker>(event)) {
|
||||||
|
if (tree_depth_show >= tree_depth) {
|
||||||
|
auto& marker = std::get<PushMarker>(event);
|
||||||
|
bool show = TreeNode(&event, "%s", marker.name.c_str());
|
||||||
|
if (show) {
|
||||||
|
tree_depth_show++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tree_depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<PopMarker>(event)) {
|
||||||
|
if (tree_depth_show >= tree_depth) {
|
||||||
|
tree_depth_show--;
|
||||||
|
TreePop();
|
||||||
|
}
|
||||||
|
tree_depth--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tree_depth_show < tree_depth) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::holds_alternative<BatchInfo>(event)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& batch = std::get<BatchInfo>(event);
|
||||||
|
auto const* pm4_hdr =
|
||||||
|
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);
|
||||||
|
|
||||||
|
char batch_hdr[128];
|
||||||
|
if (batch.type == static_cast<AmdGpu::PM4ItOpcode>(0xFF)) {
|
||||||
|
snprintf(batch_hdr, sizeof(batch_hdr), "State batch");
|
||||||
|
} else if (!batch.marker.empty()) {
|
||||||
|
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s | %s",
|
||||||
|
cmdb_addr + batch.start_addr, batch.id,
|
||||||
|
Gcn::GetOpCodeName(static_cast<u32>(batch.type)),
|
||||||
|
batch.marker.c_str());
|
||||||
|
} else {
|
||||||
|
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s",
|
||||||
|
cmdb_addr + batch.start_addr, batch.id,
|
||||||
|
Gcn::GetOpCodeName(static_cast<u32>(batch.type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch.id == batch_bp) { // highlight batch at breakpoint
|
||||||
|
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
||||||
|
}
|
||||||
|
if (batch.id == highlight_batch) {
|
||||||
|
PushStyleColor(ImGuiCol_Text, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto open_batch_view = [&, this] {
|
||||||
|
if (frame_dump->regs.contains(batch.command_addr)) {
|
||||||
|
auto data = frame_dump->regs.at(batch.command_addr);
|
||||||
|
if (GetIO().KeyShift) {
|
||||||
|
auto& pop = extra_batch_view.emplace_back();
|
||||||
|
pop.SetData(data, batch_id);
|
||||||
|
pop.open = true;
|
||||||
|
} else {
|
||||||
|
batch_view.SetData(data, batch_id);
|
||||||
|
batch_view.open = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool show_batch_content = true;
|
||||||
|
|
||||||
|
if (group_batches) {
|
||||||
|
show_batch_content =
|
||||||
|
CollapsingHeader(batch_hdr, ImGuiTreeNodeFlags_AllowOverlap);
|
||||||
|
SameLine(GetContentRegionAvail().x - 40.0f);
|
||||||
|
if (Button("->", {40.0f, 0.0f})) {
|
||||||
|
open_batch_view();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_batch_content) {
|
||||||
|
auto processed_size = 0ull;
|
||||||
|
auto bb = ctx.LastItemData.Rect;
|
||||||
|
if (group_batches) {
|
||||||
|
Indent();
|
||||||
|
}
|
||||||
|
auto const batch_sz = batch.end_addr - batch.start_addr;
|
||||||
|
|
||||||
while (processed_size < batch_sz) {
|
while (processed_size < batch_sz) {
|
||||||
AmdGpu::PM4ItOpcode op{0xFFu};
|
AmdGpu::PM4ItOpcode op{0xFFu};
|
||||||
|
|
||||||
@ -1141,25 +1345,39 @@ void CmdListViewer::Draw() {
|
|||||||
reinterpret_cast<AmdGpu::PM4Type3Header const*>(pm4_hdr);
|
reinterpret_cast<AmdGpu::PM4Type3Header const*>(pm4_hdr);
|
||||||
op = pm4_t3->opcode;
|
op = pm4_t3->opcode;
|
||||||
|
|
||||||
static char header_name[128];
|
char header_name[128];
|
||||||
sprintf(header_name, "%08llX: %s",
|
sprintf(header_name, "%08llX: %s",
|
||||||
cmdb_addr + batches[batch_id].start_addr + processed_size,
|
cmdb_addr + batch.start_addr + processed_size,
|
||||||
Gcn::GetOpCodeName((u32)op));
|
Gcn::GetOpCodeName((u32)op));
|
||||||
|
|
||||||
if (TreeNode(header_name)) {
|
bool open_pm4 = TreeNode(header_name);
|
||||||
bool just_opened = IsItemToggledOpen();
|
if (!group_batches) {
|
||||||
if (BeginTable("split", 1)) {
|
if (IsDrawCall(op)) {
|
||||||
TableNextColumn();
|
SameLine(GetContentRegionAvail().x - 40.0f);
|
||||||
Text("size: %d", pm4_hdr->count + 1);
|
if (Button("->", {40.0f, 0.0f})) {
|
||||||
|
open_batch_view();
|
||||||
if (just_opened) {
|
}
|
||||||
|
}
|
||||||
|
if (IsItemHovered() && ctx.IO.KeyShift) {
|
||||||
|
if (BeginTooltip()) {
|
||||||
|
Text("Batch %d", batch_id);
|
||||||
|
EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (open_pm4) {
|
||||||
|
if (IsItemToggledOpen()) {
|
||||||
// Editor
|
// Editor
|
||||||
parent->cmdb_view.GotoAddrAndHighlight(
|
cmdb_view.GotoAddrAndHighlight(
|
||||||
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr,
|
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr,
|
||||||
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr +
|
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr +
|
||||||
(pm4_hdr->count + 2) * 4);
|
(pm4_hdr->count + 2) * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BeginTable("split", 1)) {
|
||||||
|
TableNextColumn();
|
||||||
|
Text("size: %d", pm4_hdr->count + 1);
|
||||||
|
|
||||||
auto const* it_body =
|
auto const* it_body =
|
||||||
reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
||||||
|
|
||||||
@ -1196,6 +1414,7 @@ void CmdListViewer::Draw() {
|
|||||||
}
|
}
|
||||||
TreePop();
|
TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Text("<UNK PACKET>");
|
Text("<UNK PACKET>");
|
||||||
}
|
}
|
||||||
@ -1206,18 +1425,37 @@ void CmdListViewer::Draw() {
|
|||||||
pm4_hdr = next_pm4_hdr;
|
pm4_hdr = next_pm4_hdr;
|
||||||
processed_size += processed_len;
|
processed_size += processed_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (group_batches) {
|
||||||
|
Unindent();
|
||||||
|
};
|
||||||
|
bb = {{0.0f, bb.Max.y}, ctx.LastItemData.Rect.Max};
|
||||||
|
if (bb.Contains(ctx.IO.MousePos)) {
|
||||||
|
current_highlight_batch = batch.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch_id == batch_bp) {
|
if (batch.id == highlight_batch) {
|
||||||
PopStyleColor();
|
PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch_id == batches.size() - 2) {
|
if (batch.id == batch_bp) {
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch.id == last_batch_id) {
|
||||||
Separator();
|
Separator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PopID();
|
||||||
|
|
||||||
|
highlight_batch = current_highlight_batch;
|
||||||
|
|
||||||
|
TreePop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EndChild();
|
EndChild();
|
||||||
|
PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
@ -5,10 +5,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "video_core/buffer_cache/buffer_cache.h"
|
#include "imgui_memory_editor.h"
|
||||||
|
#include "reg_view.h"
|
||||||
|
|
||||||
namespace AmdGpu {
|
namespace AmdGpu {
|
||||||
union PM4Type3Header;
|
union PM4Type3Header;
|
||||||
@ -19,43 +23,50 @@ namespace Core::Devtools::Widget {
|
|||||||
|
|
||||||
class FrameDumpViewer;
|
class FrameDumpViewer;
|
||||||
|
|
||||||
class CmdListViewer {
|
void ParsePolygonControl(u32 value, bool begin_table = true);
|
||||||
/*
|
void ParseAaConfig(u32 value, bool begin_table = true);
|
||||||
* Generic PM4 header
|
void ParseViewportControl(u32 value, bool begin_table = true);
|
||||||
*/
|
void ParseColorControl(u32 value, bool begin_table = true);
|
||||||
union PM4Header {
|
void ParseColor0Info(u32 value, bool begin_table = true);
|
||||||
struct {
|
void ParseColor0Attrib(u32 value, bool begin_table = true);
|
||||||
u32 reserved : 16;
|
void ParseBlendControl(u32 value, bool begin_table = true);
|
||||||
u32 count : 14;
|
void ParseDepthRenderControl(u32 value, bool begin_table = true);
|
||||||
u32 type : 2; // PM4_TYPE
|
void ParseDepthControl(u32 value, bool begin_table = true);
|
||||||
};
|
void ParseEqaa(u32 value, bool begin_table = true);
|
||||||
u32 u32All;
|
void ParseZInfo(u32 value, bool begin_table = true);
|
||||||
};
|
|
||||||
struct BatchInfo {
|
|
||||||
std::string marker{};
|
|
||||||
size_t start_addr;
|
|
||||||
size_t end_addr;
|
|
||||||
size_t command_addr;
|
|
||||||
AmdGpu::PM4ItOpcode type;
|
|
||||||
bool bypass{false};
|
|
||||||
};
|
|
||||||
|
|
||||||
FrameDumpViewer* parent;
|
class CmdListViewer {
|
||||||
std::vector<BatchInfo> batches{};
|
|
||||||
|
DebugStateType::FrameDump* frame_dump;
|
||||||
|
|
||||||
|
uintptr_t base_addr;
|
||||||
|
std::string name;
|
||||||
|
std::vector<GPUEvent> events{};
|
||||||
uintptr_t cmdb_addr;
|
uintptr_t cmdb_addr;
|
||||||
size_t cmdb_size;
|
size_t cmdb_size;
|
||||||
|
|
||||||
|
std::string cmdb_view_name;
|
||||||
|
MemoryEditor cmdb_view;
|
||||||
|
|
||||||
int batch_bp{-1};
|
int batch_bp{-1};
|
||||||
int vqid{255};
|
int vqid{255};
|
||||||
|
u32 highlight_batch{~0u};
|
||||||
|
|
||||||
void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
RegView batch_view;
|
||||||
void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
std::vector<RegView> extra_batch_view;
|
||||||
void OnSetContextReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
|
||||||
void OnSetShReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
static void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
static void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
static void OnSetContextReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
static void OnSetShReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
static void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cmd_list);
|
static void LoadConfig(const char* line);
|
||||||
|
static void SerializeConfig(ImGuiTextBuffer* buf);
|
||||||
|
|
||||||
|
explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list,
|
||||||
|
uintptr_t base_addr = 0, std::string name = "");
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
};
|
};
|
||||||
|
100
src/core/devtools/widget/common.h
Normal file
100
src/core/devtools/widget/common.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic PM4 header
|
||||||
|
*/
|
||||||
|
union PM4Header {
|
||||||
|
struct {
|
||||||
|
u32 reserved : 16;
|
||||||
|
u32 count : 14;
|
||||||
|
u32 type : 2; // PM4_TYPE
|
||||||
|
};
|
||||||
|
u32 u32All;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PushMarker {
|
||||||
|
std::string name{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PopMarker {};
|
||||||
|
|
||||||
|
struct BatchBegin {
|
||||||
|
u32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BatchInfo {
|
||||||
|
u32 id;
|
||||||
|
std::string marker{};
|
||||||
|
size_t start_addr;
|
||||||
|
size_t end_addr;
|
||||||
|
size_t command_addr;
|
||||||
|
AmdGpu::PM4ItOpcode type;
|
||||||
|
bool bypass{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
using GPUEvent = std::variant<PushMarker, PopMarker, BatchBegin, BatchInfo>;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void DrawRow(const char* text, const char* fmt, Args... args) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted(text);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
char buf[128];
|
||||||
|
snprintf(buf, sizeof(buf), fmt, args...);
|
||||||
|
ImGui::TextUnformatted(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename V = u32>
|
||||||
|
void DrawEnumRow(const char* text, T value) {
|
||||||
|
DrawRow(text, "%X (%s)", V(value), magic_enum::enum_name(value).data());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename V, typename... Extra>
|
||||||
|
void DrawMultipleRow(const char* text, const char* fmt, V arg, Extra&&... extra_args) {
|
||||||
|
DrawRow(text, fmt, arg);
|
||||||
|
if constexpr (sizeof...(extra_args) > 0) {
|
||||||
|
DrawMultipleRow(std::forward<Extra>(extra_args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static void DoTooltip(const char* str_id, Args&&... args) {
|
||||||
|
if (ImGui::BeginTooltip()) {
|
||||||
|
if (ImGui::BeginTable(str_id, 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
|
DrawMultipleRow(std::forward<Args>(args)...);
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
|
||||||
|
using AmdGpu::PM4ItOpcode;
|
||||||
|
switch (opcode) {
|
||||||
|
case PM4ItOpcode::DrawIndex2:
|
||||||
|
case PM4ItOpcode::DrawIndexOffset2:
|
||||||
|
case PM4ItOpcode::DrawIndexAuto:
|
||||||
|
case PM4ItOpcode::DrawIndirect:
|
||||||
|
case PM4ItOpcode::DrawIndexIndirect:
|
||||||
|
case PM4ItOpcode::DispatchDirect:
|
||||||
|
case PM4ItOpcode::DispatchIndirect:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
@ -36,7 +36,8 @@ static std::array<char, 3> small_int_to_str(const s32 i) {
|
|||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
FrameDumpViewer::FrameDumpViewer(FrameDump _frame_dump) : frame_dump(std::move(_frame_dump)) {
|
FrameDumpViewer::FrameDumpViewer(const FrameDump& _frame_dump)
|
||||||
|
: frame_dump(std::make_shared<FrameDump>(_frame_dump)) {
|
||||||
static int unique_id = 0;
|
static int unique_id = 0;
|
||||||
id = unique_id++;
|
id = unique_id++;
|
||||||
|
|
||||||
@ -44,20 +45,19 @@ FrameDumpViewer::FrameDumpViewer(FrameDump _frame_dump) : frame_dump(std::move(_
|
|||||||
selected_submit_num = 0;
|
selected_submit_num = 0;
|
||||||
selected_queue_num2 = 0;
|
selected_queue_num2 = 0;
|
||||||
|
|
||||||
cmd_list_viewer.reserve(frame_dump.queues.size());
|
cmd_list_viewer.reserve(frame_dump->queues.size());
|
||||||
for (const auto& cmd : frame_dump.queues) {
|
for (const auto& cmd : frame_dump->queues) {
|
||||||
cmd_list_viewer.emplace_back(this, cmd.data);
|
const auto fname =
|
||||||
if (cmd.type == QueueType::dcb && cmd.submit_num == selected_submit_num &&
|
fmt::format("{}_{}_{:02}_{:02}", id, magic_enum::enum_name(selected_queue_type),
|
||||||
cmd.num2 == selected_queue_num2) {
|
selected_submit_num, selected_queue_num2);
|
||||||
selected_cmd = cmd_list_viewer.size() - 1;
|
cmd_list_viewer.emplace_back(frame_dump.get(), cmd.data, cmd.base_addr, fname);
|
||||||
|
if (cmd.type == QueueType::dcb && cmd.submit_num == 0 && cmd.num2 == 0) {
|
||||||
|
selected_cmd = static_cast<s32>(cmd_list_viewer.size() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdb_view.Open = false;
|
FrameDumpViewer::~FrameDumpViewer() = default;
|
||||||
cmdb_view.ReadOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameDumpViewer::~FrameDumpViewer() {}
|
|
||||||
|
|
||||||
void FrameDumpViewer::Draw() {
|
void FrameDumpViewer::Draw() {
|
||||||
if (!is_open) {
|
if (!is_open) {
|
||||||
@ -66,11 +66,11 @@ void FrameDumpViewer::Draw() {
|
|||||||
|
|
||||||
char name[32];
|
char name[32];
|
||||||
snprintf(name, sizeof(name), "Frame #%d dump", id);
|
snprintf(name, sizeof(name), "Frame #%d dump", id);
|
||||||
static ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
|
||||||
SetNextWindowDockID(dock_id, ImGuiCond_Appearing);
|
|
||||||
if (Begin(name, &is_open, ImGuiWindowFlags_NoSavedSettings)) {
|
if (Begin(name, &is_open, ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
if (IsWindowAppearing()) {
|
if (IsWindowAppearing()) {
|
||||||
auto window = GetCurrentWindow();
|
auto window = GetCurrentWindow();
|
||||||
|
static ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
||||||
|
SetWindowDock(window, dock_id, ImGuiCond_Once | ImGuiCond_FirstUseEver);
|
||||||
SetWindowSize(window, ImVec2{470.0f, 600.0f});
|
SetWindowSize(window, ImVec2{470.0f, 600.0f});
|
||||||
}
|
}
|
||||||
BeginGroup();
|
BeginGroup();
|
||||||
@ -89,12 +89,30 @@ void FrameDumpViewer::Draw() {
|
|||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
SameLine();
|
SameLine();
|
||||||
|
BeginDisabled(selected_cmd == -1);
|
||||||
|
if (SmallButton("Dump cmd")) {
|
||||||
|
auto now_time = fmt::localtime(std::time(nullptr));
|
||||||
|
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
|
||||||
|
magic_enum::enum_name(selected_queue_type),
|
||||||
|
selected_submit_num, selected_queue_num2);
|
||||||
|
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
|
||||||
|
const auto& data = frame_dump->queues[selected_cmd].data;
|
||||||
|
if (file.IsOpen()) {
|
||||||
|
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
|
||||||
|
file.Write(data);
|
||||||
|
} else {
|
||||||
|
DebugState.ShowDebugMessage(fmt::format("Failed to save {}", fname));
|
||||||
|
LOG_ERROR(Core, "Failed to open file {}", fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndDisabled();
|
||||||
|
|
||||||
TextEx("Submit num");
|
TextEx("Submit num");
|
||||||
SameLine();
|
SameLine();
|
||||||
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
||||||
ImGuiComboFlags_WidthFitPreview)) {
|
ImGuiComboFlags_WidthFitPreview)) {
|
||||||
std::array<bool, 32> available_submits{};
|
std::array<bool, 32> available_submits{};
|
||||||
for (const auto& cmd : frame_dump.queues) {
|
for (const auto& cmd : frame_dump->queues) {
|
||||||
if (cmd.type == selected_queue_type) {
|
if (cmd.type == selected_queue_type) {
|
||||||
available_submits[cmd.submit_num] = true;
|
available_submits[cmd.submit_num] = true;
|
||||||
}
|
}
|
||||||
@ -119,7 +137,7 @@ void FrameDumpViewer::Draw() {
|
|||||||
if (BeginCombo("##select_queue_num2", small_int_to_str(selected_queue_num2).data(),
|
if (BeginCombo("##select_queue_num2", small_int_to_str(selected_queue_num2).data(),
|
||||||
ImGuiComboFlags_WidthFitPreview)) {
|
ImGuiComboFlags_WidthFitPreview)) {
|
||||||
std::array<bool, 32> available_queues{};
|
std::array<bool, 32> available_queues{};
|
||||||
for (const auto& cmd : frame_dump.queues) {
|
for (const auto& cmd : frame_dump->queues) {
|
||||||
if (cmd.type == selected_queue_type && cmd.submit_num == selected_submit_num) {
|
if (cmd.type == selected_queue_type && cmd.submit_num == selected_submit_num) {
|
||||||
available_queues[cmd.num2] = true;
|
available_queues[cmd.num2] = true;
|
||||||
}
|
}
|
||||||
@ -134,34 +152,16 @@ void FrameDumpViewer::Draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selected) {
|
if (selected) {
|
||||||
const auto it = std::ranges::find_if(frame_dump.queues, [&](const auto& cmd) {
|
const auto it = std::ranges::find_if(frame_dump->queues, [&](const auto& cmd) {
|
||||||
return cmd.type == selected_queue_type &&
|
return cmd.type == selected_queue_type &&
|
||||||
cmd.submit_num == selected_submit_num && cmd.num2 == selected_queue_num2;
|
cmd.submit_num == selected_submit_num && cmd.num2 == selected_queue_num2;
|
||||||
});
|
});
|
||||||
if (it != frame_dump.queues.end()) {
|
if (it != frame_dump->queues.end()) {
|
||||||
selected_cmd = std::distance(frame_dump.queues.begin(), it);
|
selected_cmd = static_cast<s32>(std::distance(frame_dump->queues.begin(), it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
SameLine();
|
|
||||||
BeginDisabled(selected_cmd == -1);
|
|
||||||
if (SmallButton("Dump cmd")) {
|
|
||||||
auto now_time = fmt::localtime(std::time(nullptr));
|
|
||||||
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
|
|
||||||
magic_enum::enum_name(selected_queue_type),
|
|
||||||
selected_submit_num, selected_queue_num2);
|
|
||||||
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
|
|
||||||
auto& data = frame_dump.queues[selected_cmd].data;
|
|
||||||
if (file.IsOpen()) {
|
|
||||||
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
|
|
||||||
file.Write(data);
|
|
||||||
} else {
|
|
||||||
DebugState.ShowDebugMessage(fmt::format("Failed to save {}", fname));
|
|
||||||
LOG_ERROR(Core, "Failed to open file {}", fname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EndDisabled();
|
|
||||||
EndGroup();
|
EndGroup();
|
||||||
|
|
||||||
if (selected_cmd != -1) {
|
if (selected_cmd != -1) {
|
||||||
@ -169,21 +169,6 @@ void FrameDumpViewer::Draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
|
|
||||||
if (cmdb_view.Open && selected_cmd != -1) {
|
|
||||||
auto& cmd = frame_dump.queues[selected_cmd].data;
|
|
||||||
auto cmd_size = cmd.size() * sizeof(u32);
|
|
||||||
MemoryEditor::Sizes s;
|
|
||||||
cmdb_view.CalcSizes(s, cmd_size, (size_t)cmd.data());
|
|
||||||
SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(s.WindowWidth, FLT_MAX));
|
|
||||||
|
|
||||||
char name[64];
|
|
||||||
snprintf(name, sizeof(name), "[GFX] Command buffer %d###cmdbuf_hex_%d", id, id);
|
|
||||||
if (Begin(name, &cmdb_view.Open, ImGuiWindowFlags_NoScrollbar)) {
|
|
||||||
cmdb_view.DrawContents(cmd.data(), cmd_size, (size_t)cmd.data());
|
|
||||||
}
|
|
||||||
End();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "cmd_list.h"
|
#include "cmd_list.h"
|
||||||
#include "core/debug_state.h"
|
#include "core/debug_state.h"
|
||||||
#include "imgui_memory_editor.h"
|
|
||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
@ -17,11 +16,10 @@ class CmdListViewer;
|
|||||||
class FrameDumpViewer {
|
class FrameDumpViewer {
|
||||||
friend class CmdListViewer;
|
friend class CmdListViewer;
|
||||||
|
|
||||||
DebugStateType::FrameDump frame_dump;
|
std::shared_ptr<DebugStateType::FrameDump> frame_dump;
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
std::vector<CmdListViewer> cmd_list_viewer;
|
std::vector<CmdListViewer> cmd_list_viewer;
|
||||||
MemoryEditor cmdb_view;
|
|
||||||
|
|
||||||
DebugStateType::QueueType selected_queue_type;
|
DebugStateType::QueueType selected_queue_type;
|
||||||
s32 selected_submit_num;
|
s32 selected_submit_num;
|
||||||
@ -31,7 +29,7 @@ class FrameDumpViewer {
|
|||||||
public:
|
public:
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
|
|
||||||
explicit FrameDumpViewer(DebugStateType::FrameDump frame_dump);
|
explicit FrameDumpViewer(const DebugStateType::FrameDump& frame_dump);
|
||||||
|
|
||||||
~FrameDumpViewer();
|
~FrameDumpViewer();
|
||||||
|
|
||||||
|
182
src/core/devtools/widget/reg_popup.cpp
Normal file
182
src/core/devtools/widget/reg_popup.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "reg_popup.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "cmd_list.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
using magic_enum::enum_name;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||||
|
if (BeginTable("COLOR_BUFFER", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
DrawMultipleRow(
|
||||||
|
"BASE_ADDR", "%X", buffer.base_address,
|
||||||
|
"PITCH.TILE_MAX", "%X", buffer.pitch.tile_max,
|
||||||
|
"PITCH.FMASK_TILE_MAX", "%X", buffer.pitch.fmask_tile_max,
|
||||||
|
"SLICE.TILE_MAX", "%X", buffer.slice.tile_max,
|
||||||
|
"VIEW.SLICE_START", "%X", buffer.view.slice_start,
|
||||||
|
"VIEW.SLICE_MAX", "%X", buffer.view.slice_max
|
||||||
|
);
|
||||||
|
|
||||||
|
TableNextRow();
|
||||||
|
TableNextColumn();
|
||||||
|
if (TreeNode("Color0Info")) {
|
||||||
|
TableNextRow();
|
||||||
|
TableNextColumn();
|
||||||
|
ParseColor0Info(buffer.info.u32all, false);
|
||||||
|
TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
TableNextRow();
|
||||||
|
TableNextColumn();
|
||||||
|
if (TreeNode("Color0Attrib")) {
|
||||||
|
TableNextRow();
|
||||||
|
TableNextColumn();
|
||||||
|
ParseColor0Attrib(buffer.attrib.u32all, false);
|
||||||
|
TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
TableNextRow();
|
||||||
|
DrawMultipleRow(
|
||||||
|
"CMASK_BASE_EXT", "%X", buffer.cmask_base_address,
|
||||||
|
"FMASK_BASE_EXT", "%X", buffer.fmask_base_address,
|
||||||
|
"FMASK_SLICE.TILE_MAX", "%X", buffer.fmask_slice.tile_max,
|
||||||
|
"CLEAR_WORD0", "%X", buffer.clear_word0,
|
||||||
|
"CLEAR_WORD1", "%X", buffer.clear_word1
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawMultipleRow(
|
||||||
|
"Pitch()", "%X", buffer.Pitch(),
|
||||||
|
"Height()", "%X", buffer.Height(),
|
||||||
|
"Address()", "%X", buffer.Address(),
|
||||||
|
"CmaskAddress", "%X", buffer.CmaskAddress(),
|
||||||
|
"FmaskAddress", "%X", buffer.FmaskAddress(),
|
||||||
|
"NumSamples()", "%X", buffer.NumSamples(),
|
||||||
|
"NumSlices()", "%X", buffer.NumSlices(),
|
||||||
|
"GetColorSliceSize()", "%X", buffer.GetColorSliceSize()
|
||||||
|
);
|
||||||
|
|
||||||
|
auto tiling_mode = buffer.GetTilingMode();
|
||||||
|
auto num_format = buffer.NumFormat();
|
||||||
|
DrawEnumRow("GetTilingMode()", tiling_mode);
|
||||||
|
DrawRow("IsTiled()", "%X", buffer.IsTiled());
|
||||||
|
DrawEnumRow("NumFormat()", num_format);
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
|
||||||
|
const auto& [depth_buffer, depth_control] = depth_data;
|
||||||
|
|
||||||
|
SeparatorText("Depth buffer");
|
||||||
|
|
||||||
|
if (BeginTable("DEPTH_BUFFER", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
DrawEnumRow("Z_INFO.FORMAT", depth_buffer.z_info.format.Value());
|
||||||
|
DrawMultipleRow(
|
||||||
|
"Z_INFO.NUM_SAMPLES", "%X", depth_buffer.z_info.num_samples,
|
||||||
|
"Z_INFO.TILE_SPLIT", "%X", depth_buffer.z_info.tile_split,
|
||||||
|
"Z_INFO.TILE_MODE_INDEX", "%X", depth_buffer.z_info.tile_mode_index,
|
||||||
|
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", "%X", depth_buffer.z_info.decompress_on_n_zplanes,
|
||||||
|
"Z_INFO.ALLOW_EXPCLEAR", "%X", depth_buffer.z_info.allow_expclear,
|
||||||
|
"Z_INFO.READ_SIZE", "%X", depth_buffer.z_info.read_size,
|
||||||
|
"Z_INFO.TILE_SURFACE_EN", "%X", depth_buffer.z_info.tile_surface_en,
|
||||||
|
"Z_INFO.CLEAR_DISALLOWED", "%X", depth_buffer.z_info.clear_disallowed,
|
||||||
|
"Z_INFO.ZRANGE_PRECISION", "%X", depth_buffer.z_info.zrange_precision
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawEnumRow("STENCIL_INFO.FORMAT", depth_buffer.stencil_info.format.Value());
|
||||||
|
|
||||||
|
DrawMultipleRow(
|
||||||
|
"Z_READ_BASE", "%X", depth_buffer.z_read_base,
|
||||||
|
"STENCIL_READ_BASE", "%X", depth_buffer.stencil_read_base,
|
||||||
|
"Z_WRITE_BASE", "%X", depth_buffer.z_write_base,
|
||||||
|
"STENCIL_WRITE_BASE", "%X", depth_buffer.stencil_write_base,
|
||||||
|
"DEPTH_SIZE.PITCH_TILE_MAX", "%X", depth_buffer.depth_size.pitch_tile_max,
|
||||||
|
"DEPTH_SIZE.HEIGHT_TILE_MAX", "%X", depth_buffer.depth_size.height_tile_max,
|
||||||
|
"DEPTH_SLICE.TILE_MAX", "%X", depth_buffer.depth_slice.tile_max,
|
||||||
|
"Pitch()", "%X", depth_buffer.Pitch(),
|
||||||
|
"Height()", "%X", depth_buffer.Height(),
|
||||||
|
"Address()", "%X", depth_buffer.Address(),
|
||||||
|
"NumSamples()", "%X", depth_buffer.NumSamples(),
|
||||||
|
"NumBits()", "%X", depth_buffer.NumBits(),
|
||||||
|
"GetDepthSliceSize()", "%X", depth_buffer.GetDepthSliceSize()
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
SeparatorText("Depth control");
|
||||||
|
if (BeginTable("DEPTH_CONTROL", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
DrawMultipleRow(
|
||||||
|
"STENCIL_ENABLE", "%X", depth_control.stencil_enable,
|
||||||
|
"DEPTH_ENABLE", "%X", depth_control.depth_enable,
|
||||||
|
"DEPTH_WRITE_ENABLE", "%X", depth_control.depth_write_enable,
|
||||||
|
"DEPTH_BOUNDS_ENABLE", "%X", depth_control.depth_bounds_enable
|
||||||
|
);
|
||||||
|
DrawEnumRow("DEPTH_FUNC", depth_control.depth_func.Value());
|
||||||
|
DrawRow("BACKFACE_ENABLE", "%X", depth_control.backface_enable);
|
||||||
|
DrawEnumRow("STENCIL_FUNC", depth_control.stencil_ref_func.Value());
|
||||||
|
DrawEnumRow("STENCIL_FUNC_BF", depth_control.stencil_bf_func.Value());
|
||||||
|
DrawMultipleRow(
|
||||||
|
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", "%X", depth_control.enable_color_writes_on_depth_fail,
|
||||||
|
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", "%X", depth_control.disable_color_writes_on_depth_pass
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegPopup::RegPopup() {
|
||||||
|
static int unique_id = 0;
|
||||||
|
id = unique_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegPopup::SetData(AmdGpu::Liverpool::ColorBuffer color_buffer, u32 batch_id, u32 cb_id) {
|
||||||
|
this->data = color_buffer;
|
||||||
|
this->title = fmt::format("Batch #{} CB #{}", batch_id, cb_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegPopup::SetData(AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
||||||
|
AmdGpu::Liverpool::DepthControl depth_control, u32 batch_id) {
|
||||||
|
this->data = std::make_tuple(depth_buffer, depth_control);
|
||||||
|
this->title = fmt::format("Batch #{} Depth", batch_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegPopup::Draw() {
|
||||||
|
|
||||||
|
char name[128];
|
||||||
|
snprintf(name, sizeof(name), "%s###reg_popup_%d", title.c_str(), id);
|
||||||
|
|
||||||
|
SetNextWindowSize({250.0f, 300.0f}, ImGuiCond_FirstUseEver);
|
||||||
|
if (Begin(name, &open, ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
if (const auto* buffer = std::get_if<AmdGpu::Liverpool::ColorBuffer>(&data)) {
|
||||||
|
DrawColorBuffer(*buffer);
|
||||||
|
} else if (const auto* depth_data = std::get_if<DepthBuffer>(&data)) {
|
||||||
|
DrawDepthBuffer(*depth_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
38
src/core/devtools/widget/reg_popup.h
Normal file
38
src/core/devtools/widget/reg_popup.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class RegPopup {
|
||||||
|
int id;
|
||||||
|
|
||||||
|
using DepthBuffer = std::tuple<AmdGpu::Liverpool::DepthBuffer, AmdGpu::Liverpool::DepthControl>;
|
||||||
|
|
||||||
|
std::variant<AmdGpu::Liverpool::ColorBuffer, DepthBuffer> data;
|
||||||
|
std::string title{};
|
||||||
|
|
||||||
|
void DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer);
|
||||||
|
|
||||||
|
void DrawDepthBuffer(const DepthBuffer& depth_data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool open = false;
|
||||||
|
|
||||||
|
RegPopup();
|
||||||
|
|
||||||
|
void SetData(AmdGpu::Liverpool::ColorBuffer color_buffer, u32 batch_id, u32 cb_id);
|
||||||
|
|
||||||
|
void SetData(AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
||||||
|
AmdGpu::Liverpool::DepthControl depth_control, u32 batch_id);
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
305
src/core/devtools/widget/reg_view.cpp
Normal file
305
src/core/devtools/widget/reg_view.cpp
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "common/io_file.h"
|
||||||
|
#include "core/devtools/options.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
#include "reg_view.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define popen _popen
|
||||||
|
#define pclose _pclose
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
using magic_enum::enum_name;
|
||||||
|
|
||||||
|
static std::optional<std::string> exec_cli(const char* cli) {
|
||||||
|
std::array<char, 64> buffer{};
|
||||||
|
std::string output;
|
||||||
|
const auto f = popen(cli, "r");
|
||||||
|
if (!f) {
|
||||||
|
pclose(f);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
while (fgets(buffer.data(), buffer.size(), f)) {
|
||||||
|
output += buffer.data();
|
||||||
|
}
|
||||||
|
pclose(f);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
void RegView::ProcessShader(int shader_id) {
|
||||||
|
auto shader = data.stages[shader_id];
|
||||||
|
|
||||||
|
std::string shader_dis;
|
||||||
|
|
||||||
|
if (Options.disassembly_cli.empty()) {
|
||||||
|
shader_dis = "No disassembler set";
|
||||||
|
} else {
|
||||||
|
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
|
||||||
|
|
||||||
|
constexpr std::string_view src_arg = "{src}";
|
||||||
|
std::string cli = Options.disassembly_cli;
|
||||||
|
const auto pos = cli.find(src_arg);
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument");
|
||||||
|
} else {
|
||||||
|
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||||
|
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||||
|
file.Write(shader.code);
|
||||||
|
file.Close();
|
||||||
|
|
||||||
|
auto result = exec_cli(cli.c_str());
|
||||||
|
shader_dis = result.value_or("Could not disassemble shader");
|
||||||
|
if (shader_dis.empty()) {
|
||||||
|
shader_dis = "Disassembly empty or failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::remove(bin_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryEditor hex_view;
|
||||||
|
hex_view.Open = true;
|
||||||
|
hex_view.ReadOnly = true;
|
||||||
|
hex_view.Cols = 16;
|
||||||
|
hex_view.OptShowAscii = false;
|
||||||
|
|
||||||
|
TextEditor dis_view;
|
||||||
|
dis_view.SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
dis_view.SetReadOnly(true);
|
||||||
|
dis_view.SetText(shader_dis);
|
||||||
|
|
||||||
|
ShaderCache cache{
|
||||||
|
.hex_view = hex_view,
|
||||||
|
.dis_view = dis_view,
|
||||||
|
.user_data = shader.user_data.user_data,
|
||||||
|
};
|
||||||
|
shader_decomp.emplace(shader_id, std::move(cache));
|
||||||
|
}
|
||||||
|
void RegView::SelectShader(int id) {
|
||||||
|
selected_shader = id;
|
||||||
|
if (!shader_decomp.contains(id)) {
|
||||||
|
ProcessShader(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::DrawRegs() {
|
||||||
|
const auto& regs = data.regs;
|
||||||
|
|
||||||
|
if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
|
||||||
|
auto& s = regs.screen_scissor;
|
||||||
|
DrawRow("Scissor", "(%d, %d, %d, %d)", s.top_left_x, s.top_left_y, s.bottom_right_x,
|
||||||
|
s.bottom_right_y);
|
||||||
|
|
||||||
|
auto cc_mode = regs.color_control.mode.Value();
|
||||||
|
DrawRow("Color control", "%X (%s)", cc_mode, enum_name(cc_mode).data());
|
||||||
|
|
||||||
|
const auto open_new_popup = [&](int cb, auto... args) {
|
||||||
|
if (GetIO().KeyShift) {
|
||||||
|
auto& pop = extra_reg_popup.emplace_back();
|
||||||
|
pop.SetData(args...);
|
||||||
|
pop.open = true;
|
||||||
|
} else if (last_selected_cb == cb && default_reg_popup.open) {
|
||||||
|
default_reg_popup.open = false;
|
||||||
|
} else {
|
||||||
|
last_selected_cb = cb;
|
||||||
|
default_reg_popup.SetData(args...);
|
||||||
|
if (!default_reg_popup.open) {
|
||||||
|
default_reg_popup.open = true;
|
||||||
|
auto popup_pos =
|
||||||
|
GetCurrentContext()->LastItemData.Rect.Max + ImVec2(5.0f, 0.0f);
|
||||||
|
SetNextWindowPos(popup_pos, ImGuiCond_Always);
|
||||||
|
default_reg_popup.Draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int cb = 0; cb < AmdGpu::Liverpool::NumColorBuffers; ++cb) {
|
||||||
|
PushID(cb);
|
||||||
|
|
||||||
|
TableNextRow();
|
||||||
|
TableNextColumn();
|
||||||
|
|
||||||
|
const auto& buffer = regs.color_buffers[cb];
|
||||||
|
|
||||||
|
Text("Color buffer %d", cb);
|
||||||
|
TableNextColumn();
|
||||||
|
if (!buffer || !regs.color_target_mask.GetMask(cb)) {
|
||||||
|
TextUnformatted("N/A");
|
||||||
|
} else {
|
||||||
|
const char* text = last_selected_cb == cb && default_reg_popup.open ? "x" : "->";
|
||||||
|
if (SmallButton(text)) {
|
||||||
|
open_new_popup(cb, buffer, batch_id, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
TableNextRow();
|
||||||
|
TableNextColumn();
|
||||||
|
TextUnformatted("Depth buffer");
|
||||||
|
TableNextColumn();
|
||||||
|
if (regs.depth_buffer.Address() == 0 || !regs.depth_control.depth_enable) {
|
||||||
|
TextUnformatted("N/A");
|
||||||
|
} else {
|
||||||
|
constexpr auto depth_id = 0xF3;
|
||||||
|
const char* text = last_selected_cb == depth_id && default_reg_popup.open ? "x" : "->";
|
||||||
|
if (SmallButton(text)) {
|
||||||
|
open_new_popup(depth_id, regs.depth_buffer, regs.depth_control, batch_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegView::RegView() {
|
||||||
|
static int unique_id = 0;
|
||||||
|
id = unique_id++;
|
||||||
|
|
||||||
|
char name[128];
|
||||||
|
snprintf(name, sizeof(name), "BatchView###reg_dump_%d", id);
|
||||||
|
SetNextWindowPos({400.0f, 200.0f});
|
||||||
|
SetNextWindowSize({450.0f, 500.0f});
|
||||||
|
ImGuiID root_dock_id;
|
||||||
|
Begin(name);
|
||||||
|
{
|
||||||
|
char dock_name[64];
|
||||||
|
snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id);
|
||||||
|
root_dock_id = ImHashStr(dock_name);
|
||||||
|
DockSpace(root_dock_id);
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
ImGuiID up1, down1;
|
||||||
|
|
||||||
|
DockBuilderRemoveNodeChildNodes(root_dock_id);
|
||||||
|
DockBuilderSplitNode(root_dock_id, ImGuiDir_Up, 0.2f, &up1, &down1);
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
||||||
|
DockBuilderDockWindow(name, up1);
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id);
|
||||||
|
DockBuilderDockWindow(name, down1);
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "Disassembly###reg_dump_%d/disassembly", id);
|
||||||
|
DockBuilderDockWindow(name, down1);
|
||||||
|
|
||||||
|
DockBuilderFinish(root_dock_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::SetData(DebugStateType::RegDump data, u32 batch_id) {
|
||||||
|
this->data = std::move(data);
|
||||||
|
this->batch_id = batch_id;
|
||||||
|
// clear cache
|
||||||
|
selected_shader = -1;
|
||||||
|
shader_decomp.clear();
|
||||||
|
default_reg_popup.open = false;
|
||||||
|
extra_reg_popup.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::Draw() {
|
||||||
|
|
||||||
|
char name[128];
|
||||||
|
snprintf(name, sizeof(name), "BatchView %u###reg_dump_%d", batch_id, id);
|
||||||
|
if (Begin(name, &open, ImGuiWindowFlags_MenuBar)) {
|
||||||
|
const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"};
|
||||||
|
|
||||||
|
if (BeginMenuBar()) {
|
||||||
|
if (BeginMenu("Stage")) {
|
||||||
|
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
||||||
|
if (data.regs.stage_enable.IsStageEnabled(i)) {
|
||||||
|
bool selected = selected_shader == i;
|
||||||
|
if (Selectable(names[i], &selected)) {
|
||||||
|
SelectShader(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
if (BeginMenu("Windows")) {
|
||||||
|
Checkbox("Registers", &show_registers);
|
||||||
|
Checkbox("User data", &show_user_data);
|
||||||
|
Checkbox("Disassembly", &show_disassembly);
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
char dock_name[64];
|
||||||
|
snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id);
|
||||||
|
auto root_dock_id = ImHashStr(dock_name);
|
||||||
|
DockSpace(root_dock_id);
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
auto get_shader = [&]() -> ShaderCache* {
|
||||||
|
auto shader_cache = shader_decomp.find(selected_shader);
|
||||||
|
if (shader_cache == shader_decomp.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &shader_cache->second;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (show_user_data) {
|
||||||
|
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
||||||
|
if (Begin(name, &show_user_data)) {
|
||||||
|
auto shader = get_shader();
|
||||||
|
if (!shader) {
|
||||||
|
Text("Select a stage");
|
||||||
|
} else {
|
||||||
|
shader->hex_view.DrawContents(shader->user_data.data(), shader->user_data.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_disassembly) {
|
||||||
|
snprintf(name, sizeof(name), "Disassembly###reg_dump_%d/disassembly", id);
|
||||||
|
if (Begin(name, &show_disassembly)) {
|
||||||
|
auto shader = get_shader();
|
||||||
|
if (!shader) {
|
||||||
|
Text("Select a stage");
|
||||||
|
} else {
|
||||||
|
shader->dis_view.Render("Disassembly", GetContentRegionAvail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_registers) {
|
||||||
|
snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id);
|
||||||
|
if (Begin(name, &show_registers)) {
|
||||||
|
DrawRegs();
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_reg_popup.open) {
|
||||||
|
default_reg_popup.Draw();
|
||||||
|
}
|
||||||
|
for (auto it = extra_reg_popup.begin(); it != extra_reg_popup.end();) {
|
||||||
|
if (!it->open) {
|
||||||
|
it = extra_reg_popup.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it->Draw();
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
50
src/core/devtools/widget/reg_view.h
Normal file
50
src/core/devtools/widget/reg_view.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "imgui_memory_editor.h"
|
||||||
|
#include "reg_popup.h"
|
||||||
|
#include "text_editor.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
struct ShaderCache {
|
||||||
|
MemoryEditor hex_view;
|
||||||
|
TextEditor dis_view;
|
||||||
|
Vulkan::Liverpool::UserData user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RegView {
|
||||||
|
int id;
|
||||||
|
|
||||||
|
DebugStateType::RegDump data;
|
||||||
|
u32 batch_id{~0u};
|
||||||
|
|
||||||
|
std::unordered_map<int, ShaderCache> shader_decomp;
|
||||||
|
int selected_shader{-1};
|
||||||
|
RegPopup default_reg_popup;
|
||||||
|
int last_selected_cb{-1};
|
||||||
|
std::vector<RegPopup> extra_reg_popup;
|
||||||
|
|
||||||
|
bool show_registers{true};
|
||||||
|
bool show_user_data{true};
|
||||||
|
bool show_disassembly{true};
|
||||||
|
|
||||||
|
void ProcessShader(int shader_id);
|
||||||
|
|
||||||
|
void SelectShader(int shader_id);
|
||||||
|
|
||||||
|
void DrawRegs();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool open = false;
|
||||||
|
|
||||||
|
RegView();
|
||||||
|
|
||||||
|
void SetData(DebugStateType::RegDump data, u32 batch_id);
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
2334
src/core/devtools/widget/text_editor.cpp
Normal file
2334
src/core/devtools/widget/text_editor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
408
src/core/devtools/widget/text_editor.h
Normal file
408
src/core/devtools/widget/text_editor.h
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2017 BalazsJako
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
// source: https://github.com/BalazsJako/ImGuiColorTextEdit
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class TextEditor {
|
||||||
|
public:
|
||||||
|
enum class PaletteIndex {
|
||||||
|
Default,
|
||||||
|
Keyword,
|
||||||
|
Number,
|
||||||
|
String,
|
||||||
|
CharLiteral,
|
||||||
|
Punctuation,
|
||||||
|
Preprocessor,
|
||||||
|
Identifier,
|
||||||
|
KnownIdentifier,
|
||||||
|
PreprocIdentifier,
|
||||||
|
Comment,
|
||||||
|
MultiLineComment,
|
||||||
|
Background,
|
||||||
|
Cursor,
|
||||||
|
Selection,
|
||||||
|
ErrorMarker,
|
||||||
|
Breakpoint,
|
||||||
|
LineNumber,
|
||||||
|
CurrentLineFill,
|
||||||
|
CurrentLineFillInactive,
|
||||||
|
CurrentLineEdge,
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SelectionMode { Normal, Word, Line };
|
||||||
|
|
||||||
|
struct Breakpoint {
|
||||||
|
int mLine;
|
||||||
|
bool mEnabled;
|
||||||
|
std::string mCondition;
|
||||||
|
|
||||||
|
Breakpoint() : mLine(-1), mEnabled(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents a character coordinate from the user's point of view,
|
||||||
|
// i. e. consider an uniform grid (assuming fixed-width font) on the
|
||||||
|
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
|
||||||
|
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
|
||||||
|
// how many space is necessary to reach the next tab stop.
|
||||||
|
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize
|
||||||
|
// = 4, because it is rendered as " ABC" on the screen.
|
||||||
|
struct Coordinates {
|
||||||
|
int mLine, mColumn;
|
||||||
|
Coordinates() : mLine(0), mColumn(0) {}
|
||||||
|
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn) {
|
||||||
|
ASSERT(aLine >= 0);
|
||||||
|
ASSERT(aColumn >= 0);
|
||||||
|
}
|
||||||
|
static Coordinates Invalid() {
|
||||||
|
static Coordinates invalid(-1, -1);
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Coordinates& o) const {
|
||||||
|
return mLine == o.mLine && mColumn == o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Coordinates& o) const {
|
||||||
|
return mLine != o.mLine || mColumn != o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine < o.mLine;
|
||||||
|
return mColumn < o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine > o.mLine;
|
||||||
|
return mColumn > o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine < o.mLine;
|
||||||
|
return mColumn <= o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine > o.mLine;
|
||||||
|
return mColumn >= o.mColumn;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Identifier {
|
||||||
|
Coordinates mLocation;
|
||||||
|
std::string mDeclaration;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::string String;
|
||||||
|
typedef std::unordered_map<std::string, Identifier> Identifiers;
|
||||||
|
typedef std::unordered_set<std::string> Keywords;
|
||||||
|
typedef std::map<int, std::string> ErrorMarkers;
|
||||||
|
typedef std::unordered_set<int> Breakpoints;
|
||||||
|
typedef std::array<ImU32, (unsigned)PaletteIndex::Max> Palette;
|
||||||
|
typedef uint8_t Char;
|
||||||
|
|
||||||
|
struct Glyph {
|
||||||
|
Char mChar;
|
||||||
|
PaletteIndex mColorIndex = PaletteIndex::Default;
|
||||||
|
bool mComment : 1;
|
||||||
|
bool mMultiLineComment : 1;
|
||||||
|
bool mPreprocessor : 1;
|
||||||
|
|
||||||
|
Glyph(Char aChar, PaletteIndex aColorIndex)
|
||||||
|
: mChar(aChar), mColorIndex(aColorIndex), mComment(false), mMultiLineComment(false),
|
||||||
|
mPreprocessor(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Glyph> Line;
|
||||||
|
typedef std::vector<Line> Lines;
|
||||||
|
|
||||||
|
struct LanguageDefinition {
|
||||||
|
typedef std::pair<std::string, PaletteIndex> TokenRegexString;
|
||||||
|
typedef std::vector<TokenRegexString> TokenRegexStrings;
|
||||||
|
typedef bool (*TokenizeCallback)(const char* in_begin, const char* in_end,
|
||||||
|
const char*& out_begin, const char*& out_end,
|
||||||
|
PaletteIndex& paletteIndex);
|
||||||
|
|
||||||
|
std::string mName;
|
||||||
|
Keywords mKeywords;
|
||||||
|
Identifiers mIdentifiers;
|
||||||
|
Identifiers mPreprocIdentifiers;
|
||||||
|
std::string mCommentStart, mCommentEnd, mSingleLineComment;
|
||||||
|
char mPreprocChar;
|
||||||
|
bool mAutoIndentation;
|
||||||
|
|
||||||
|
TokenizeCallback mTokenize;
|
||||||
|
|
||||||
|
TokenRegexStrings mTokenRegexStrings;
|
||||||
|
|
||||||
|
bool mCaseSensitive;
|
||||||
|
|
||||||
|
LanguageDefinition()
|
||||||
|
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true) {}
|
||||||
|
|
||||||
|
static const LanguageDefinition& GLSL();
|
||||||
|
};
|
||||||
|
|
||||||
|
TextEditor();
|
||||||
|
~TextEditor();
|
||||||
|
|
||||||
|
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
|
||||||
|
const LanguageDefinition& GetLanguageDefinition() const {
|
||||||
|
return mLanguageDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Palette& GetPalette() const {
|
||||||
|
return mPaletteBase;
|
||||||
|
}
|
||||||
|
void SetPalette(const Palette& aValue);
|
||||||
|
|
||||||
|
void SetErrorMarkers(const ErrorMarkers& aMarkers) {
|
||||||
|
mErrorMarkers = aMarkers;
|
||||||
|
}
|
||||||
|
void SetBreakpoints(const Breakpoints& aMarkers) {
|
||||||
|
mBreakpoints = aMarkers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
|
||||||
|
void SetText(const std::string& aText);
|
||||||
|
std::string GetText() const;
|
||||||
|
|
||||||
|
void SetTextLines(const std::vector<std::string>& aLines);
|
||||||
|
std::vector<std::string> GetTextLines() const;
|
||||||
|
|
||||||
|
std::string GetSelectedText() const;
|
||||||
|
std::string GetCurrentLineText() const;
|
||||||
|
|
||||||
|
int GetTotalLines() const {
|
||||||
|
return (int)mLines.size();
|
||||||
|
}
|
||||||
|
bool IsOverwrite() const {
|
||||||
|
return mOverwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetReadOnly(bool aValue);
|
||||||
|
bool IsReadOnly() const {
|
||||||
|
return mReadOnly;
|
||||||
|
}
|
||||||
|
bool IsTextChanged() const {
|
||||||
|
return mTextChanged;
|
||||||
|
}
|
||||||
|
bool IsCursorPositionChanged() const {
|
||||||
|
return mCursorPositionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsColorizerEnabled() const {
|
||||||
|
return mColorizerEnabled;
|
||||||
|
}
|
||||||
|
void SetColorizerEnable(bool aValue);
|
||||||
|
|
||||||
|
Coordinates GetCursorPosition() const {
|
||||||
|
return GetActualCursorCoordinates();
|
||||||
|
}
|
||||||
|
void SetCursorPosition(const Coordinates& aPosition);
|
||||||
|
|
||||||
|
inline void SetHandleMouseInputs(bool aValue) {
|
||||||
|
mHandleMouseInputs = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsHandleMouseInputsEnabled() const {
|
||||||
|
return mHandleKeyboardInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetHandleKeyboardInputs(bool aValue) {
|
||||||
|
mHandleKeyboardInputs = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsHandleKeyboardInputsEnabled() const {
|
||||||
|
return mHandleKeyboardInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetImGuiChildIgnored(bool aValue) {
|
||||||
|
mIgnoreImGuiChild = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsImGuiChildIgnored() const {
|
||||||
|
return mIgnoreImGuiChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetShowWhitespaces(bool aValue) {
|
||||||
|
mShowWhitespaces = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsShowingWhitespaces() const {
|
||||||
|
return mShowWhitespaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTabSize(int aValue);
|
||||||
|
inline int GetTabSize() const {
|
||||||
|
return mTabSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertText(const std::string& aValue);
|
||||||
|
void InsertText(const char* aValue);
|
||||||
|
|
||||||
|
void MoveUp(int aAmount = 1, bool aSelect = false);
|
||||||
|
void MoveDown(int aAmount = 1, bool aSelect = false);
|
||||||
|
void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
|
||||||
|
void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
|
||||||
|
void MoveTop(bool aSelect = false);
|
||||||
|
void MoveBottom(bool aSelect = false);
|
||||||
|
void MoveHome(bool aSelect = false);
|
||||||
|
void MoveEnd(bool aSelect = false);
|
||||||
|
|
||||||
|
void SetSelectionStart(const Coordinates& aPosition);
|
||||||
|
void SetSelectionEnd(const Coordinates& aPosition);
|
||||||
|
void SetSelection(const Coordinates& aStart, const Coordinates& aEnd,
|
||||||
|
SelectionMode aMode = SelectionMode::Normal);
|
||||||
|
void SelectWordUnderCursor();
|
||||||
|
void SelectAll();
|
||||||
|
bool HasSelection() const;
|
||||||
|
|
||||||
|
void Copy();
|
||||||
|
void Cut();
|
||||||
|
void Paste();
|
||||||
|
void Delete();
|
||||||
|
|
||||||
|
bool CanUndo() const;
|
||||||
|
bool CanRedo() const;
|
||||||
|
void Undo(int aSteps = 1);
|
||||||
|
void Redo(int aSteps = 1);
|
||||||
|
|
||||||
|
static const Palette& GetDarkPalette();
|
||||||
|
static const Palette& GetLightPalette();
|
||||||
|
static const Palette& GetRetroBluePalette();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList;
|
||||||
|
|
||||||
|
struct EditorState {
|
||||||
|
Coordinates mSelectionStart;
|
||||||
|
Coordinates mSelectionEnd;
|
||||||
|
Coordinates mCursorPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UndoRecord {
|
||||||
|
public:
|
||||||
|
UndoRecord() {}
|
||||||
|
~UndoRecord() {}
|
||||||
|
|
||||||
|
UndoRecord(const std::string& aAdded, const TextEditor::Coordinates aAddedStart,
|
||||||
|
const TextEditor::Coordinates aAddedEnd,
|
||||||
|
|
||||||
|
const std::string& aRemoved, const TextEditor::Coordinates aRemovedStart,
|
||||||
|
const TextEditor::Coordinates aRemovedEnd,
|
||||||
|
|
||||||
|
TextEditor::EditorState& aBefore, TextEditor::EditorState& aAfter);
|
||||||
|
|
||||||
|
void Undo(TextEditor* aEditor);
|
||||||
|
void Redo(TextEditor* aEditor);
|
||||||
|
|
||||||
|
std::string mAdded;
|
||||||
|
Coordinates mAddedStart;
|
||||||
|
Coordinates mAddedEnd;
|
||||||
|
|
||||||
|
std::string mRemoved;
|
||||||
|
Coordinates mRemovedStart;
|
||||||
|
Coordinates mRemovedEnd;
|
||||||
|
|
||||||
|
EditorState mBefore;
|
||||||
|
EditorState mAfter;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<UndoRecord> UndoBuffer;
|
||||||
|
|
||||||
|
void ProcessInputs();
|
||||||
|
void Colorize(int aFromLine = 0, int aCount = -1);
|
||||||
|
void ColorizeRange(int aFromLine = 0, int aToLine = 0);
|
||||||
|
void ColorizeInternal();
|
||||||
|
float TextDistanceToLineStart(const Coordinates& aFrom) const;
|
||||||
|
void EnsureCursorVisible();
|
||||||
|
int GetPageSize() const;
|
||||||
|
std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
|
||||||
|
Coordinates GetActualCursorCoordinates() const;
|
||||||
|
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
|
||||||
|
void Advance(Coordinates& aCoordinates) const;
|
||||||
|
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
|
||||||
|
int InsertTextAt(Coordinates& aWhere, const char* aValue);
|
||||||
|
void AddUndo(UndoRecord& aValue);
|
||||||
|
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
|
||||||
|
Coordinates FindWordStart(const Coordinates& aFrom) const;
|
||||||
|
Coordinates FindWordEnd(const Coordinates& aFrom) const;
|
||||||
|
Coordinates FindNextWord(const Coordinates& aFrom) const;
|
||||||
|
int GetCharacterIndex(const Coordinates& aCoordinates) const;
|
||||||
|
int GetCharacterColumn(int aLine, int aIndex) const;
|
||||||
|
int GetLineCharacterCount(int aLine) const;
|
||||||
|
int GetLineMaxColumn(int aLine) const;
|
||||||
|
bool IsOnWordBoundary(const Coordinates& aAt) const;
|
||||||
|
void RemoveLine(int aStart, int aEnd);
|
||||||
|
void RemoveLine(int aIndex);
|
||||||
|
Line& InsertLine(int aIndex);
|
||||||
|
void EnterCharacter(ImWchar aChar, bool aShift);
|
||||||
|
void Backspace();
|
||||||
|
void DeleteSelection();
|
||||||
|
std::string GetWordUnderCursor() const;
|
||||||
|
std::string GetWordAt(const Coordinates& aCoords) const;
|
||||||
|
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
|
||||||
|
|
||||||
|
void HandleKeyboardInputs();
|
||||||
|
void HandleMouseInputs();
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
float mLineSpacing;
|
||||||
|
Lines mLines;
|
||||||
|
EditorState mState;
|
||||||
|
UndoBuffer mUndoBuffer;
|
||||||
|
int mUndoIndex;
|
||||||
|
|
||||||
|
int mTabSize;
|
||||||
|
bool mOverwrite;
|
||||||
|
bool mReadOnly;
|
||||||
|
bool mWithinRender;
|
||||||
|
bool mScrollToCursor;
|
||||||
|
bool mScrollToTop;
|
||||||
|
bool mTextChanged;
|
||||||
|
bool mColorizerEnabled;
|
||||||
|
float mTextStart; // position (in pixels) where a code line starts relative to the left of the
|
||||||
|
// TextEditor.
|
||||||
|
int mLeftMargin;
|
||||||
|
bool mCursorPositionChanged;
|
||||||
|
int mColorRangeMin, mColorRangeMax;
|
||||||
|
SelectionMode mSelectionMode;
|
||||||
|
bool mHandleKeyboardInputs;
|
||||||
|
bool mHandleMouseInputs;
|
||||||
|
bool mIgnoreImGuiChild;
|
||||||
|
bool mShowWhitespaces;
|
||||||
|
|
||||||
|
Palette mPaletteBase;
|
||||||
|
Palette mPalette;
|
||||||
|
LanguageDefinition mLanguageDefinition;
|
||||||
|
RegexList mRegexList;
|
||||||
|
|
||||||
|
bool mCheckComments;
|
||||||
|
Breakpoints mBreakpoints;
|
||||||
|
ErrorMarkers mErrorMarkers;
|
||||||
|
ImVec2 mCharAdvance;
|
||||||
|
Coordinates mInteractiveStart, mInteractiveEnd;
|
||||||
|
std::string mLineBuffer;
|
||||||
|
uint64_t mStartTime;
|
||||||
|
|
||||||
|
float mLastClick;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
@ -227,6 +227,12 @@ void PSF::AddBinary(std::string key, std::vector<u8> value, bool update) {
|
|||||||
map_binaries.emplace(entry_list.size() - 1, std::move(value));
|
map_binaries.emplace(entry_list.size() - 1, std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSF::AddBinary(std::string key, uint64_t value, bool update) {
|
||||||
|
std::vector<u8> data(8);
|
||||||
|
std::memcpy(data.data(), &value, 8);
|
||||||
|
return AddBinary(std::move(key), std::move(data), update);
|
||||||
|
}
|
||||||
|
|
||||||
void PSF::AddString(std::string key, std::string value, bool update) {
|
void PSF::AddString(std::string key, std::string value, bool update) {
|
||||||
auto [it, index] = FindEntry(key);
|
auto [it, index] = FindEntry(key);
|
||||||
bool exist = it != entry_list.end();
|
bool exist = it != entry_list.end();
|
||||||
|
@ -67,6 +67,7 @@ public:
|
|||||||
std::optional<s32> GetInteger(std::string_view key) const;
|
std::optional<s32> GetInteger(std::string_view key) const;
|
||||||
|
|
||||||
void AddBinary(std::string key, std::vector<u8> value, bool update = false);
|
void AddBinary(std::string key, std::vector<u8> value, bool update = false);
|
||||||
|
void AddBinary(std::string key, uint64_t value, bool update = false); // rsv4 format
|
||||||
void AddString(std::string key, std::string value, bool update = false);
|
void AddString(std::string key, std::string value, bool update = false);
|
||||||
void AddInteger(std::string key, s32 value, bool update = false);
|
void AddInteger(std::string key, s32 value, bool update = false);
|
||||||
|
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
#include "avplayer_impl.h"
|
#include "avplayer_impl.h"
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/libkernel.h"
|
||||||
|
#include "core/linker.h"
|
||||||
|
|
||||||
using namespace Libraries::Kernel;
|
using namespace Libraries::Kernel;
|
||||||
|
|
||||||
@ -17,28 +19,32 @@ void* PS4_SYSV_ABI AvPlayer::Allocate(void* handle, u32 alignment, u32 size) {
|
|||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto allocate = self->m_init_data_original.memory_replacement.allocate;
|
const auto allocate = self->m_init_data_original.memory_replacement.allocate;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return allocate(ptr, alignment, size);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(allocate, ptr, alignment, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI AvPlayer::Deallocate(void* handle, void* memory) {
|
void PS4_SYSV_ABI AvPlayer::Deallocate(void* handle, void* memory) {
|
||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate;
|
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return deallocate(ptr, memory);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(deallocate, ptr, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* PS4_SYSV_ABI AvPlayer::AllocateTexture(void* handle, u32 alignment, u32 size) {
|
void* PS4_SYSV_ABI AvPlayer::AllocateTexture(void* handle, u32 alignment, u32 size) {
|
||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto allocate = self->m_init_data_original.memory_replacement.allocate_texture;
|
const auto allocate = self->m_init_data_original.memory_replacement.allocate_texture;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return allocate(ptr, alignment, size);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(allocate, ptr, alignment, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI AvPlayer::DeallocateTexture(void* handle, void* memory) {
|
void PS4_SYSV_ABI AvPlayer::DeallocateTexture(void* handle, void* memory) {
|
||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate_texture;
|
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate_texture;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return deallocate(ptr, memory);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(deallocate, ptr, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
|
int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
|
||||||
@ -47,7 +53,8 @@ int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
|
|||||||
|
|
||||||
const auto open = self->m_init_data_original.file_replacement.open;
|
const auto open = self->m_init_data_original.file_replacement.open;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return open(ptr, filename);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(open, ptr, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
|
int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
|
||||||
@ -56,7 +63,8 @@ int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
|
|||||||
|
|
||||||
const auto close = self->m_init_data_original.file_replacement.close;
|
const auto close = self->m_init_data_original.file_replacement.close;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return close(ptr);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(close, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length) {
|
int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length) {
|
||||||
@ -65,7 +73,8 @@ int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position
|
|||||||
|
|
||||||
const auto read_offset = self->m_init_data_original.file_replacement.readOffset;
|
const auto read_offset = self->m_init_data_original.file_replacement.readOffset;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return read_offset(ptr, buffer, position, length);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(read_offset, ptr, buffer, position, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
|
u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
|
||||||
@ -74,7 +83,8 @@ u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
|
|||||||
|
|
||||||
const auto size = self->m_init_data_original.file_replacement.size;
|
const auto size = self->m_init_data_original.file_replacement.size;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return size(ptr);
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
return linker->ExecuteGuest(size, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
SceAvPlayerInitData AvPlayer::StubInitData(const SceAvPlayerInitData& data) {
|
SceAvPlayerInitData AvPlayer::StubInitData(const SceAvPlayerInitData& data) {
|
||||||
|
@ -87,7 +87,12 @@ void PS4_SYSV_ABI AvPlayerState::AutoPlayEventCallback(void* opaque, SceAvPlayer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass other events to the game
|
DefaultEventCallback(opaque, event_id, 0, event_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvPlayerState::DefaultEventCallback(void* opaque, SceAvPlayerEvents event_id, s32 source_id,
|
||||||
|
void* event_data) {
|
||||||
|
auto const self = reinterpret_cast<AvPlayerState*>(opaque);
|
||||||
const auto callback = self->m_event_replacement.event_callback;
|
const auto callback = self->m_event_replacement.event_callback;
|
||||||
const auto ptr = self->m_event_replacement.object_ptr;
|
const auto ptr = self->m_event_replacement.object_ptr;
|
||||||
if (callback != nullptr) {
|
if (callback != nullptr) {
|
||||||
@ -102,8 +107,10 @@ AvPlayerState::AvPlayerState(const SceAvPlayerInitData& init_data)
|
|||||||
if (m_event_replacement.event_callback == nullptr || init_data.auto_start) {
|
if (m_event_replacement.event_callback == nullptr || init_data.auto_start) {
|
||||||
m_auto_start = true;
|
m_auto_start = true;
|
||||||
m_init_data.event_replacement.event_callback = &AvPlayerState::AutoPlayEventCallback;
|
m_init_data.event_replacement.event_callback = &AvPlayerState::AutoPlayEventCallback;
|
||||||
m_init_data.event_replacement.object_ptr = this;
|
} else {
|
||||||
|
m_init_data.event_replacement.event_callback = &AvPlayerState::DefaultEventCallback;
|
||||||
}
|
}
|
||||||
|
m_init_data.event_replacement.object_ptr = this;
|
||||||
if (init_data.default_language != nullptr) {
|
if (init_data.default_language != nullptr) {
|
||||||
std::memcpy(m_default_language, init_data.default_language, sizeof(m_default_language));
|
std::memcpy(m_default_language, init_data.default_language, sizeof(m_default_language));
|
||||||
}
|
}
|
||||||
@ -367,8 +374,7 @@ void AvPlayerState::EmitEvent(SceAvPlayerEvents event_id, void* event_data) {
|
|||||||
const auto callback = m_init_data.event_replacement.event_callback;
|
const auto callback = m_init_data.event_replacement.event_callback;
|
||||||
if (callback) {
|
if (callback) {
|
||||||
const auto ptr = m_init_data.event_replacement.object_ptr;
|
const auto ptr = m_init_data.event_replacement.object_ptr;
|
||||||
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
callback(ptr, event_id, 0, event_data);
|
||||||
linker->ExecuteGuest(callback, ptr, event_id, 0, event_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,9 @@ private:
|
|||||||
static void PS4_SYSV_ABI AutoPlayEventCallback(void* handle, SceAvPlayerEvents event_id,
|
static void PS4_SYSV_ABI AutoPlayEventCallback(void* handle, SceAvPlayerEvents event_id,
|
||||||
s32 source_id, void* event_data);
|
s32 source_id, void* event_data);
|
||||||
|
|
||||||
|
static void PS4_SYSV_ABI DefaultEventCallback(void* handle, SceAvPlayerEvents event_id,
|
||||||
|
s32 source_id, void* event_data);
|
||||||
|
|
||||||
void OnWarning(u32 id) override;
|
void OnWarning(u32 id) override;
|
||||||
void OnError() override;
|
void OnError() override;
|
||||||
void OnEOF() override;
|
void OnEOF() override;
|
||||||
|
@ -75,7 +75,7 @@ public:
|
|||||||
std::min(io.DisplaySize.y, 300.0f),
|
std::min(io.DisplaySize.y, 300.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
if (first_render || !io.NavActive) {
|
if (first_render || !io.NavActive) {
|
||||||
|
@ -1,28 +1,75 @@
|
|||||||
// 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 <array>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "ime_dialog.h"
|
#include "ime_dialog.h"
|
||||||
|
#include "ime_dialog_ui.h"
|
||||||
|
|
||||||
|
static constexpr std::array<float, 2> MAX_X_POSITIONS = {3840.0f, 1920.0f};
|
||||||
|
static constexpr std::array<float, 2> MAX_Y_POSITIONS = {2160.0f, 1080.0f};
|
||||||
|
|
||||||
namespace Libraries::ImeDialog {
|
namespace Libraries::ImeDialog {
|
||||||
|
|
||||||
static OrbisImeDialogStatus g_ime_dlg_status = OrbisImeDialogStatus::ORBIS_IME_DIALOG_STATUS_NONE;
|
static OrbisImeDialogStatus g_ime_dlg_status = OrbisImeDialogStatus::NONE;
|
||||||
|
static OrbisImeDialogResult g_ime_dlg_result{};
|
||||||
|
static ImeDialogState g_ime_dlg_state{};
|
||||||
|
static ImeDialogUi g_ime_dlg_ui;
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogAbort() {
|
static bool IsValidOption(OrbisImeDialogOption option, OrbisImeType type) {
|
||||||
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
|
if (False(~option &
|
||||||
return ORBIS_OK;
|
(OrbisImeDialogOption::MULTILINE | OrbisImeDialogOption::NO_AUTO_COMPLETION))) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogForceClose() {
|
if (True(option & OrbisImeDialogOption::MULTILINE) && type != OrbisImeType::DEFAULT &&
|
||||||
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
|
type != OrbisImeType::BASIC_LATIN) {
|
||||||
return ORBIS_OK;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogForTestFunction() {
|
if (True(option & OrbisImeDialogOption::NO_AUTO_COMPLETION) && type != OrbisImeType::NUMBER &&
|
||||||
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
|
type != OrbisImeType::BASIC_LATIN) {
|
||||||
return ORBIS_OK;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error PS4_SYSV_ABI sceImeDialogAbort() {
|
||||||
|
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "IME dialog not in use");
|
||||||
|
return Error::DIALOG_NOT_IN_USE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_ime_dlg_status != OrbisImeDialogStatus::RUNNING) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "IME dialog not running");
|
||||||
|
return Error::DIALOG_NOT_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_dlg_status = OrbisImeDialogStatus::FINISHED;
|
||||||
|
g_ime_dlg_result.endstatus = OrbisImeDialogEndStatus::ABORTED;
|
||||||
|
|
||||||
|
return Error::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error PS4_SYSV_ABI sceImeDialogForceClose() {
|
||||||
|
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "IME dialog not in use");
|
||||||
|
return Error::DIALOG_NOT_IN_USE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_dlg_status = OrbisImeDialogStatus::NONE;
|
||||||
|
g_ime_dlg_ui = ImeDialogUi();
|
||||||
|
g_ime_dlg_state = ImeDialogState();
|
||||||
|
|
||||||
|
return Error::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error PS4_SYSV_ABI sceImeDialogForTestFunction() {
|
||||||
|
return Error::INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState() {
|
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState() {
|
||||||
@ -45,26 +92,118 @@ int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result) {
|
Error PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result) {
|
||||||
result->endstatus = OrbisImeDialogEndStatus::ORBIS_IME_DIALOG_END_STATUS_OK;
|
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
|
||||||
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
|
LOG_INFO(Lib_ImeDialog, "IME dialog is not running");
|
||||||
return ORBIS_OK;
|
return Error::DIALOG_NOT_IN_USE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogGetStatus() {
|
if (result == nullptr) {
|
||||||
if (g_ime_dlg_status == OrbisImeDialogStatus::ORBIS_IME_DIALOG_STATUS_RUNNING) {
|
LOG_INFO(Lib_ImeDialog, "called with result (NULL)");
|
||||||
return OrbisImeDialogStatus::ORBIS_IME_DIALOG_STATUS_FINISHED;
|
return Error::INVALID_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result->endstatus = g_ime_dlg_result.endstatus;
|
||||||
|
|
||||||
|
if (g_ime_dlg_status == OrbisImeDialogStatus::RUNNING) {
|
||||||
|
return Error::DIALOG_NOT_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_dlg_state.CopyTextToOrbisBuffer();
|
||||||
|
return Error::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus() {
|
||||||
|
if (g_ime_dlg_status == OrbisImeDialogStatus::RUNNING) {
|
||||||
|
g_ime_dlg_state.CallTextFilter();
|
||||||
|
}
|
||||||
|
|
||||||
return g_ime_dlg_status;
|
return g_ime_dlg_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) {
|
Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) {
|
||||||
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
|
if (g_ime_dlg_status != OrbisImeDialogStatus::NONE) {
|
||||||
const std::wstring_view text = L"shadPS4";
|
LOG_INFO(Lib_ImeDialog, "IME dialog is already running");
|
||||||
param->maxTextLength = text.size();
|
return Error::BUSY;
|
||||||
std::memcpy(param->inputTextBuffer, text.data(), text.size() * sizeof(wchar_t));
|
}
|
||||||
g_ime_dlg_status = OrbisImeDialogStatus::ORBIS_IME_DIALOG_STATUS_RUNNING;
|
|
||||||
return ORBIS_OK;
|
if (param == nullptr) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "called with param (NULL)");
|
||||||
|
return Error::INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!magic_enum::enum_contains(param->type)) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->type");
|
||||||
|
return Error::INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do correct param->option validation
|
||||||
|
// TODO: do correct param->supportedLanguages validation
|
||||||
|
|
||||||
|
if (param->posx < 0.0f ||
|
||||||
|
param->posx >=
|
||||||
|
MAX_X_POSITIONS[False(param->option & OrbisImeDialogOption::LARGE_RESOLUTION)]) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->posx");
|
||||||
|
return Error::INVALID_POSX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->posy < 0.0f ||
|
||||||
|
param->posy >=
|
||||||
|
MAX_Y_POSITIONS[False(param->option & OrbisImeDialogOption::LARGE_RESOLUTION)]) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->posy");
|
||||||
|
return Error::INVALID_POSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!magic_enum::enum_contains(param->horizontalAlignment)) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->horizontalAlignment");
|
||||||
|
return Error::INVALID_HORIZONTALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!magic_enum::enum_contains(param->verticalAlignment)) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->verticalAlignment");
|
||||||
|
return Error::INVALID_VERTICALALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidOption(param->option, param->type)) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->option");
|
||||||
|
return Error::INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->inputTextBuffer == nullptr) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->inputTextBuffer");
|
||||||
|
return Error::INVALID_INPUT_TEXT_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extended) {
|
||||||
|
if (!magic_enum::enum_contains(extended->priority)) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid extended->priority");
|
||||||
|
return Error::INVALID_EXTENDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do correct extended->option validation
|
||||||
|
|
||||||
|
if ((extended->extKeyboardMode & 0xe3fffffc) != 0) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid extended->extKeyboardMode");
|
||||||
|
return Error::INVALID_EXTENDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extended->disableDevice > 7) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid extended->disableDevice");
|
||||||
|
return Error::INVALID_EXTENDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "Invalid param->maxTextLength");
|
||||||
|
return Error::INVALID_MAX_TEXT_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_dlg_result = {};
|
||||||
|
g_ime_dlg_state = ImeDialogState(param, extended);
|
||||||
|
g_ime_dlg_status = OrbisImeDialogStatus::RUNNING;
|
||||||
|
g_ime_dlg_ui = ImeDialogUi(&g_ime_dlg_state, &g_ime_dlg_status, &g_ime_dlg_result);
|
||||||
|
|
||||||
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogInitInternal() {
|
int PS4_SYSV_ABI sceImeDialogInitInternal() {
|
||||||
@ -87,10 +226,22 @@ int PS4_SYSV_ABI sceImeDialogSetPanelPosition() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogTerm() {
|
Error PS4_SYSV_ABI sceImeDialogTerm() {
|
||||||
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
|
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
|
||||||
g_ime_dlg_status = OrbisImeDialogStatus::ORBIS_IME_DIALOG_STATUS_NONE;
|
LOG_INFO(Lib_ImeDialog, "IME dialog not in use");
|
||||||
return ORBIS_OK;
|
return Error::DIALOG_NOT_IN_USE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_ime_dlg_status == OrbisImeDialogStatus::RUNNING) {
|
||||||
|
LOG_INFO(Lib_ImeDialog, "IME dialog is still running");
|
||||||
|
return Error::DIALOG_NOT_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_dlg_status = OrbisImeDialogStatus::NONE;
|
||||||
|
g_ime_dlg_ui = ImeDialogUi();
|
||||||
|
g_ime_dlg_state = ImeDialogState();
|
||||||
|
|
||||||
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterlibSceImeDialog(Core::Loader::SymbolsResolver* sym) {
|
void RegisterlibSceImeDialog(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/enum.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
@ -11,71 +12,150 @@ class SymbolsResolver;
|
|||||||
|
|
||||||
namespace Libraries::ImeDialog {
|
namespace Libraries::ImeDialog {
|
||||||
|
|
||||||
enum OrbisImeDialogStatus {
|
constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 0x78;
|
||||||
ORBIS_IME_DIALOG_STATUS_NONE = 0,
|
|
||||||
ORBIS_IME_DIALOG_STATUS_RUNNING = 1,
|
enum class Error : u32 {
|
||||||
ORBIS_IME_DIALOG_STATUS_FINISHED = 2
|
OK = 0x0,
|
||||||
|
BUSY = 0x80bc0001,
|
||||||
|
NOT_OPENED = 0x80bc0002,
|
||||||
|
NO_MEMORY = 0x80bc0003,
|
||||||
|
CONNECTION_FAILED = 0x80bc0004,
|
||||||
|
TOO_MANY_REQUESTS = 0x80bc0005,
|
||||||
|
INVALID_TEXT = 0x80bc0006,
|
||||||
|
EVENT_OVERFLOW = 0x80bc0007,
|
||||||
|
NOT_ACTIVE = 0x80bc0008,
|
||||||
|
IME_SUSPENDING = 0x80bc0009,
|
||||||
|
DEVICE_IN_USE = 0x80bc000a,
|
||||||
|
INVALID_USER_ID = 0x80bc0010,
|
||||||
|
INVALID_TYPE = 0x80bc0011,
|
||||||
|
INVALID_SUPPORTED_LANGUAGES = 0x80bc0012,
|
||||||
|
INVALID_ENTER_LABEL = 0x80bc0013,
|
||||||
|
INVALID_INPUT_METHOD = 0x80bc0014,
|
||||||
|
INVALID_OPTION = 0x80bc0015,
|
||||||
|
INVALID_MAX_TEXT_LENGTH = 0x80bc0016,
|
||||||
|
INVALID_INPUT_TEXT_BUFFER = 0x80bc0017,
|
||||||
|
INVALID_POSX = 0x80bc0018,
|
||||||
|
INVALID_POSY = 0x80bc0019,
|
||||||
|
INVALID_HORIZONTALIGNMENT = 0x80bc001a,
|
||||||
|
INVALID_VERTICALALIGNMENT = 0x80bc001b,
|
||||||
|
INVALID_EXTENDED = 0x80bc001c,
|
||||||
|
INVALID_KEYBOARD_TYPE = 0x80bc001d,
|
||||||
|
INVALID_WORK = 0x80bc0020,
|
||||||
|
INVALID_ARG = 0x80bc0021,
|
||||||
|
INVALID_HANDLER = 0x80bc0022,
|
||||||
|
NO_RESOURCE_ID = 0x80bc0023,
|
||||||
|
INVALID_MODE = 0x80bc0024,
|
||||||
|
INVALID_PARAM = 0x80bc0030,
|
||||||
|
INVALID_ADDRESS = 0x80bc0031,
|
||||||
|
INVALID_RESERVED = 0x80bc0032,
|
||||||
|
INVALID_TIMING = 0x80bc0033,
|
||||||
|
INTERNAL = 0x80bc00ff,
|
||||||
|
DIALOG_INVALID_TITLE = 0x80bc0101,
|
||||||
|
DIALOG_NOT_RUNNING = 0x80bc0105,
|
||||||
|
DIALOG_NOT_FINISHED = 0x80bc0106,
|
||||||
|
DIALOG_NOT_IN_USE = 0x80bc0107,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OrbisImeDialogEndStatus {
|
enum class OrbisImeDialogStatus : u32 {
|
||||||
ORBIS_IME_DIALOG_END_STATUS_OK = 0,
|
NONE = 0,
|
||||||
ORBIS_IME_DIALOG_END_STATUS_USER_CANCELED = 1,
|
RUNNING = 1,
|
||||||
ORBIS_IME_DIALOG_END_STATUS_ABORTED = 2
|
FINISHED = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisImeDialogResult {
|
enum class OrbisImeDialogEndStatus : u32 {
|
||||||
OrbisImeDialogEndStatus endstatus;
|
OK = 0,
|
||||||
s32 reserved[12];
|
USER_CANCELED = 1,
|
||||||
|
ABORTED = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OrbisImeType {
|
enum class OrbisImeType : u32 {
|
||||||
ORBIS_IME_TYPE_DEFAULT = 0,
|
DEFAULT = 0,
|
||||||
ORBIS_IME_TYPE_BASIC_LATIN = 1,
|
BASIC_LATIN = 1,
|
||||||
ORBIS_IME_TYPE_URL = 2,
|
URL = 2,
|
||||||
ORBIS_IME_TYPE_MAIL = 3,
|
MAIL = 3,
|
||||||
ORBIS_IME_TYPE_NUMBER = 4
|
NUMBER = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OrbisImeEnterLabel {
|
enum class OrbisImeEnterLabel : u32 {
|
||||||
ORBIS_IME_ENTER_LABEL_DEFAULT = 0,
|
DEFAULT = 0,
|
||||||
ORBIS_IME_ENTER_LABEL_SEND = 1,
|
SEND = 1,
|
||||||
ORBIS_IME_ENTER_LABEL_SEARCH = 2,
|
SEARCH = 2,
|
||||||
ORBIS_IME_ENTER_LABEL_GO = 3
|
GO = 3,
|
||||||
};
|
|
||||||
enum OrbiImeInputMethod { ORBIS_IME_INPUT_METHOD_DEFAULT = 0 };
|
|
||||||
|
|
||||||
typedef int (*OrbisImeTextFilter)(wchar_t* outText, u32* outTextLength, const wchar_t* srcText,
|
|
||||||
u32 srcTextLength);
|
|
||||||
|
|
||||||
enum OrbisImeHorizontalAlignment {
|
|
||||||
ORBIS_IME_HALIGN_LEFT = 0,
|
|
||||||
ORBIS_IME_HALIGN_CENTER = 1,
|
|
||||||
ORBIS_IME_HALIGN_RIGHT = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OrbisImeVerticalAlignment {
|
enum class OrbisImeDialogOption : u32 {
|
||||||
ORBIS_IME_VALIGN_TOP = 0,
|
DEFAULT = 0,
|
||||||
ORBIS_IME_VALIGN_CENTER = 1,
|
MULTILINE = 1,
|
||||||
ORBIS_IME_VALIGN_BOTTOM = 2
|
NO_AUTO_CORRECTION = 2,
|
||||||
|
NO_AUTO_COMPLETION = 4,
|
||||||
|
// TODO: Document missing options
|
||||||
|
LARGE_RESOLUTION = 1024,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisImeDialogParam {
|
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDialogOption)
|
||||||
s32 userId;
|
|
||||||
OrbisImeType type;
|
enum class OrbisImeInputMethod : u32 {
|
||||||
u64 supportedLanguages;
|
DEFAULT = 0,
|
||||||
OrbisImeEnterLabel enterLabel;
|
};
|
||||||
OrbiImeInputMethod inputMethod;
|
|
||||||
OrbisImeTextFilter filter;
|
enum class OrbisImeHorizontalAlignment : u32 {
|
||||||
u32 option;
|
LEFT = 0,
|
||||||
u32 maxTextLength;
|
CENTER = 1,
|
||||||
wchar_t* inputTextBuffer;
|
RIGHT = 2,
|
||||||
float posx;
|
};
|
||||||
float posy;
|
|
||||||
OrbisImeHorizontalAlignment horizontalAlignment;
|
enum class OrbisImeVerticalAlignment : u32 {
|
||||||
OrbisImeVerticalAlignment verticalAlignment;
|
TOP = 0,
|
||||||
const wchar_t* placeholder;
|
CENTER = 1,
|
||||||
const wchar_t* title;
|
BOTTOM = 2,
|
||||||
s8 reserved[16];
|
};
|
||||||
|
|
||||||
|
enum class OrbisImePanelPriority : u32 {
|
||||||
|
DEFAULT = 0,
|
||||||
|
ALPHABET = 1,
|
||||||
|
SYMBOL = 2,
|
||||||
|
ACCENT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeKeyboardType : u32 {
|
||||||
|
NONE = 0,
|
||||||
|
DANISH = 1,
|
||||||
|
GERMAN = 2,
|
||||||
|
GERMAN_SW = 3,
|
||||||
|
ENGLISH_US = 4,
|
||||||
|
ENGLISH_GB = 5,
|
||||||
|
SPANISH = 6,
|
||||||
|
SPANISH_LA = 7,
|
||||||
|
FINNISH = 8,
|
||||||
|
FRENCH = 9,
|
||||||
|
FRENCH_BR = 10,
|
||||||
|
FRENCH_CA = 11,
|
||||||
|
FRENCH_SW = 12,
|
||||||
|
ITALIAN = 13,
|
||||||
|
DUTCH = 14,
|
||||||
|
NORWEGIAN = 15,
|
||||||
|
POLISH = 16,
|
||||||
|
PORTUGUESE_BR = 17,
|
||||||
|
PORTUGUESE_PT = 18,
|
||||||
|
RUSSIAN = 19,
|
||||||
|
SWEDISH = 20,
|
||||||
|
TURKISH = 21,
|
||||||
|
JAPANESE_ROMAN = 22,
|
||||||
|
JAPANESE_KANA = 23,
|
||||||
|
KOREAN = 24,
|
||||||
|
SM_CHINESE = 25,
|
||||||
|
TR_CHINESE_ZY = 26,
|
||||||
|
TR_CHINESE_PY_HK = 27,
|
||||||
|
TR_CHINESE_PY_TW = 28,
|
||||||
|
TR_CHINESE_CG = 29,
|
||||||
|
ARABIC_AR = 30,
|
||||||
|
THAI = 31,
|
||||||
|
CZECH = 32,
|
||||||
|
GREEK = 33,
|
||||||
|
INDONESIAN = 34,
|
||||||
|
VIETNAMESE = 35,
|
||||||
|
ROMANIAN = 36,
|
||||||
|
HUNGARIAN = 37,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisImeColor {
|
struct OrbisImeColor {
|
||||||
@ -85,57 +165,14 @@ struct OrbisImeColor {
|
|||||||
u8 a;
|
u8 a;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OrbisImePanelPriority {
|
struct OrbisImeDialogResult {
|
||||||
ORBIS_IME_PANEL_PRIORITY_DEFAULT = 0,
|
OrbisImeDialogEndStatus endstatus;
|
||||||
ORBIS_IME_PANEL_PRIORITY_ALPHABET = 1,
|
s32 reserved[12];
|
||||||
ORBIS_IME_PANEL_PRIORITY_SYMBOL = 2,
|
|
||||||
ORBIS_IME_PANEL_PRIORITY_ACCENT = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
enum OrbisImeKeyboardType {
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_NONE = 0,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_DANISH = 1,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_GERMAN = 2,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_GERMAN_SW = 3,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_ENGLISH_US = 4,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_ENGLISH_GB = 5,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_SPANISH = 6,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_SPANISH_LA = 7,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_FINNISH = 8,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_FRENCH = 9,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_FRENCH_BR = 10,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_FRENCH_CA = 11,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_FRENCH_SW = 12,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_ITALIAN = 13,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_DUTCH = 14,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_NORWEGIAN = 15,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_POLISH = 16,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_PORTUGUESE_BR = 17,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_PORTUGUESE_PT = 18,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_RUSSIAN = 19,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_SWEDISH = 20,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_TURKISH = 21,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_JAPANESE_ROMAN = 22,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_JAPANESE_KANA = 23,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_KOREAN = 24,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_SM_CHINESE = 25,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_TR_CHINESE_ZY = 26,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_TR_CHINESE_PY_HK = 27,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_TR_CHINESE_PY_TW = 28,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_TR_CHINESE_CG = 29,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_ARABIC_AR = 30,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_THAI = 31,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_CZECH = 32,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_GREEK = 33,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_INDONESIAN = 34,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_VIETNAMESE = 35,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_ROMANIAN = 36,
|
|
||||||
ORBIS_IME_KEYBOARD_TYPE_HUNGARIAN = 37
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrbisImeKeycode {
|
struct OrbisImeKeycode {
|
||||||
u16 keycode;
|
u16 keycode;
|
||||||
wchar_t character;
|
char16_t character;
|
||||||
u32 status;
|
u32 status;
|
||||||
OrbisImeKeyboardType type;
|
OrbisImeKeyboardType type;
|
||||||
s32 userId;
|
s32 userId;
|
||||||
@ -143,11 +180,34 @@ struct OrbisImeKeycode {
|
|||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*OrbisImeExtKeyboardFilter)(const OrbisImeKeycode* srcKeycode, u16* outKeycode,
|
typedef PS4_SYSV_ABI int (*OrbisImeTextFilter)(char16_t* outText, u32* outTextLength,
|
||||||
u32* outStatus, void* reserved);
|
const char16_t* srcText, u32 srcTextLength);
|
||||||
|
|
||||||
|
typedef PS4_SYSV_ABI int (*OrbisImeExtKeyboardFilter)(const OrbisImeKeycode* srcKeycode,
|
||||||
|
u16* outKeycode, u32* outStatus,
|
||||||
|
void* reserved);
|
||||||
|
|
||||||
|
struct OrbisImeDialogParam {
|
||||||
|
s32 userId;
|
||||||
|
OrbisImeType type;
|
||||||
|
u64 supportedLanguages;
|
||||||
|
OrbisImeEnterLabel enterLabel;
|
||||||
|
OrbisImeInputMethod inputMethod;
|
||||||
|
OrbisImeTextFilter filter;
|
||||||
|
OrbisImeDialogOption option;
|
||||||
|
u32 maxTextLength;
|
||||||
|
char16_t* inputTextBuffer;
|
||||||
|
float posx;
|
||||||
|
float posy;
|
||||||
|
OrbisImeHorizontalAlignment horizontalAlignment;
|
||||||
|
OrbisImeVerticalAlignment verticalAlignment;
|
||||||
|
const char16_t* placeholder;
|
||||||
|
const char16_t* title;
|
||||||
|
s8 reserved[16];
|
||||||
|
};
|
||||||
|
|
||||||
struct OrbisImeParamExtended {
|
struct OrbisImeParamExtended {
|
||||||
u32 option;
|
u32 option; // OrbisImeDialogOptionExtended
|
||||||
OrbisImeColor colorBase;
|
OrbisImeColor colorBase;
|
||||||
OrbisImeColor colorLine;
|
OrbisImeColor colorLine;
|
||||||
OrbisImeColor colorTextField;
|
OrbisImeColor colorTextField;
|
||||||
@ -165,21 +225,21 @@ struct OrbisImeParamExtended {
|
|||||||
int8_t reserved[60];
|
int8_t reserved[60];
|
||||||
};
|
};
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeDialogAbort();
|
Error PS4_SYSV_ABI sceImeDialogAbort();
|
||||||
int PS4_SYSV_ABI sceImeDialogForceClose();
|
Error PS4_SYSV_ABI sceImeDialogForceClose();
|
||||||
int PS4_SYSV_ABI sceImeDialogForTestFunction();
|
Error PS4_SYSV_ABI sceImeDialogForTestFunction();
|
||||||
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState();
|
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState();
|
||||||
int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm();
|
int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm();
|
||||||
int PS4_SYSV_ABI sceImeDialogGetPanelSize();
|
int PS4_SYSV_ABI sceImeDialogGetPanelSize();
|
||||||
int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended();
|
int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended();
|
||||||
int PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result);
|
Error PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result);
|
||||||
/*OrbisImeDialogStatus*/ int PS4_SYSV_ABI sceImeDialogGetStatus();
|
OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus();
|
||||||
int PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended);
|
Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended);
|
||||||
int PS4_SYSV_ABI sceImeDialogInitInternal();
|
int PS4_SYSV_ABI sceImeDialogInitInternal();
|
||||||
int PS4_SYSV_ABI sceImeDialogInitInternal2();
|
int PS4_SYSV_ABI sceImeDialogInitInternal2();
|
||||||
int PS4_SYSV_ABI sceImeDialogInitInternal3();
|
int PS4_SYSV_ABI sceImeDialogInitInternal3();
|
||||||
int PS4_SYSV_ABI sceImeDialogSetPanelPosition();
|
int PS4_SYSV_ABI sceImeDialogSetPanelPosition();
|
||||||
int PS4_SYSV_ABI sceImeDialogTerm();
|
Error PS4_SYSV_ABI sceImeDialogTerm();
|
||||||
|
|
||||||
void RegisterlibSceImeDialog(Core::Loader::SymbolsResolver* sym);
|
void RegisterlibSceImeDialog(Core::Loader::SymbolsResolver* sym);
|
||||||
} // namespace Libraries::ImeDialog
|
} // namespace Libraries::ImeDialog
|
390
src/core/libraries/dialogs/ime_dialog_ui.cpp
Normal file
390
src/core/libraries/dialogs/ime_dialog_ui.cpp
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cwchar>
|
||||||
|
#include <string>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "core/libraries/dialogs/ime_dialog.h"
|
||||||
|
#include "core/libraries/dialogs/ime_dialog_ui.h"
|
||||||
|
#include "core/linker.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
|
||||||
|
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||||
|
|
||||||
|
namespace Libraries::ImeDialog {
|
||||||
|
|
||||||
|
ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param,
|
||||||
|
const OrbisImeParamExtended* extended) {
|
||||||
|
if (!param)
|
||||||
|
return;
|
||||||
|
|
||||||
|
userId = param->userId;
|
||||||
|
is_multiLine = True(param->option & OrbisImeDialogOption::MULTILINE);
|
||||||
|
is_numeric = param->type == OrbisImeType::NUMBER;
|
||||||
|
type = param->type;
|
||||||
|
enter_label = param->enterLabel;
|
||||||
|
text_filter = param->filter;
|
||||||
|
keyboard_filter = extended ? extended->extKeyboardFilter : nullptr;
|
||||||
|
max_text_length = param->maxTextLength;
|
||||||
|
text_buffer = param->inputTextBuffer;
|
||||||
|
|
||||||
|
if (param->title) {
|
||||||
|
std::size_t title_len = std::char_traits<char16_t>::length(param->title);
|
||||||
|
title.resize(title_len * 4 + 1);
|
||||||
|
title[title_len * 4] = '\0';
|
||||||
|
|
||||||
|
if (!ConvertOrbisToUTF8(param->title, title_len, &title[0], title_len * 4)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert title to utf8 encoding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->placeholder) {
|
||||||
|
std::size_t placeholder_len = std::char_traits<char16_t>::length(param->placeholder);
|
||||||
|
placeholder.resize(placeholder_len * 4 + 1);
|
||||||
|
placeholder[placeholder_len * 4] = '\0';
|
||||||
|
|
||||||
|
if (!ConvertOrbisToUTF8(param->placeholder, placeholder_len, &placeholder[0],
|
||||||
|
placeholder_len * 4)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert placeholder to utf8 encoding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t text_len = std::char_traits<char16_t>::length(text_buffer);
|
||||||
|
if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(),
|
||||||
|
ORBIS_IME_DIALOG_MAX_TEXT_LENGTH * 4)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeDialogState::ImeDialogState(ImeDialogState&& other) noexcept
|
||||||
|
: input_changed(other.input_changed), userId(other.userId), is_multiLine(other.is_multiLine),
|
||||||
|
is_numeric(other.is_numeric), type(other.type), enter_label(other.enter_label),
|
||||||
|
text_filter(other.text_filter), keyboard_filter(other.keyboard_filter),
|
||||||
|
max_text_length(other.max_text_length), text_buffer(other.text_buffer),
|
||||||
|
title(std::move(other.title)), placeholder(std::move(other.placeholder)),
|
||||||
|
current_text(other.current_text) {
|
||||||
|
|
||||||
|
other.text_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeDialogState& ImeDialogState::operator=(ImeDialogState&& other) {
|
||||||
|
if (this != &other) {
|
||||||
|
input_changed = other.input_changed;
|
||||||
|
userId = other.userId;
|
||||||
|
is_multiLine = other.is_multiLine;
|
||||||
|
is_numeric = other.is_numeric;
|
||||||
|
type = other.type;
|
||||||
|
enter_label = other.enter_label;
|
||||||
|
text_filter = other.text_filter;
|
||||||
|
keyboard_filter = other.keyboard_filter;
|
||||||
|
max_text_length = other.max_text_length;
|
||||||
|
text_buffer = other.text_buffer;
|
||||||
|
title = std::move(other.title);
|
||||||
|
placeholder = std::move(other.placeholder);
|
||||||
|
current_text = other.current_text;
|
||||||
|
|
||||||
|
other.text_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeDialogState::CopyTextToOrbisBuffer() {
|
||||||
|
if (!text_buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConvertUTF8ToOrbis(current_text.begin(), current_text.capacity(), text_buffer,
|
||||||
|
max_text_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeDialogState::CallTextFilter() {
|
||||||
|
if (!text_filter || !input_changed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_changed = false;
|
||||||
|
|
||||||
|
char16_t src_text[ORBIS_IME_DIALOG_MAX_TEXT_LENGTH + 1] = {0};
|
||||||
|
u32 src_text_length = current_text.size();
|
||||||
|
char16_t out_text[ORBIS_IME_DIALOG_MAX_TEXT_LENGTH + 1] = {0};
|
||||||
|
u32 out_text_length = ORBIS_IME_DIALOG_MAX_TEXT_LENGTH;
|
||||||
|
|
||||||
|
if (!ConvertUTF8ToOrbis(current_text.begin(), src_text_length, src_text,
|
||||||
|
ORBIS_IME_DIALOG_MAX_TEXT_LENGTH)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to orbis encoding");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
int ret =
|
||||||
|
linker->ExecuteGuest(text_filter, out_text, &out_text_length, src_text, src_text_length);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ConvertOrbisToUTF8(out_text, out_text_length, current_text.begin(),
|
||||||
|
ORBIS_IME_DIALOG_MAX_TEXT_LENGTH * 4)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeDialogState::CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode,
|
||||||
|
u32* out_status) {
|
||||||
|
if (!keyboard_filter) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
int ret = linker->ExecuteGuest(keyboard_filter, src_keycode, out_keycode, out_status, nullptr);
|
||||||
|
|
||||||
|
return ret == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeDialogState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len,
|
||||||
|
char* utf8_text, std::size_t utf8_text_len) {
|
||||||
|
|
||||||
|
std::fill(utf8_text, utf8_text + utf8_text_len, '\0');
|
||||||
|
const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text);
|
||||||
|
ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeDialogState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len,
|
||||||
|
char16_t* orbis_text, std::size_t orbis_text_len) {
|
||||||
|
|
||||||
|
std::fill(orbis_text, orbis_text + orbis_text_len, u'\0');
|
||||||
|
ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeDialogUi::ImeDialogUi(ImeDialogState* state, OrbisImeDialogStatus* status,
|
||||||
|
OrbisImeDialogResult* result)
|
||||||
|
: state(state), status(status), result(result) {
|
||||||
|
|
||||||
|
if (state && *status == OrbisImeDialogStatus::RUNNING) {
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeDialogUi::~ImeDialogUi() {
|
||||||
|
std::scoped_lock lock(draw_mutex);
|
||||||
|
|
||||||
|
Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeDialogUi::ImeDialogUi(ImeDialogUi&& other) noexcept
|
||||||
|
: state(other.state), status(other.status), result(other.result),
|
||||||
|
first_render(other.first_render) {
|
||||||
|
|
||||||
|
std::scoped_lock lock(draw_mutex, other.draw_mutex);
|
||||||
|
other.state = nullptr;
|
||||||
|
other.status = nullptr;
|
||||||
|
other.result = nullptr;
|
||||||
|
|
||||||
|
if (state && *status == OrbisImeDialogStatus::RUNNING) {
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeDialogUi& ImeDialogUi::operator=(ImeDialogUi&& other) {
|
||||||
|
std::scoped_lock lock(draw_mutex, other.draw_mutex);
|
||||||
|
Free();
|
||||||
|
|
||||||
|
state = other.state;
|
||||||
|
status = other.status;
|
||||||
|
result = other.result;
|
||||||
|
first_render = other.first_render;
|
||||||
|
other.state = nullptr;
|
||||||
|
other.status = nullptr;
|
||||||
|
other.result = nullptr;
|
||||||
|
|
||||||
|
if (state && *status == OrbisImeDialogStatus::RUNNING) {
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeDialogUi::Free() {
|
||||||
|
RemoveLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeDialogUi::Draw() {
|
||||||
|
std::unique_lock lock{draw_mutex};
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!status || *status != OrbisImeDialogStatus::RUNNING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& ctx = *GetCurrentContext();
|
||||||
|
const auto& io = ctx.IO;
|
||||||
|
|
||||||
|
ImVec2 window_size;
|
||||||
|
|
||||||
|
if (state->is_multiLine) {
|
||||||
|
window_size = {500.0f, 300.0f};
|
||||||
|
} else {
|
||||||
|
window_size = {500.0f, 150.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
CentralizeWindow();
|
||||||
|
SetNextWindowSize(window_size);
|
||||||
|
SetNextWindowCollapsed(false);
|
||||||
|
|
||||||
|
if (first_render || !io.NavActive) {
|
||||||
|
SetNextWindowFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Begin("IME Dialog##ImeDialog", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
DrawPrettyBackground();
|
||||||
|
|
||||||
|
if (!state->title.empty()) {
|
||||||
|
SetWindowFontScale(1.7f);
|
||||||
|
TextUnformatted(state->title.data());
|
||||||
|
SetWindowFontScale(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->is_multiLine) {
|
||||||
|
DrawMultiLineInputText();
|
||||||
|
} else {
|
||||||
|
DrawInputText();
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCursorPosY(GetCursorPosY() + 10.0f);
|
||||||
|
|
||||||
|
const char* button_text;
|
||||||
|
|
||||||
|
switch (state->enter_label) {
|
||||||
|
case OrbisImeEnterLabel::GO:
|
||||||
|
button_text = "Go##ImeDialogOK";
|
||||||
|
break;
|
||||||
|
case OrbisImeEnterLabel::SEARCH:
|
||||||
|
button_text = "Search##ImeDialogOK";
|
||||||
|
break;
|
||||||
|
case OrbisImeEnterLabel::SEND:
|
||||||
|
button_text = "Send##ImeDialogOK";
|
||||||
|
break;
|
||||||
|
case OrbisImeEnterLabel::DEFAULT:
|
||||||
|
default:
|
||||||
|
button_text = "OK##ImeDialogOK";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float button_spacing = 10.0f;
|
||||||
|
float total_button_width = BUTTON_SIZE.x * 2 + button_spacing;
|
||||||
|
float button_start_pos = (window_size.x - total_button_width) / 2.0f;
|
||||||
|
|
||||||
|
SetCursorPosX(button_start_pos);
|
||||||
|
|
||||||
|
if (Button(button_text, BUTTON_SIZE) ||
|
||||||
|
(!state->is_multiLine && IsKeyPressed(ImGuiKey_Enter))) {
|
||||||
|
*status = OrbisImeDialogStatus::FINISHED;
|
||||||
|
result->endstatus = OrbisImeDialogEndStatus::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SameLine(0.0f, button_spacing);
|
||||||
|
|
||||||
|
if (Button("Cancel##ImeDialogCancel", BUTTON_SIZE)) {
|
||||||
|
*status = OrbisImeDialogStatus::FINISHED;
|
||||||
|
result->endstatus = OrbisImeDialogEndStatus::USER_CANCELED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
first_render = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeDialogUi::DrawInputText() {
|
||||||
|
ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f};
|
||||||
|
SetCursorPosX(20.0f);
|
||||||
|
if (first_render) {
|
||||||
|
SetKeyboardFocusHere();
|
||||||
|
}
|
||||||
|
const char* placeholder = state->placeholder.empty() ? nullptr : state->placeholder.data();
|
||||||
|
if (InputTextEx("##ImeDialogInput", placeholder, state->current_text.begin(),
|
||||||
|
state->max_text_length, input_size, ImGuiInputTextFlags_CallbackCharFilter,
|
||||||
|
InputTextCallback, this)) {
|
||||||
|
state->input_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeDialogUi::DrawMultiLineInputText() {
|
||||||
|
ImVec2 input_size = {GetWindowWidth() - 40.0f, 200.0f};
|
||||||
|
SetCursorPosX(20.0f);
|
||||||
|
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CallbackCharFilter |
|
||||||
|
static_cast<ImGuiInputTextFlags>(ImGuiInputTextFlags_Multiline);
|
||||||
|
if (first_render) {
|
||||||
|
SetKeyboardFocusHere();
|
||||||
|
}
|
||||||
|
const char* placeholder = state->placeholder.empty() ? nullptr : state->placeholder.data();
|
||||||
|
if (InputTextEx("##ImeDialogInput", placeholder, state->current_text.begin(),
|
||||||
|
state->max_text_length, input_size, flags, InputTextCallback, this)) {
|
||||||
|
state->input_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||||
|
ImeDialogUi* ui = static_cast<ImeDialogUi*>(data->UserData);
|
||||||
|
|
||||||
|
ASSERT(ui);
|
||||||
|
|
||||||
|
// Should we filter punctuation?
|
||||||
|
if (ui->state->is_numeric && (data->EventChar < '0' || data->EventChar > '9') &&
|
||||||
|
data->EventChar != '\b' && data->EventChar != ',' && data->EventChar != '.') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ui->state->keyboard_filter) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImGui encodes ImWchar32 as multi-byte UTF-8 characters
|
||||||
|
char* event_char = reinterpret_cast<char*>(&data->EventChar);
|
||||||
|
|
||||||
|
// Call the keyboard filter
|
||||||
|
OrbisImeKeycode src_keycode = {
|
||||||
|
.keycode = 0,
|
||||||
|
.character = 0,
|
||||||
|
.status = 1, // ??? 1 = key pressed, 0 = key released
|
||||||
|
.type = OrbisImeKeyboardType::ENGLISH_US, // TODO set this to the correct value (maybe use
|
||||||
|
// the current language?)
|
||||||
|
.userId = ui->state->userId,
|
||||||
|
.resourceId = 0,
|
||||||
|
.timestamp = 0};
|
||||||
|
|
||||||
|
if (!ui->state->ConvertUTF8ToOrbis(event_char, 4, &src_keycode.character, 1)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert orbis char to utf8");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
src_keycode.keycode = src_keycode.character; // TODO set this to the correct value
|
||||||
|
|
||||||
|
u16 out_keycode;
|
||||||
|
u32 out_status;
|
||||||
|
|
||||||
|
ui->state->CallKeyboardFilter(&src_keycode, &out_keycode, &out_status);
|
||||||
|
|
||||||
|
// TODO. set the keycode
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libraries::ImeDialog
|
84
src/core/libraries/dialogs/ime_dialog_ui.h
Normal file
84
src/core/libraries/dialogs/ime_dialog_ui.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include "common/cstring.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/dialogs/ime_dialog.h"
|
||||||
|
#include "imgui/imgui_layer.h"
|
||||||
|
|
||||||
|
namespace Libraries::ImeDialog {
|
||||||
|
|
||||||
|
class ImeDialogUi;
|
||||||
|
|
||||||
|
class ImeDialogState final {
|
||||||
|
friend ImeDialogUi;
|
||||||
|
|
||||||
|
bool input_changed = false;
|
||||||
|
|
||||||
|
s32 userId{};
|
||||||
|
bool is_multiLine{};
|
||||||
|
bool is_numeric{};
|
||||||
|
OrbisImeType type{};
|
||||||
|
OrbisImeEnterLabel enter_label{};
|
||||||
|
OrbisImeTextFilter text_filter{};
|
||||||
|
OrbisImeExtKeyboardFilter keyboard_filter{};
|
||||||
|
u32 max_text_length{};
|
||||||
|
char16_t* text_buffer{};
|
||||||
|
std::vector<char> title;
|
||||||
|
std::vector<char> placeholder;
|
||||||
|
|
||||||
|
// A character can hold up to 4 bytes in UTF-8
|
||||||
|
Common::CString<ORBIS_IME_DIALOG_MAX_TEXT_LENGTH * 4> current_text;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImeDialogState(const OrbisImeDialogParam* param = nullptr,
|
||||||
|
const OrbisImeParamExtended* extended = nullptr);
|
||||||
|
ImeDialogState(const ImeDialogState& other) = delete;
|
||||||
|
ImeDialogState(ImeDialogState&& other) noexcept;
|
||||||
|
ImeDialogState& operator=(ImeDialogState&& other);
|
||||||
|
|
||||||
|
bool CopyTextToOrbisBuffer();
|
||||||
|
bool CallTextFilter();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode, u32* out_status);
|
||||||
|
|
||||||
|
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text,
|
||||||
|
std::size_t native_text_len);
|
||||||
|
bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len,
|
||||||
|
char16_t* orbis_text, std::size_t orbis_text_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImeDialogUi final : public ImGui::Layer {
|
||||||
|
ImeDialogState* state{};
|
||||||
|
OrbisImeDialogStatus* status{};
|
||||||
|
OrbisImeDialogResult* result{};
|
||||||
|
|
||||||
|
bool first_render = true;
|
||||||
|
std::mutex draw_mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImeDialogUi(ImeDialogState* state = nullptr, OrbisImeDialogStatus* status = nullptr,
|
||||||
|
OrbisImeDialogResult* result = nullptr);
|
||||||
|
~ImeDialogUi() override;
|
||||||
|
ImeDialogUi(const ImeDialogUi& other) = delete;
|
||||||
|
ImeDialogUi(ImeDialogUi&& other) noexcept;
|
||||||
|
ImeDialogUi& operator=(ImeDialogUi&& other);
|
||||||
|
|
||||||
|
void Draw() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Free();
|
||||||
|
|
||||||
|
void DrawInputText();
|
||||||
|
void DrawMultiLineInputText();
|
||||||
|
|
||||||
|
static int InputTextCallback(ImGuiInputTextCallbackData* data);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::ImeDialog
|
@ -500,3 +500,11 @@ constexpr int ORBIS_AVPLAYER_ERROR_INFO_OTHER_ENCRY = 0x806A00BF;
|
|||||||
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
|
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
|
||||||
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
|
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
|
||||||
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
||||||
|
|
||||||
|
// Fiber library
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_NULL = 0x80590001;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_ALIGNMENT = 0x80590002;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_RANGE = 0x80590003;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_INVALID = 0x80590004;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_PERMISSION = 0x80590005;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_STATE = 0x80590006;
|
284
src/core/libraries/fiber/fiber.cpp
Normal file
284
src/core/libraries/fiber/fiber.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "fiber.h"
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/linker.h"
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Libraries::Fiber {
|
||||||
|
|
||||||
|
constexpr static u64 kFiberSignature = 0x054ad954;
|
||||||
|
|
||||||
|
thread_local SceFiber* gCurrentFiber = nullptr;
|
||||||
|
thread_local void* gFiberThread = nullptr;
|
||||||
|
|
||||||
|
void FiberEntry(void* param) {
|
||||||
|
SceFiber* fiber = static_cast<SceFiber*>(param);
|
||||||
|
u64 argRun = 0;
|
||||||
|
u64 argRet = 0;
|
||||||
|
|
||||||
|
gCurrentFiber = fiber;
|
||||||
|
|
||||||
|
if (fiber->pArgRun != nullptr) {
|
||||||
|
argRun = *fiber->pArgRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
linker->ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun);
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry,
|
||||||
|
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||||
|
const SceFiberOptParam* optParam) {
|
||||||
|
LOG_INFO(Lib_Fiber, "called: name = {}", name);
|
||||||
|
|
||||||
|
if (!fiber || !name || !entry) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiber->signature = kFiberSignature;
|
||||||
|
|
||||||
|
fiber->entry = entry;
|
||||||
|
fiber->argOnInitialize = argOnInitialize;
|
||||||
|
|
||||||
|
fiber->argRun = 0;
|
||||||
|
fiber->pArgRun = &fiber->argRun;
|
||||||
|
fiber->argReturn = 0;
|
||||||
|
fiber->pArgReturn = &fiber->argReturn;
|
||||||
|
|
||||||
|
fiber->sizeContext = sizeContext;
|
||||||
|
|
||||||
|
fiber->state = FiberState::Init;
|
||||||
|
#ifdef _WIN64
|
||||||
|
fiber->handle = CreateFiber(sizeContext, FiberEntry, fiber);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam) {
|
||||||
|
LOG_ERROR(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!optParam) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
if (fiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (fiber->state != FiberState::Run) {
|
||||||
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiber->signature = 0;
|
||||||
|
fiber->state = FiberState::None;
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
DeleteFiber(fiber->handle);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
if (fiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (fiber->state == FiberState::Run) {
|
||||||
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gFiberThread == nullptr) {
|
||||||
|
#ifdef _WIN64
|
||||||
|
gFiberThread = ConvertThreadToFiber(nullptr);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
gCurrentFiber = fiber;
|
||||||
|
|
||||||
|
if (fiber->pArgRun != nullptr) {
|
||||||
|
*fiber->pArgRun = argOnRunTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiber->pArgReturn = argOnReturn;
|
||||||
|
fiber->state = FiberState::Run;
|
||||||
|
#ifdef _WIN64
|
||||||
|
SwitchToFiber(fiber->handle);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
if (fiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (gCurrentFiber == nullptr) {
|
||||||
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
|
}
|
||||||
|
if (fiber->state == FiberState::Run) {
|
||||||
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gCurrentFiber->state = FiberState::Suspend;
|
||||||
|
|
||||||
|
// TODO: argOnRun
|
||||||
|
|
||||||
|
*fiber->pArgRun = argOnRunTo;
|
||||||
|
fiber->state = FiberState::Run;
|
||||||
|
|
||||||
|
gCurrentFiber = fiber;
|
||||||
|
#ifdef _WIN64
|
||||||
|
SwitchToFiber(fiber->handle);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber || !gCurrentFiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if (gCurrentFiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fiber = gCurrentFiber;
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (gCurrentFiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gCurrentFiber->pArgReturn != nullptr) {
|
||||||
|
*gCurrentFiber->pArgReturn = argOnReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: argOnRun
|
||||||
|
gCurrentFiber->state = FiberState::Suspend;
|
||||||
|
gCurrentFiber = nullptr;
|
||||||
|
#ifdef _WIN64
|
||||||
|
SwitchToFiber(gFiberThread);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo) {
|
||||||
|
LOG_INFO(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber || !fiberInfo) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiberInfo->entry = fiber->entry;
|
||||||
|
fiberInfo->argOnInitialize = fiber->argOnInitialize;
|
||||||
|
fiberInfo->addrContext = nullptr;
|
||||||
|
fiberInfo->sizeContext = fiber->sizeContext;
|
||||||
|
fiberInfo->sizeContextMargin = 0;
|
||||||
|
|
||||||
|
strncpy(fiberInfo->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags) {
|
||||||
|
LOG_ERROR(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() {
|
||||||
|
LOG_ERROR(Lib_Fiber, "called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) {
|
||||||
|
LOG_INFO(Lib_Fiber, "called, name = {}", name);
|
||||||
|
|
||||||
|
if (!fiber || !name) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||||
|
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
||||||
|
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
||||||
|
|
||||||
|
LIB_FUNCTION("a0LLrZWac0M", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRun);
|
||||||
|
LIB_FUNCTION("PFT2S-tJ7Uk", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberSwitch);
|
||||||
|
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
|
||||||
|
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
|
||||||
|
|
||||||
|
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
|
||||||
|
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberStartContextSizeCheck);
|
||||||
|
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberStopContextSizeCheck);
|
||||||
|
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libraries::Fiber
|
83
src/core/libraries/fiber/fiber.h
Normal file
83
src/core/libraries/fiber/fiber.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
namespace Core::Loader {
|
||||||
|
class SymbolsResolver;
|
||||||
|
}
|
||||||
|
namespace Libraries::Fiber {
|
||||||
|
|
||||||
|
#define ORBIS_FIBER_MAX_NAME_LENGTH (31)
|
||||||
|
|
||||||
|
typedef void PS4_SYSV_ABI (*SceFiberEntry)(u64 argOnInitialize, u64 argOnRun);
|
||||||
|
|
||||||
|
enum FiberState : u32 {
|
||||||
|
None = 0u,
|
||||||
|
Init = 1u,
|
||||||
|
Run = 2u,
|
||||||
|
Suspend = 3u,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceFiber {
|
||||||
|
u64 signature;
|
||||||
|
FiberState state;
|
||||||
|
SceFiberEntry entry;
|
||||||
|
|
||||||
|
u64 argOnInitialize;
|
||||||
|
|
||||||
|
u64 argRun;
|
||||||
|
u64* pArgRun;
|
||||||
|
|
||||||
|
u64 argReturn;
|
||||||
|
u64* pArgReturn;
|
||||||
|
|
||||||
|
u64 sizeContext;
|
||||||
|
|
||||||
|
char name[ORBIS_FIBER_MAX_NAME_LENGTH];
|
||||||
|
void* handle;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SceFiber) <= 256);
|
||||||
|
|
||||||
|
struct SceFiberInfo {
|
||||||
|
u64 size;
|
||||||
|
SceFiberEntry entry;
|
||||||
|
u64 argOnInitialize;
|
||||||
|
void* addrContext;
|
||||||
|
u64 sizeContext;
|
||||||
|
char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1];
|
||||||
|
u64 sizeContextMargin;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SceFiberInfo) <= 128);
|
||||||
|
|
||||||
|
typedef void* SceFiberOptParam;
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry,
|
||||||
|
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||||
|
const SceFiberOptParam* optParam);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name);
|
||||||
|
|
||||||
|
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Fiber
|
354
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
Normal file
354
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "gamelivestreaming.h"
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
namespace Libraries::GameLiveStreaming {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStartDebugBroadcast() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStopDebugBroadcast() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingApplySocialFeedbackMessageFilter() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingCheckCallback() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingClearPresetSocialFeedbackCommands() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingClearSocialFeedbackMessages() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingClearSpoilerTag() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingEnableLiveStreaming() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingEnableSocialFeedback() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetCurrentBroadcastScreenLayout() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetCurrentStatus(OrbisGameLiveStreamingStatus* status) {
|
||||||
|
memset(status, 0, sizeof(*status));
|
||||||
|
status->isOnAir = false;
|
||||||
|
LOG_DEBUG(Lib_GameLiveStreaming, "(STUBBED) called userid = {}", status->userId);
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetCurrentStatus2() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetProgramInfo() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetSocialFeedbackMessages() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetSocialFeedbackMessagesCount() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingInitialize() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingLaunchLiveViewer() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingLaunchLiveViewerA() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingPermitLiveStreaming() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingPermitServerSideRecording() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingPostSocialMessage() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingRegisterCallback() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenCloseSeparateMode() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenConfigureSeparateMode() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenInitialize() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenInitializeSeparateModeParameter() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenOpenSeparateMode() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenSetMode() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenTerminate() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetCameraFrameSetting() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetDefaultServiceProviderPermission() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetGuardAreas() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetInvitationSessionId() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetLinkCommentPreset() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetMaxBitrate() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetMetadata() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetPresetSocialFeedbackCommands() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetPresetSocialFeedbackCommandsDescription() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetServiceProviderPermission() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetSpoilerTag() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetStandbyScreenResource() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStartGenerateStandbyScreenResource() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStartSocialFeedbackMessageFiltering() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStopGenerateStandbyScreenResource() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStopSocialFeedbackMessageFiltering() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingTerminate() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingUnregisterCallback() {
|
||||||
|
LOG_ERROR(Lib_GameLiveStreaming, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceGameLiveStreaming(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("caqgDl+V9qA", "libSceGameLiveStreaming_debug", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingStartDebugBroadcast);
|
||||||
|
LIB_FUNCTION("0i8Lrllxwow", "libSceGameLiveStreaming_debug", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingStopDebugBroadcast);
|
||||||
|
LIB_FUNCTION("NqkTzemliC0", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingApplySocialFeedbackMessageFilter);
|
||||||
|
LIB_FUNCTION("PC4jq87+YQI", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingCheckCallback);
|
||||||
|
LIB_FUNCTION("FcHBfHjFXkA", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingClearPresetSocialFeedbackCommands);
|
||||||
|
LIB_FUNCTION("lZ2Sd0uEvpo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingClearSocialFeedbackMessages);
|
||||||
|
LIB_FUNCTION("6c2zGtThFww", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingClearSpoilerTag);
|
||||||
|
LIB_FUNCTION("dWM80AX39o4", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingEnableLiveStreaming);
|
||||||
|
LIB_FUNCTION("wBOQWjbWMfU", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingEnableSocialFeedback);
|
||||||
|
LIB_FUNCTION("aRSQNqbats4", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetCurrentBroadcastScreenLayout);
|
||||||
|
LIB_FUNCTION("CoPMx369EqM", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetCurrentStatus);
|
||||||
|
LIB_FUNCTION("lK8dLBNp9OE", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetCurrentStatus2);
|
||||||
|
LIB_FUNCTION("OIIm19xu+NM", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetProgramInfo);
|
||||||
|
LIB_FUNCTION("PMx7N4WqNdo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetSocialFeedbackMessages);
|
||||||
|
LIB_FUNCTION("yeQKjHETi40", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetSocialFeedbackMessagesCount);
|
||||||
|
LIB_FUNCTION("kvYEw2lBndk", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingInitialize);
|
||||||
|
LIB_FUNCTION("ysWfX5PPbfc", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingLaunchLiveViewer);
|
||||||
|
LIB_FUNCTION("cvRCb7DTAig", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingLaunchLiveViewerA);
|
||||||
|
LIB_FUNCTION("K0QxEbD7q+c", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingPermitLiveStreaming);
|
||||||
|
LIB_FUNCTION("-EHnU68gExU", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingPermitServerSideRecording);
|
||||||
|
LIB_FUNCTION("hggKhPySVgI", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingPostSocialMessage);
|
||||||
|
LIB_FUNCTION("nFP8qT9YXbo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingRegisterCallback);
|
||||||
|
LIB_FUNCTION("b5RaMD2J0So", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenCloseSeparateMode);
|
||||||
|
LIB_FUNCTION("hBdd8n6kuvE", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenConfigureSeparateMode);
|
||||||
|
LIB_FUNCTION("uhCmn81s-mU", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenInitialize);
|
||||||
|
LIB_FUNCTION("fo5B8RUaBxQ", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenInitializeSeparateModeParameter);
|
||||||
|
LIB_FUNCTION("iorzW0pKOiA", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenOpenSeparateMode);
|
||||||
|
LIB_FUNCTION("gDSvt78H3Oo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenSetMode);
|
||||||
|
LIB_FUNCTION("HE93dr-5rx4", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingScreenTerminate);
|
||||||
|
LIB_FUNCTION("3PSiwAzFISE", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetCameraFrameSetting);
|
||||||
|
LIB_FUNCTION("TwuUzTKKeek", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetDefaultServiceProviderPermission);
|
||||||
|
LIB_FUNCTION("Gw6S4oqlY7E", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetGuardAreas);
|
||||||
|
LIB_FUNCTION("QmQYwQ7OTJI", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetInvitationSessionId);
|
||||||
|
LIB_FUNCTION("Sb5bAXyUt5c", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetLinkCommentPreset);
|
||||||
|
LIB_FUNCTION("q-kxuaF7URU", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetMaxBitrate);
|
||||||
|
LIB_FUNCTION("hUY-mSOyGL0", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetMetadata);
|
||||||
|
LIB_FUNCTION("ycodiP2I0xo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetPresetSocialFeedbackCommands);
|
||||||
|
LIB_FUNCTION("x6deXUpQbBo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetPresetSocialFeedbackCommandsDescription);
|
||||||
|
LIB_FUNCTION("mCoz3k3zPmA", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetServiceProviderPermission);
|
||||||
|
LIB_FUNCTION("ZuX+zzz2DkA", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetSpoilerTag);
|
||||||
|
LIB_FUNCTION("MLvYI86FFAo", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingSetStandbyScreenResource);
|
||||||
|
LIB_FUNCTION("y0KkAydy9xE", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingStartGenerateStandbyScreenResource);
|
||||||
|
LIB_FUNCTION("Y1WxX7dPMCw", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingStartSocialFeedbackMessageFiltering);
|
||||||
|
LIB_FUNCTION("D7dg5QJ4FlE", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingStopGenerateStandbyScreenResource);
|
||||||
|
LIB_FUNCTION("bYuGUBuIsaY", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingStopSocialFeedbackMessageFiltering);
|
||||||
|
LIB_FUNCTION("9yK6Fk8mKOQ", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingTerminate);
|
||||||
|
LIB_FUNCTION("5XHaH3kL+bA", "libSceGameLiveStreaming", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingUnregisterCallback);
|
||||||
|
LIB_FUNCTION("caqgDl+V9qA", "libSceGameLiveStreaming_direct_streaming", 1,
|
||||||
|
"libSceGameLiveStreaming", 1, 1, sceGameLiveStreamingStartDebugBroadcast);
|
||||||
|
LIB_FUNCTION("0i8Lrllxwow", "libSceGameLiveStreaming_direct_streaming", 1,
|
||||||
|
"libSceGameLiveStreaming", 1, 1, sceGameLiveStreamingStopDebugBroadcast);
|
||||||
|
LIB_FUNCTION("CoPMx369EqM", "libSceGameLiveStreamingCompat", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingGetCurrentStatus);
|
||||||
|
LIB_FUNCTION("ysWfX5PPbfc", "libSceGameLiveStreamingCompat", 1, "libSceGameLiveStreaming", 1, 1,
|
||||||
|
sceGameLiveStreamingLaunchLiveViewer);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::GameLiveStreaming
|
81
src/core/libraries/game_live_streaming/gamelivestreaming.h
Normal file
81
src/core/libraries/game_live_streaming/gamelivestreaming.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// 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::GameLiveStreaming {
|
||||||
|
|
||||||
|
struct OrbisGameLiveStreamingStatus {
|
||||||
|
bool isOnAir;
|
||||||
|
u8 align[3];
|
||||||
|
u32 spectatorCounts;
|
||||||
|
s32 userId;
|
||||||
|
u8 reserved[60];
|
||||||
|
};
|
||||||
|
struct OrbisGameLiveStreamingStatus2 {
|
||||||
|
s32 userId;
|
||||||
|
bool isOnAir;
|
||||||
|
u8 align[3];
|
||||||
|
u32 spectatorCounts;
|
||||||
|
u32 textMessageCounts;
|
||||||
|
u32 commandMessageCounts;
|
||||||
|
u32 broadcastVideoResolution;
|
||||||
|
u8 reserved[48];
|
||||||
|
};
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStartDebugBroadcast();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStopDebugBroadcast();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingApplySocialFeedbackMessageFilter();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingCheckCallback();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingClearPresetSocialFeedbackCommands();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingClearSocialFeedbackMessages();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingClearSpoilerTag();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingEnableLiveStreaming();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingEnableSocialFeedback();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetCurrentBroadcastScreenLayout();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetCurrentStatus(OrbisGameLiveStreamingStatus* status);
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetCurrentStatus2();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetProgramInfo();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetSocialFeedbackMessages();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingGetSocialFeedbackMessagesCount();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingInitialize();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingLaunchLiveViewer();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingLaunchLiveViewerA();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingPermitLiveStreaming();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingPermitServerSideRecording();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingPostSocialMessage();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingRegisterCallback();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenCloseSeparateMode();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenConfigureSeparateMode();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenInitialize();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenInitializeSeparateModeParameter();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenOpenSeparateMode();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenSetMode();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingScreenTerminate();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetCameraFrameSetting();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetDefaultServiceProviderPermission();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetGuardAreas();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetInvitationSessionId();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetLinkCommentPreset();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetMaxBitrate();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetMetadata();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetPresetSocialFeedbackCommands();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetPresetSocialFeedbackCommandsDescription();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetServiceProviderPermission();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetSpoilerTag();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingSetStandbyScreenResource();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStartGenerateStandbyScreenResource();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStartSocialFeedbackMessageFiltering();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStopGenerateStandbyScreenResource();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingStopSocialFeedbackMessageFiltering();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingTerminate();
|
||||||
|
int PS4_SYSV_ABI sceGameLiveStreamingUnregisterCallback();
|
||||||
|
|
||||||
|
void RegisterlibSceGameLiveStreaming(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::GameLiveStreaming
|
@ -519,10 +519,12 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
// Dumping them using the current ring pointer would result in files containing only the
|
// Dumping them using the current ring pointer would result in files containing only the
|
||||||
// `IndirectBuffer` command. To access the actual command stream, we need to unwrap the IB.
|
// `IndirectBuffer` command. To access the actual command stream, we need to unwrap the IB.
|
||||||
auto acb = acb_span;
|
auto acb = acb_span;
|
||||||
|
auto base_addr = reinterpret_cast<uintptr_t>(acb_ptr);
|
||||||
const auto* indirect_buffer =
|
const auto* indirect_buffer =
|
||||||
reinterpret_cast<const PM4CmdIndirectBuffer*>(acb_span.data());
|
reinterpret_cast<const PM4CmdIndirectBuffer*>(acb_span.data());
|
||||||
if (indirect_buffer->header.opcode == PM4ItOpcode::IndirectBuffer) {
|
if (indirect_buffer->header.opcode == PM4ItOpcode::IndirectBuffer) {
|
||||||
acb = {indirect_buffer->Address<const u32>(), indirect_buffer->ib_size};
|
base_addr = reinterpret_cast<uintptr_t>(indirect_buffer->Address<const u32>());
|
||||||
|
acb = {reinterpret_cast<const u32*>(base_addr), indirect_buffer->ib_size};
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace DebugStateType;
|
using namespace DebugStateType;
|
||||||
@ -532,9 +534,9 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
.submit_num = seq_num,
|
.submit_num = seq_num,
|
||||||
.num2 = gnm_vqid,
|
.num2 = gnm_vqid,
|
||||||
.data = {acb.begin(), acb.end()},
|
.data = {acb.begin(), acb.end()},
|
||||||
|
.base_addr = base_addr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
liverpool->SubmitAsc(vqid, acb_span);
|
liverpool->SubmitAsc(vqid, acb_span);
|
||||||
|
|
||||||
*asc_queue.read_addr += acb_size;
|
*asc_queue.read_addr += acb_size;
|
||||||
@ -1076,10 +1078,28 @@ s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertPushColorMarker() {
|
s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
|
if (cmdbuf && marker) {
|
||||||
|
const auto len = std::strlen(marker);
|
||||||
|
const u32 packet_size = ((len + 0xc) >> 2) + ((len + 0x10) >> 3) * 2;
|
||||||
|
if (packet_size + 2 == size) {
|
||||||
|
auto* nop = reinterpret_cast<PM4CmdNop*>(cmdbuf);
|
||||||
|
nop->header =
|
||||||
|
PM4Type3Header{PM4ItOpcode::Nop, packet_size, PM4ShaderType::ShaderGraphics};
|
||||||
|
nop->data_block[0] = PM4CmdNop::PayloadType::DebugColorMarkerPush;
|
||||||
|
const auto marker_len = len + 1;
|
||||||
|
std::memcpy(&nop->data_block[1], marker, marker_len);
|
||||||
|
*reinterpret_cast<u32*>(reinterpret_cast<u8*>(&nop->data_block[1]) + marker_len + 8) =
|
||||||
|
color;
|
||||||
|
std::memset(reinterpret_cast<u8*>(&nop->data_block[1]) + marker_len + 8 + sizeof(u32),
|
||||||
|
0, packet_size * 4 - marker_len - 8 - sizeof(u32));
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker) {
|
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker) {
|
||||||
LOG_TRACE(Lib_GnmDriver, "called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
@ -1107,10 +1127,26 @@ int PS4_SYSV_ABI sceGnmInsertSetColorMarker() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker() {
|
s32 PS4_SYSV_ABI sceGnmInsertSetMarker(u32* cmdbuf, u32 size, const char* marker) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
|
if (cmdbuf && marker) {
|
||||||
|
const auto len = std::strlen(marker);
|
||||||
|
const u32 packet_size = ((len + 8) >> 2) + ((len + 0xc) >> 3) * 2;
|
||||||
|
if (packet_size + 2 == size) {
|
||||||
|
auto* nop = reinterpret_cast<PM4CmdNop*>(cmdbuf);
|
||||||
|
nop->header =
|
||||||
|
PM4Type3Header{PM4ItOpcode::Nop, packet_size, PM4ShaderType::ShaderGraphics};
|
||||||
|
nop->data_block[0] = PM4CmdNop::PayloadType::DebugSetMarker;
|
||||||
|
const auto marker_len = len + 1;
|
||||||
|
std::memcpy(&nop->data_block[1], marker, marker_len);
|
||||||
|
std::memset(reinterpret_cast<u8*>(&nop->data_block[1]) + marker_len, 0,
|
||||||
|
packet_size * 4 - marker_len);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker() {
|
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker() {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||||
@ -2145,15 +2181,16 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
|||||||
.submit_num = seq_num,
|
.submit_num = seq_num,
|
||||||
.num2 = cbpair,
|
.num2 = cbpair,
|
||||||
.data = {dcb_span.begin(), dcb_span.end()},
|
.data = {dcb_span.begin(), dcb_span.end()},
|
||||||
|
.base_addr = reinterpret_cast<uintptr_t>(dcb_gpu_addrs[cbpair]),
|
||||||
});
|
});
|
||||||
DebugState.PushQueueDump({
|
DebugState.PushQueueDump({
|
||||||
.type = QueueType::ccb,
|
.type = QueueType::ccb,
|
||||||
.submit_num = seq_num,
|
.submit_num = seq_num,
|
||||||
.num2 = cbpair,
|
.num2 = cbpair,
|
||||||
.data = {ccb_span.begin(), ccb_span.end()},
|
.data = {ccb_span.begin(), ccb_span.end()},
|
||||||
|
.base_addr = reinterpret_cast<uintptr_t>(ccb),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
liverpool->SubmitGfx(dcb_span, ccb_span);
|
liverpool->SubmitGfx(dcb_span, ccb_span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +105,10 @@ int PS4_SYSV_ABI sceGnmGpuPaDebugEnter();
|
|||||||
int PS4_SYSV_ABI sceGnmGpuPaDebugLeave();
|
int PS4_SYSV_ABI sceGnmGpuPaDebugLeave();
|
||||||
int PS4_SYSV_ABI sceGnmInsertDingDongMarker();
|
int PS4_SYSV_ABI sceGnmInsertDingDongMarker();
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size);
|
s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size);
|
||||||
int PS4_SYSV_ABI sceGnmInsertPushColorMarker();
|
s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color);
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker();
|
s32 PS4_SYSV_ABI sceGnmInsertSetMarker(u32* cmdbuf, u32 size, const char* marker);
|
||||||
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker();
|
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker();
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle, u32 buf_idx);
|
s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle, u32 buf_idx);
|
||||||
int PS4_SYSV_ABI sceGnmIsCoredumpValid();
|
int PS4_SYSV_ABI sceGnmIsCoredumpValid();
|
||||||
|
340
src/core/libraries/ime/ime.cpp
Normal file
340
src/core/libraries/ime/ime.cpp
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "ime.h"
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
namespace Libraries::Ime {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI FinalizeImeModule() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI InitializeImeModule() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeCheckFilterText() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeCheckRemoteEventParam() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeCheckUpdateTextInfo() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeClose() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeConfigGet() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeConfigSet() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeConfirmCandidate() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDicAddWord() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDicDeleteLearnDics() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDicDeleteUserDics() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDicDeleteWord() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDicGetWords() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDicReplaceWord() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeDisableController() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeFilterText() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeForTestFunction() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeGetPanelSize() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardClose() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardGetInfo() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardGetResourceId() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardOpen() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardOpenInternal() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardSetMode() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardUpdate() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeOpen() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeOpenInternal() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeParamInit() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeSetCandidateIndex() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeSetCaret() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeSetText() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeSetTextGeometry() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeUpdate() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshClearPreedit() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshClose() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshConfirmPreedit() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshDisableController() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshGetPanelPositionAndForm() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshInformConfirmdString() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshInformConfirmdString2() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshOpen() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSendTextInfo() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetCaretGeometry() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetCaretIndexInPreedit() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetPanelPosition() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetParam() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetPreeditGeometry() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetSelectGeometry() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetSelectionText() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshUpdate() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshUpdateContext() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceImeVshUpdateContext2() {
|
||||||
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceIme(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("mN+ZoSN-8hQ", "libSceIme", 1, "libSceIme", 1, 1, FinalizeImeModule);
|
||||||
|
LIB_FUNCTION("uTW+63goeJs", "libSceIme", 1, "libSceIme", 1, 1, InitializeImeModule);
|
||||||
|
LIB_FUNCTION("Lf3DeGWC6xg", "libSceIme", 1, "libSceIme", 1, 1, sceImeCheckFilterText);
|
||||||
|
LIB_FUNCTION("zHuMUGb-AQI", "libSceIme", 1, "libSceIme", 1, 1, sceImeCheckRemoteEventParam);
|
||||||
|
LIB_FUNCTION("OTb0Mg+1i1k", "libSceIme", 1, "libSceIme", 1, 1, sceImeCheckUpdateTextInfo);
|
||||||
|
LIB_FUNCTION("TmVP8LzcFcY", "libSceIme", 1, "libSceIme", 1, 1, sceImeClose);
|
||||||
|
LIB_FUNCTION("Ho5NVQzpKHo", "libSceIme", 1, "libSceIme", 1, 1, sceImeConfigGet);
|
||||||
|
LIB_FUNCTION("P5dPeiLwm-M", "libSceIme", 1, "libSceIme", 1, 1, sceImeConfigSet);
|
||||||
|
LIB_FUNCTION("tKLmVIUkpyM", "libSceIme", 1, "libSceIme", 1, 1, sceImeConfirmCandidate);
|
||||||
|
LIB_FUNCTION("NYDsL9a0oEo", "libSceIme", 1, "libSceIme", 1, 1, sceImeDicAddWord);
|
||||||
|
LIB_FUNCTION("l01GKoyiQrY", "libSceIme", 1, "libSceIme", 1, 1, sceImeDicDeleteLearnDics);
|
||||||
|
LIB_FUNCTION("E2OcGgi-FPY", "libSceIme", 1, "libSceIme", 1, 1, sceImeDicDeleteUserDics);
|
||||||
|
LIB_FUNCTION("JAiMBkOTYKI", "libSceIme", 1, "libSceIme", 1, 1, sceImeDicDeleteWord);
|
||||||
|
LIB_FUNCTION("JoPdCUXOzMU", "libSceIme", 1, "libSceIme", 1, 1, sceImeDicGetWords);
|
||||||
|
LIB_FUNCTION("FuEl46uHDyo", "libSceIme", 1, "libSceIme", 1, 1, sceImeDicReplaceWord);
|
||||||
|
LIB_FUNCTION("E+f1n8e8DAw", "libSceIme", 1, "libSceIme", 1, 1, sceImeDisableController);
|
||||||
|
LIB_FUNCTION("evjOsE18yuI", "libSceIme", 1, "libSceIme", 1, 1, sceImeFilterText);
|
||||||
|
LIB_FUNCTION("wVkehxutK-U", "libSceIme", 1, "libSceIme", 1, 1, sceImeForTestFunction);
|
||||||
|
LIB_FUNCTION("T6FYjZXG93o", "libSceIme", 1, "libSceIme", 1, 1, sceImeGetPanelPositionAndForm);
|
||||||
|
LIB_FUNCTION("ziPDcIjO0Vk", "libSceIme", 1, "libSceIme", 1, 1, sceImeGetPanelSize);
|
||||||
|
LIB_FUNCTION("PMVehSlfZ94", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardClose);
|
||||||
|
LIB_FUNCTION("VkqLPArfFdc", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardGetInfo);
|
||||||
|
LIB_FUNCTION("dKadqZFgKKQ", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardGetResourceId);
|
||||||
|
LIB_FUNCTION("eaFXjfJv3xs", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardOpen);
|
||||||
|
LIB_FUNCTION("oYkJlMK51SA", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardOpenInternal);
|
||||||
|
LIB_FUNCTION("ua+13Hk9kKs", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardSetMode);
|
||||||
|
LIB_FUNCTION("3Hx2Uw9xnv8", "libSceIme", 1, "libSceIme", 1, 1, sceImeKeyboardUpdate);
|
||||||
|
LIB_FUNCTION("RPydv-Jr1bc", "libSceIme", 1, "libSceIme", 1, 1, sceImeOpen);
|
||||||
|
LIB_FUNCTION("16UI54cWRQk", "libSceIme", 1, "libSceIme", 1, 1, sceImeOpenInternal);
|
||||||
|
LIB_FUNCTION("WmYDzdC4EHI", "libSceIme", 1, "libSceIme", 1, 1, sceImeParamInit);
|
||||||
|
LIB_FUNCTION("TQaogSaqkEk", "libSceIme", 1, "libSceIme", 1, 1, sceImeSetCandidateIndex);
|
||||||
|
LIB_FUNCTION("WLxUN2WMim8", "libSceIme", 1, "libSceIme", 1, 1, sceImeSetCaret);
|
||||||
|
LIB_FUNCTION("ieCNrVrzKd4", "libSceIme", 1, "libSceIme", 1, 1, sceImeSetText);
|
||||||
|
LIB_FUNCTION("TXYHFRuL8UY", "libSceIme", 1, "libSceIme", 1, 1, sceImeSetTextGeometry);
|
||||||
|
LIB_FUNCTION("-4GCfYdNF1s", "libSceIme", 1, "libSceIme", 1, 1, sceImeUpdate);
|
||||||
|
LIB_FUNCTION("oOwl47ouxoM", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshClearPreedit);
|
||||||
|
LIB_FUNCTION("gtoTsGM9vEY", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshClose);
|
||||||
|
LIB_FUNCTION("wTKF4mUlSew", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshConfirmPreedit);
|
||||||
|
LIB_FUNCTION("rM-1hkuOhh0", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshDisableController);
|
||||||
|
LIB_FUNCTION("42xMaQ+GLeQ", "libSceIme", 1, "libSceIme", 1, 1,
|
||||||
|
sceImeVshGetPanelPositionAndForm);
|
||||||
|
LIB_FUNCTION("ZmmV6iukhyo", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshInformConfirmdString);
|
||||||
|
LIB_FUNCTION("EQBusz6Uhp8", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshInformConfirmdString2);
|
||||||
|
LIB_FUNCTION("LBicRa-hj3A", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshOpen);
|
||||||
|
LIB_FUNCTION("-IAOwd2nO7g", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSendTextInfo);
|
||||||
|
LIB_FUNCTION("qDagOjvJdNk", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetCaretGeometry);
|
||||||
|
LIB_FUNCTION("tNOlmxee-Nk", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetCaretIndexInPreedit);
|
||||||
|
LIB_FUNCTION("rASXozKkQ9g", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetPanelPosition);
|
||||||
|
LIB_FUNCTION("idvMaIu5H+k", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetParam);
|
||||||
|
LIB_FUNCTION("ga5GOgThbjo", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetPreeditGeometry);
|
||||||
|
LIB_FUNCTION("RuSca8rS6yA", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetSelectGeometry);
|
||||||
|
LIB_FUNCTION("J7COZrgSFRA", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshSetSelectionText);
|
||||||
|
LIB_FUNCTION("WqAayyok5p0", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshUpdate);
|
||||||
|
LIB_FUNCTION("O7Fdd+Oc-qQ", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshUpdateContext);
|
||||||
|
LIB_FUNCTION("fwcPR7+7Rks", "libSceIme", 1, "libSceIme", 1, 1, sceImeVshUpdateContext2);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Ime
|
70
src/core/libraries/ime/ime.h
Normal file
70
src/core/libraries/ime/ime.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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::Ime {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI FinalizeImeModule();
|
||||||
|
int PS4_SYSV_ABI InitializeImeModule();
|
||||||
|
int PS4_SYSV_ABI sceImeCheckFilterText();
|
||||||
|
int PS4_SYSV_ABI sceImeCheckRemoteEventParam();
|
||||||
|
int PS4_SYSV_ABI sceImeCheckUpdateTextInfo();
|
||||||
|
int PS4_SYSV_ABI sceImeClose();
|
||||||
|
int PS4_SYSV_ABI sceImeConfigGet();
|
||||||
|
int PS4_SYSV_ABI sceImeConfigSet();
|
||||||
|
int PS4_SYSV_ABI sceImeConfirmCandidate();
|
||||||
|
int PS4_SYSV_ABI sceImeDicAddWord();
|
||||||
|
int PS4_SYSV_ABI sceImeDicDeleteLearnDics();
|
||||||
|
int PS4_SYSV_ABI sceImeDicDeleteUserDics();
|
||||||
|
int PS4_SYSV_ABI sceImeDicDeleteWord();
|
||||||
|
int PS4_SYSV_ABI sceImeDicGetWords();
|
||||||
|
int PS4_SYSV_ABI sceImeDicReplaceWord();
|
||||||
|
int PS4_SYSV_ABI sceImeDisableController();
|
||||||
|
int PS4_SYSV_ABI sceImeFilterText();
|
||||||
|
int PS4_SYSV_ABI sceImeForTestFunction();
|
||||||
|
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm();
|
||||||
|
int PS4_SYSV_ABI sceImeGetPanelSize();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardClose();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardGetInfo();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardGetResourceId();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardOpen();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardOpenInternal();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardSetMode();
|
||||||
|
int PS4_SYSV_ABI sceImeKeyboardUpdate();
|
||||||
|
int PS4_SYSV_ABI sceImeOpen();
|
||||||
|
int PS4_SYSV_ABI sceImeOpenInternal();
|
||||||
|
int PS4_SYSV_ABI sceImeParamInit();
|
||||||
|
int PS4_SYSV_ABI sceImeSetCandidateIndex();
|
||||||
|
int PS4_SYSV_ABI sceImeSetCaret();
|
||||||
|
int PS4_SYSV_ABI sceImeSetText();
|
||||||
|
int PS4_SYSV_ABI sceImeSetTextGeometry();
|
||||||
|
int PS4_SYSV_ABI sceImeUpdate();
|
||||||
|
int PS4_SYSV_ABI sceImeVshClearPreedit();
|
||||||
|
int PS4_SYSV_ABI sceImeVshClose();
|
||||||
|
int PS4_SYSV_ABI sceImeVshConfirmPreedit();
|
||||||
|
int PS4_SYSV_ABI sceImeVshDisableController();
|
||||||
|
int PS4_SYSV_ABI sceImeVshGetPanelPositionAndForm();
|
||||||
|
int PS4_SYSV_ABI sceImeVshInformConfirmdString();
|
||||||
|
int PS4_SYSV_ABI sceImeVshInformConfirmdString2();
|
||||||
|
int PS4_SYSV_ABI sceImeVshOpen();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSendTextInfo();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetCaretGeometry();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetCaretIndexInPreedit();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetPanelPosition();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetParam();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetPreeditGeometry();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetSelectGeometry();
|
||||||
|
int PS4_SYSV_ABI sceImeVshSetSelectionText();
|
||||||
|
int PS4_SYSV_ABI sceImeVshUpdate();
|
||||||
|
int PS4_SYSV_ABI sceImeVshUpdateContext();
|
||||||
|
int PS4_SYSV_ABI sceImeVshUpdateContext2();
|
||||||
|
|
||||||
|
void RegisterlibSceIme(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Ime
|
@ -321,25 +321,25 @@ int PS4_SYSV_ABI sceKernelRmdir(const char* path) {
|
|||||||
const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
|
const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
|
||||||
|
|
||||||
if (dir_name.empty()) {
|
if (dir_name.empty()) {
|
||||||
LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, permission denied",
|
LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, permission denied",
|
||||||
fmt::UTF(dir_name.u8string()));
|
fmt::UTF(dir_name.u8string()));
|
||||||
return SCE_KERNEL_ERROR_EACCES;
|
return SCE_KERNEL_ERROR_EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ro) {
|
if (ro) {
|
||||||
LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, directory is read only",
|
LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, directory is read only",
|
||||||
fmt::UTF(dir_name.u8string()));
|
fmt::UTF(dir_name.u8string()));
|
||||||
return SCE_KERNEL_ERROR_EROFS;
|
return SCE_KERNEL_ERROR_EROFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::filesystem::is_directory(dir_name)) {
|
if (!std::filesystem::is_directory(dir_name)) {
|
||||||
LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, path is not a directory",
|
LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, path is not a directory",
|
||||||
fmt::UTF(dir_name.u8string()));
|
fmt::UTF(dir_name.u8string()));
|
||||||
return ORBIS_KERNEL_ERROR_ENOTDIR;
|
return ORBIS_KERNEL_ERROR_ENOTDIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::filesystem::exists(dir_name)) {
|
if (!std::filesystem::exists(dir_name)) {
|
||||||
LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, no such file or directory",
|
LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, no such file or directory",
|
||||||
fmt::UTF(dir_name.u8string()));
|
fmt::UTF(dir_name.u8string()));
|
||||||
return ORBIS_KERNEL_ERROR_ENOENT;
|
return ORBIS_KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
@ -348,7 +348,7 @@ int PS4_SYSV_ABI sceKernelRmdir(const char* path) {
|
|||||||
int result = std::filesystem::remove_all(dir_name, ec);
|
int result = std::filesystem::remove_all(dir_name, ec);
|
||||||
|
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
LOG_DEBUG(Kernel_Fs, "Removed directory: {}", fmt::UTF(dir_name.u8string()));
|
LOG_INFO(Kernel_Fs, "Removed directory: {}", fmt::UTF(dir_name.u8string()));
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, error_code={}",
|
LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, error_code={}",
|
||||||
|
@ -157,6 +157,7 @@ void SetPosixErrno(int e) {
|
|||||||
g_posix_errno = e;
|
g_posix_errno = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset,
|
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset,
|
||||||
void** res) {
|
void** res) {
|
||||||
LOG_INFO(Kernel_Vmm, "called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, offset = {}",
|
LOG_INFO(Kernel_Vmm, "called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, offset = {}",
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5056_MB; // ~ 5GB
|
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5056_MB; // ~ 5GB
|
||||||
|
// TODO: Confirm this value on hardware.
|
||||||
|
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE_PRO = 5568_MB; // ~ 5.5GB
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ void init_pthreads() {
|
|||||||
ScePthreadMutexattr default_mutexattr = nullptr;
|
ScePthreadMutexattr default_mutexattr = nullptr;
|
||||||
scePthreadMutexattrInit(&default_mutexattr);
|
scePthreadMutexattrInit(&default_mutexattr);
|
||||||
g_pthread_cxt->setDefaultMutexattr(default_mutexattr);
|
g_pthread_cxt->setDefaultMutexattr(default_mutexattr);
|
||||||
|
ScePthreadMutexattr adaptive_mutexattr = nullptr;
|
||||||
|
scePthreadMutexattrInit(&adaptive_mutexattr);
|
||||||
|
scePthreadMutexattrSettype(&adaptive_mutexattr, ORBIS_PTHREAD_MUTEX_ADAPTIVE);
|
||||||
|
g_pthread_cxt->setAdaptiveMutexattr(adaptive_mutexattr);
|
||||||
// default cond init
|
// default cond init
|
||||||
ScePthreadCondattr default_condattr = nullptr;
|
ScePthreadCondattr default_condattr = nullptr;
|
||||||
scePthreadCondattrInit(&default_condattr);
|
scePthreadCondattrInit(&default_condattr);
|
||||||
@ -412,7 +416,8 @@ int PS4_SYSV_ABI scePthreadGetaffinity(ScePthread thread, /*SceKernelCpumask*/ u
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScePthreadMutex* createMutex(ScePthreadMutex* addr) {
|
ScePthreadMutex* createMutex(ScePthreadMutex* addr) {
|
||||||
if (addr == nullptr || *addr != nullptr) {
|
if (addr == nullptr ||
|
||||||
|
(*addr != nullptr && *addr != ORBIS_PTHREAD_MUTEX_ADAPTIVE_INITIALIZER)) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,15 +434,15 @@ int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMut
|
|||||||
if (mutex == nullptr) {
|
if (mutex == nullptr) {
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
if (mutex_attr == nullptr) {
|
if (mutex_attr == nullptr || *mutex_attr == nullptr) {
|
||||||
attr = g_pthread_cxt->getDefaultMutexattr();
|
if (*mutex == ORBIS_PTHREAD_MUTEX_ADAPTIVE_INITIALIZER) {
|
||||||
|
attr = g_pthread_cxt->getAdaptiveMutexattr();
|
||||||
} else {
|
} else {
|
||||||
if (*mutex_attr == nullptr) {
|
|
||||||
attr = g_pthread_cxt->getDefaultMutexattr();
|
attr = g_pthread_cxt->getDefaultMutexattr();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
attr = mutex_attr;
|
attr = mutex_attr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
*mutex = new PthreadMutexInternal{};
|
*mutex = new PthreadMutexInternal{};
|
||||||
if (name != nullptr) {
|
if (name != nullptr) {
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#define ORBIS_PTHREAD_MUTEX_ADAPTIVE_INITIALIZER (reinterpret_cast<ScePthreadMutex>(1))
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
}
|
}
|
||||||
@ -134,6 +136,12 @@ public:
|
|||||||
void setDefaultMutexattr(ScePthreadMutexattr attr) {
|
void setDefaultMutexattr(ScePthreadMutexattr attr) {
|
||||||
m_default_mutexattr = attr;
|
m_default_mutexattr = attr;
|
||||||
}
|
}
|
||||||
|
ScePthreadMutexattr* getAdaptiveMutexattr() {
|
||||||
|
return &m_adaptive_mutexattr;
|
||||||
|
}
|
||||||
|
void setAdaptiveMutexattr(ScePthreadMutexattr attr) {
|
||||||
|
m_adaptive_mutexattr = attr;
|
||||||
|
}
|
||||||
ScePthreadCondattr* getDefaultCondattr() {
|
ScePthreadCondattr* getDefaultCondattr() {
|
||||||
return &m_default_condattr;
|
return &m_default_condattr;
|
||||||
}
|
}
|
||||||
@ -161,6 +169,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ScePthreadMutexattr m_default_mutexattr = nullptr;
|
ScePthreadMutexattr m_default_mutexattr = nullptr;
|
||||||
|
ScePthreadMutexattr m_adaptive_mutexattr = nullptr;
|
||||||
ScePthreadCondattr m_default_condattr = nullptr;
|
ScePthreadCondattr m_default_condattr = nullptr;
|
||||||
ScePthreadAttr m_default_attr = nullptr;
|
ScePthreadAttr m_default_attr = nullptr;
|
||||||
PThreadPool* m_pthread_pool = nullptr;
|
PThreadPool* m_pthread_pool = nullptr;
|
||||||
|
@ -148,7 +148,7 @@ int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
|
|||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
FILETIME filetime;
|
FILETIME filetime;
|
||||||
GetSystemTimeAsFileTime(&filetime);
|
GetSystemTimePreciseAsFileTime(&filetime);
|
||||||
|
|
||||||
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
||||||
constexpr u64 TICKS_PER_SECOND = 1000000;
|
constexpr u64 TICKS_PER_SECOND = 1000000;
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
#include "core/libraries/dialogs/error_dialog.h"
|
#include "core/libraries/dialogs/error_dialog.h"
|
||||||
#include "core/libraries/dialogs/ime_dialog.h"
|
#include "core/libraries/dialogs/ime_dialog.h"
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
|
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
|
||||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||||
|
#include "core/libraries/ime/ime.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/libkernel.h"
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libpng/pngdec.h"
|
#include "core/libraries/libpng/pngdec.h"
|
||||||
@ -26,10 +28,12 @@
|
|||||||
#include "core/libraries/pad/pad.h"
|
#include "core/libraries/pad/pad.h"
|
||||||
#include "core/libraries/playgo/playgo.h"
|
#include "core/libraries/playgo/playgo.h"
|
||||||
#include "core/libraries/random/random.h"
|
#include "core/libraries/random/random.h"
|
||||||
|
#include "core/libraries/remote_play/remoteplay.h"
|
||||||
#include "core/libraries/rtc/rtc.h"
|
#include "core/libraries/rtc/rtc.h"
|
||||||
#include "core/libraries/save_data/dialog/savedatadialog.h"
|
#include "core/libraries/save_data/dialog/savedatadialog.h"
|
||||||
#include "core/libraries/save_data/savedata.h"
|
#include "core/libraries/save_data/savedata.h"
|
||||||
#include "core/libraries/screenshot/screenshot.h"
|
#include "core/libraries/screenshot/screenshot.h"
|
||||||
|
#include "core/libraries/share_play/shareplay.h"
|
||||||
#include "core/libraries/system/commondialog.h"
|
#include "core/libraries/system/commondialog.h"
|
||||||
#include "core/libraries/system/msgdialog.h"
|
#include "core/libraries/system/msgdialog.h"
|
||||||
#include "core/libraries/system/posix.h"
|
#include "core/libraries/system/posix.h"
|
||||||
@ -77,6 +81,10 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||||||
Libraries::ImeDialog::RegisterlibSceImeDialog(sym);
|
Libraries::ImeDialog::RegisterlibSceImeDialog(sym);
|
||||||
Libraries::AvPlayer::RegisterlibSceAvPlayer(sym);
|
Libraries::AvPlayer::RegisterlibSceAvPlayer(sym);
|
||||||
Libraries::Audio3d::RegisterlibSceAudio3d(sym);
|
Libraries::Audio3d::RegisterlibSceAudio3d(sym);
|
||||||
|
Libraries::Ime::RegisterlibSceIme(sym);
|
||||||
|
Libraries::GameLiveStreaming::RegisterlibSceGameLiveStreaming(sym);
|
||||||
|
Libraries::SharePlay::RegisterlibSceSharePlay(sym);
|
||||||
|
Libraries::Remoteplay::RegisterlibSceRemoteplay(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries
|
} // namespace Libraries
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
namespace Libraries::Net {
|
namespace Libraries::Net {
|
||||||
|
|
||||||
|
static thread_local int32_t net_errno = 0;
|
||||||
|
|
||||||
int PS4_SYSV_ABI in6addr_any() {
|
int PS4_SYSV_ABI in6addr_any() {
|
||||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -563,9 +565,9 @@ int PS4_SYSV_ABI sceNetEpollWait() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetErrnoLoc() {
|
int* PS4_SYSV_ABI sceNetErrnoLoc() {
|
||||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return &net_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetEtherNtostr() {
|
int PS4_SYSV_ABI sceNetEtherNtostr() {
|
||||||
@ -732,9 +734,16 @@ int PS4_SYSV_ABI sceNetInetNtopWithScopeId() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetInetPton() {
|
int PS4_SYSV_ABI sceNetInetPton(int af, const char* src, void* dst) {
|
||||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
#ifdef WIN32
|
||||||
return ORBIS_OK;
|
int res = InetPtonA(af, src, dst);
|
||||||
|
#else
|
||||||
|
int res = inet_pton(af, src, dst);
|
||||||
|
#endif
|
||||||
|
if (res < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetInetPtonEx() {
|
int PS4_SYSV_ABI sceNetInetPtonEx() {
|
||||||
|
@ -136,7 +136,7 @@ int PS4_SYSV_ABI sceNetEpollControl();
|
|||||||
int PS4_SYSV_ABI sceNetEpollCreate();
|
int PS4_SYSV_ABI sceNetEpollCreate();
|
||||||
int PS4_SYSV_ABI sceNetEpollDestroy();
|
int PS4_SYSV_ABI sceNetEpollDestroy();
|
||||||
int PS4_SYSV_ABI sceNetEpollWait();
|
int PS4_SYSV_ABI sceNetEpollWait();
|
||||||
int PS4_SYSV_ABI sceNetErrnoLoc();
|
int* PS4_SYSV_ABI sceNetErrnoLoc();
|
||||||
int PS4_SYSV_ABI sceNetEtherNtostr();
|
int PS4_SYSV_ABI sceNetEtherNtostr();
|
||||||
int PS4_SYSV_ABI sceNetEtherStrton();
|
int PS4_SYSV_ABI sceNetEtherStrton();
|
||||||
int PS4_SYSV_ABI sceNetEventCallbackCreate();
|
int PS4_SYSV_ABI sceNetEventCallbackCreate();
|
||||||
@ -169,7 +169,7 @@ u64 PS4_SYSV_ABI sceNetHtonll(u64 host64);
|
|||||||
u16 PS4_SYSV_ABI sceNetHtons(u16 host16);
|
u16 PS4_SYSV_ABI sceNetHtons(u16 host16);
|
||||||
const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 size);
|
const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 size);
|
||||||
int PS4_SYSV_ABI sceNetInetNtopWithScopeId();
|
int PS4_SYSV_ABI sceNetInetNtopWithScopeId();
|
||||||
int PS4_SYSV_ABI sceNetInetPton();
|
int PS4_SYSV_ABI sceNetInetPton(int af, const char* src, void* dst);
|
||||||
int PS4_SYSV_ABI sceNetInetPtonEx();
|
int PS4_SYSV_ABI sceNetInetPtonEx();
|
||||||
int PS4_SYSV_ABI sceNetInetPtonWithScopeId();
|
int PS4_SYSV_ABI sceNetInetPtonWithScopeId();
|
||||||
int PS4_SYSV_ABI sceNetInfoDumpStart();
|
int PS4_SYSV_ABI sceNetInfoDumpStart();
|
||||||
|
@ -26,3 +26,11 @@ constexpr int ORBIS_NET_CTL_STATE_IPOBTAINED = 3;
|
|||||||
constexpr int ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED = 1;
|
constexpr int ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED = 1;
|
||||||
constexpr int ORBIS_SCE_NET_CTL_EVENT_TYPE_DISCONNECT_REQ_FINISHED = 2;
|
constexpr int ORBIS_SCE_NET_CTL_EVENT_TYPE_DISCONNECT_REQ_FINISHED = 2;
|
||||||
constexpr int ORBIS_NET_CTL_EVENT_TYPE_IPOBTAINED = 3;
|
constexpr int ORBIS_NET_CTL_EVENT_TYPE_IPOBTAINED = 3;
|
||||||
|
|
||||||
|
// get info codes
|
||||||
|
// device
|
||||||
|
constexpr int ORBIS_NET_CTL_DEVICE_WIRED = 0;
|
||||||
|
constexpr int ORBIS_NET_CTL_DEVICE_WIRELESS = 1;
|
||||||
|
// link
|
||||||
|
constexpr int ORBIS_NET_CTL_LINK_DISCONNECTED = 0;
|
||||||
|
constexpr int ORBIS_NET_CTL_LINK_CONNECTED = 1;
|
||||||
|
0
src/core/libraries/network/net_obj.cpp
Normal file
0
src/core/libraries/network/net_obj.cpp
Normal file
0
src/core/libraries/network/net_obj.h
Normal file
0
src/core/libraries/network/net_obj.h
Normal file
@ -1,6 +1,17 @@
|
|||||||
// 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
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||||
|
#include <Ws2tcpip.h>
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
@ -149,15 +160,32 @@ int PS4_SYSV_ABI sceNetCtlGetIfStat() {
|
|||||||
int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
|
int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ORBIS_NET_CTL_INFO_DEVICE:
|
case ORBIS_NET_CTL_INFO_DEVICE:
|
||||||
info->device = 0;
|
info->device = ORBIS_NET_CTL_DEVICE_WIRED;
|
||||||
break;
|
break;
|
||||||
case ORBIS_NET_CTL_INFO_LINK:
|
case ORBIS_NET_CTL_INFO_LINK:
|
||||||
info->link = 0; // disconnected
|
info->link = ORBIS_NET_CTL_LINK_DISCONNECTED;
|
||||||
break;
|
break;
|
||||||
|
case ORBIS_NET_CTL_INFO_IP_ADDRESS: {
|
||||||
|
strcpy(info->ip_address,
|
||||||
|
"127.0.0.1"); // placeholder in case gethostbyname can't find another ip
|
||||||
|
char devname[80];
|
||||||
|
gethostname(devname, 80);
|
||||||
|
struct hostent* resolved = gethostbyname(devname);
|
||||||
|
for (int i = 0; resolved->h_addr_list[i] != nullptr; ++i) {
|
||||||
|
struct in_addr addrIn;
|
||||||
|
memcpy(&addrIn, resolved->h_addr_list[i], sizeof(u32));
|
||||||
|
char* addr = inet_ntoa(addrIn);
|
||||||
|
if (strcmp(addr, "127.0.0.1") != 0) {
|
||||||
|
strcpy(info->ip_address, addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Lib_NetCtl, "{} unsupported code", code);
|
LOG_ERROR(Lib_NetCtl, "{} unsupported code", code);
|
||||||
}
|
}
|
||||||
LOG_ERROR(Lib_NetCtl, "(STUBBED) called");
|
LOG_DEBUG(Lib_NetCtl, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +215,10 @@ int PS4_SYSV_ABI sceNetCtlGetNetEvConfigInfoIpcInt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetCtlGetResult(int eventType, int* errorCode) {
|
int PS4_SYSV_ABI sceNetCtlGetResult(int eventType, int* errorCode) {
|
||||||
LOG_ERROR(Lib_NetCtl, "(STUBBED) called eventType = {} ", eventType);
|
if (!errorCode) {
|
||||||
|
return ORBIS_NET_CTL_ERROR_INVALID_ADDR;
|
||||||
|
}
|
||||||
|
LOG_DEBUG(Lib_NetCtl, "(STUBBED) called eventType = {} ", eventType);
|
||||||
*errorCode = 0;
|
*errorCode = 0;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ typedef union OrbisNetCtlInfo {
|
|||||||
// GetInfo codes
|
// GetInfo codes
|
||||||
constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1;
|
constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1;
|
||||||
constexpr int ORBIS_NET_CTL_INFO_LINK = 4;
|
constexpr int ORBIS_NET_CTL_INFO_LINK = 4;
|
||||||
|
constexpr int ORBIS_NET_CTL_INFO_IP_ADDRESS = 14;
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetBweCheckCallbackIpcInt();
|
int PS4_SYSV_ABI sceNetBweCheckCallbackIpcInt();
|
||||||
int PS4_SYSV_ABI sceNetBweClearEventIpcInt();
|
int PS4_SYSV_ABI sceNetBweClearEventIpcInt();
|
||||||
|
@ -902,12 +902,13 @@ int PS4_SYSV_ABI sceNpCreateAsyncRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpCreateRequest() {
|
int PS4_SYSV_ABI sceNpCreateRequest() {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_ERROR(Lib_NpManager, "(DUMMY) called");
|
||||||
return ORBIS_OK;
|
static int id = 0;
|
||||||
|
return ++id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpDeleteRequest() {
|
int PS4_SYSV_ABI sceNpDeleteRequest(int reqId) {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_ERROR(Lib_NpManager, "(DUMMY) called reqId = {}", reqId);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,9 +986,9 @@ int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetOnlineId() {
|
int PS4_SYSV_ABI sceNpGetOnlineId(s32 userId, OrbisNpOnlineId* onlineId) {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_DEBUG(Lib_NpManager, "called returned sign out");
|
||||||
return ORBIS_OK;
|
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
||||||
|
@ -218,7 +218,7 @@ int PS4_SYSV_ABI sceNpCheckNpReachability();
|
|||||||
int PS4_SYSV_ABI sceNpCheckPlus();
|
int PS4_SYSV_ABI sceNpCheckPlus();
|
||||||
int PS4_SYSV_ABI sceNpCreateAsyncRequest();
|
int PS4_SYSV_ABI sceNpCreateAsyncRequest();
|
||||||
int PS4_SYSV_ABI sceNpCreateRequest();
|
int PS4_SYSV_ABI sceNpCreateRequest();
|
||||||
int PS4_SYSV_ABI sceNpDeleteRequest();
|
int PS4_SYSV_ABI sceNpDeleteRequest(int reqId);
|
||||||
int PS4_SYSV_ABI sceNpGetAccountAge();
|
int PS4_SYSV_ABI sceNpGetAccountAge();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountCountry();
|
int PS4_SYSV_ABI sceNpGetAccountCountry();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
||||||
@ -233,7 +233,7 @@ 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 userId, OrbisNpId* npId);
|
||||||
int PS4_SYSV_ABI sceNpGetNpReachabilityState();
|
int PS4_SYSV_ABI sceNpGetNpReachabilityState();
|
||||||
int PS4_SYSV_ABI sceNpGetOnlineId();
|
int PS4_SYSV_ABI sceNpGetOnlineId(s32 userId, OrbisNpOnlineId* onlineId);
|
||||||
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(s32 userId, OrbisNpState* state);
|
||||||
|
@ -520,7 +520,7 @@ s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
|
|||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy xml : {}", result.description());
|
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy xml : {}", result.description());
|
||||||
return ORBIS_OK;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_trophies = 0;
|
int num_trophies = 0;
|
||||||
|
@ -88,7 +88,7 @@ int PS4_SYSV_ABI scePadGetCapability() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerInformation* pInfo) {
|
int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerInformation* pInfo) {
|
||||||
LOG_INFO(Lib_Pad, "called handle = {}", handle);
|
LOG_DEBUG(Lib_Pad, "called handle = {}", handle);
|
||||||
if (handle < 0) {
|
if (handle < 0) {
|
||||||
pInfo->touchPadInfo.pixelDensity = 1;
|
pInfo->touchPadInfo.pixelDensity = 1;
|
||||||
pInfo->touchPadInfo.resolution.x = 1920;
|
pInfo->touchPadInfo.resolution.x = 1920;
|
||||||
@ -368,12 +368,13 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||||||
pData->angularVelocity.x = 0.0f;
|
pData->angularVelocity.x = 0.0f;
|
||||||
pData->angularVelocity.y = 0.0f;
|
pData->angularVelocity.y = 0.0f;
|
||||||
pData->angularVelocity.z = 0.0f;
|
pData->angularVelocity.z = 0.0f;
|
||||||
pData->touchData.touchNum = 0;
|
pData->touchData.touchNum =
|
||||||
pData->touchData.touch[0].x = 0;
|
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
||||||
pData->touchData.touch[0].y = 0;
|
pData->touchData.touch[0].x = state.touchpad[0].x;
|
||||||
|
pData->touchData.touch[0].y = state.touchpad[0].y;
|
||||||
pData->touchData.touch[0].id = 1;
|
pData->touchData.touch[0].id = 1;
|
||||||
pData->touchData.touch[1].x = 0;
|
pData->touchData.touch[1].x = state.touchpad[1].x;
|
||||||
pData->touchData.touch[1].y = 0;
|
pData->touchData.touch[1].y = state.touchpad[1].y;
|
||||||
pData->touchData.touch[1].id = 2;
|
pData->touchData.touch[1].id = 2;
|
||||||
pData->timestamp = state.time;
|
pData->timestamp = state.time;
|
||||||
pData->connected = true; // isConnected; //TODO fix me proper
|
pData->connected = true; // isConnected; //TODO fix me proper
|
||||||
|
309
src/core/libraries/remote_play/remoteplay.cpp
Normal file
309
src/core/libraries/remote_play/remoteplay.cpp
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "remoteplay.h"
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
namespace Libraries::Remoteplay {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayApprove() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayChangeEnterKey() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayClearAllRegistData() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayClearConnectHistory() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayConfirmDeviceRegist() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayDisconnect() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGeneratePinCode() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetApMode() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetConnectHistory() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetConnectionStatus(s32 userId, int* pStatus) {
|
||||||
|
*pStatus = ORBIS_REMOTEPLAY_CONNECTION_STATUS_DISCONNECT;
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetConnectUserId() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetMbusDeviceInfo() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetOperationStatus() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetRemoteplayStatus() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetRpMode() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeClose() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeFilterResult() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeGetEvent() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeNotify() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeNotifyEventResult() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeOpen() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeSetCaret() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeSetText() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayInitialize() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayIsRemoteOskReady() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayIsRemotePlaying() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyMbusDeviceRegistComplete() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyNpPushWakeup() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyPinCodeError() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyUserDelete() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayPrintAllRegistData() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayProhibit() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayProhibitStreaming() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayServerLock() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayServerUnLock() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetApMode() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetLogLevel() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetProhibition() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetProhibitionForVsh() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetRpMode() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayTerminate() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI Func_1D5EE365ED5FADB3() {
|
||||||
|
LOG_ERROR(Lib_Remoteplay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceRemoteplay(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("xQeIryTX7dY", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayApprove);
|
||||||
|
LIB_FUNCTION("IYZ+Mu+8tPo", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayChangeEnterKey);
|
||||||
|
LIB_FUNCTION("ZYUsJtcAnqA", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayClearAllRegistData);
|
||||||
|
LIB_FUNCTION("cCheyCbF7qw", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayClearConnectHistory);
|
||||||
|
LIB_FUNCTION("tPYT-kGbZh8", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayConfirmDeviceRegist);
|
||||||
|
LIB_FUNCTION("6Lg4BNleJWc", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayDisconnect);
|
||||||
|
LIB_FUNCTION("j98LdSGy4eY", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGeneratePinCode);
|
||||||
|
LIB_FUNCTION("L+cL-M-DP3w", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetApMode);
|
||||||
|
LIB_FUNCTION("g4K51cY+PEw", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetConnectHistory);
|
||||||
|
LIB_FUNCTION("g3PNjYKWqnQ", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetConnectionStatus);
|
||||||
|
LIB_FUNCTION("3eBNV9A0BUM", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetConnectUserId);
|
||||||
|
LIB_FUNCTION("ufesWMVX6iU", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetMbusDeviceInfo);
|
||||||
|
LIB_FUNCTION("DxU4JGh4S2k", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetOperationStatus);
|
||||||
|
LIB_FUNCTION("n5OxFJEvPlc", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetRemoteplayStatus);
|
||||||
|
LIB_FUNCTION("Cekhs6LSHC0", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayGetRpMode);
|
||||||
|
LIB_FUNCTION("ig1ocbR7Ptw", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeClose);
|
||||||
|
LIB_FUNCTION("gV9-8cJPM3I", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeFilterResult);
|
||||||
|
LIB_FUNCTION("cMk57DZXe6c", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeGetEvent);
|
||||||
|
LIB_FUNCTION("-gwkQpOCl68", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeNotify);
|
||||||
|
LIB_FUNCTION("58v9tSlRxc8", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeNotifyEventResult);
|
||||||
|
LIB_FUNCTION("C3r2zT5ebMg", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeOpen);
|
||||||
|
LIB_FUNCTION("oB730zwoz0s", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeSetCaret);
|
||||||
|
LIB_FUNCTION("rOTg1Nljp8w", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayImeSetText);
|
||||||
|
LIB_FUNCTION("k1SwgkMSOM8", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayInitialize);
|
||||||
|
LIB_FUNCTION("R8RZC1ZIkzU", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayIsRemoteOskReady);
|
||||||
|
LIB_FUNCTION("uYhiELUtLgA", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayIsRemotePlaying);
|
||||||
|
LIB_FUNCTION("d-BBSEq1nfc", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayNotifyMbusDeviceRegistComplete);
|
||||||
|
LIB_FUNCTION("Yytq7NE38R8", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayNotifyNpPushWakeup);
|
||||||
|
LIB_FUNCTION("Wg-w8xjMZA4", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayNotifyPinCodeError);
|
||||||
|
LIB_FUNCTION("yheulqylKwI", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayNotifyUserDelete);
|
||||||
|
LIB_FUNCTION("t5ZvUiZ1hpE", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayPrintAllRegistData);
|
||||||
|
LIB_FUNCTION("mrNh78tBpmg", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayProhibit);
|
||||||
|
LIB_FUNCTION("7QLrixwVHcU", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayProhibitStreaming);
|
||||||
|
LIB_FUNCTION("-ThIlThsN80", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayServerLock);
|
||||||
|
LIB_FUNCTION("0Z-Pm5rZJOI", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayServerUnLock);
|
||||||
|
LIB_FUNCTION("xSrhtSLIjOc", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplaySetApMode);
|
||||||
|
LIB_FUNCTION("5-2agAeaE+c", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplaySetLogLevel);
|
||||||
|
LIB_FUNCTION("Rf0XMVR7xPw", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplaySetProhibition);
|
||||||
|
LIB_FUNCTION("n4l3FTZtNQM", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplaySetProhibitionForVsh);
|
||||||
|
LIB_FUNCTION("-BPcEQ1w8xc", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplaySetRpMode);
|
||||||
|
LIB_FUNCTION("BOwybKVa3Do", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
sceRemoteplayTerminate);
|
||||||
|
LIB_FUNCTION("HV7jZe1frbM", "libSceRemoteplay", 1, "libSceRemoteplay", 0, 0,
|
||||||
|
Func_1D5EE365ED5FADB3);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Remoteplay
|
62
src/core/libraries/remote_play/remoteplay.h
Normal file
62
src/core/libraries/remote_play/remoteplay.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returning codes in sceRemoteplayGetConnectionStatus pstatus
|
||||||
|
constexpr int ORBIS_REMOTEPLAY_CONNECTION_STATUS_DISCONNECT = 0;
|
||||||
|
constexpr int ORBIS_REMOTEPLAY_CONNECTION_STATUS_CONNECT = 1;
|
||||||
|
|
||||||
|
namespace Libraries::Remoteplay {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayApprove();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayChangeEnterKey();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayClearAllRegistData();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayClearConnectHistory();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayConfirmDeviceRegist();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayDisconnect();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGeneratePinCode();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetApMode();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetConnectHistory();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetConnectionStatus(s32 userId, int* pStatus);
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetConnectUserId();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetMbusDeviceInfo();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetOperationStatus();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetRemoteplayStatus();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayGetRpMode();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeClose();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeFilterResult();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeGetEvent();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeNotify();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeNotifyEventResult();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeOpen();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeSetCaret();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayImeSetText();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayInitialize();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayIsRemoteOskReady();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayIsRemotePlaying();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyMbusDeviceRegistComplete();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyNpPushWakeup();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyPinCodeError();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayNotifyUserDelete();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayPrintAllRegistData();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayProhibit();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayProhibitStreaming();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayServerLock();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayServerUnLock();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetApMode();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetLogLevel();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetProhibition();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetProhibitionForVsh();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplaySetRpMode();
|
||||||
|
int PS4_SYSV_ABI sceRemoteplayTerminate();
|
||||||
|
int PS4_SYSV_ABI Func_1D5EE365ED5FADB3();
|
||||||
|
|
||||||
|
void RegisterlibSceRemoteplay(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Remoteplay
|
@ -98,7 +98,7 @@ SaveDialogState::SaveDialogState(const OrbisSaveDataDialogParam& param) {
|
|||||||
param_sfo.Open(param_sfo_path);
|
param_sfo.Open(param_sfo_path);
|
||||||
|
|
||||||
auto last_write = param_sfo.GetLastWrite();
|
auto last_write = param_sfo.GetLastWrite();
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32) && !defined(__GNUC__) && !defined(__MINGW32__) && !defined(__MINGW64__)
|
||||||
auto utc_time = std::chrono::file_clock::to_utc(last_write);
|
auto utc_time = std::chrono::file_clock::to_utc(last_write);
|
||||||
#else
|
#else
|
||||||
auto utc_time = std::chrono::file_clock::to_sys(last_write);
|
auto utc_time = std::chrono::file_clock::to_sys(last_write);
|
||||||
@ -402,7 +402,7 @@ void SaveDialogUi::Draw() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
if (first_render || !io.NavActive) {
|
if (first_render || !io.NavActive) {
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "save_instance.h"
|
#include "save_instance.h"
|
||||||
|
|
||||||
constexpr u32 OrbisSaveDataBlocksMax = 32768; // 1 GiB
|
constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
|
||||||
|
constexpr auto OrbisSaveDataBlocksMax = 32768; // 1 GiB
|
||||||
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 max_block_file_name = "max_block.txt";
|
|
||||||
|
|
||||||
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
|
||||||
@ -58,18 +58,13 @@ std::filesystem::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_
|
|||||||
game_serial / dir_name;
|
game_serial / dir_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SaveInstance::GetMaxBlocks(const std::filesystem::path& save_path) {
|
uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
|
||||||
Common::FS::IOFile max_blocks_file{save_path / sce_sys / max_block_file_name,
|
const auto vec = psf.GetBinary(std::string{SaveParams::SAVEDATA_BLOCKS});
|
||||||
Common::FS::FileAccessMode::Read};
|
if (!vec.has_value()) {
|
||||||
int max_blocks = 0;
|
return OrbisSaveDataBlocksMax;
|
||||||
if (max_blocks_file.IsOpen()) {
|
|
||||||
max_blocks = std::atoi(max_blocks_file.ReadString(16).c_str());
|
|
||||||
}
|
}
|
||||||
if (max_blocks <= 0) {
|
auto value = vec.value();
|
||||||
max_blocks = OrbisSaveDataBlocksMax;
|
return *(uint64_t*)value.data();
|
||||||
}
|
|
||||||
|
|
||||||
return max_blocks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
|
std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
|
||||||
@ -92,13 +87,15 @@ void SaveInstance::SetupDefaultParamSFO(PSF& param_sfo, std::string dir_name,
|
|||||||
P(String, SaveParams::SAVEDATA_DIRECTORY, std::move(dir_name));
|
P(String, SaveParams::SAVEDATA_DIRECTORY, std::move(dir_name));
|
||||||
P(Integer, SaveParams::SAVEDATA_LIST_PARAM, 0);
|
P(Integer, SaveParams::SAVEDATA_LIST_PARAM, 0);
|
||||||
P(String, SaveParams::TITLE_ID, std::move(game_serial));
|
P(String, SaveParams::TITLE_ID, std::move(game_serial));
|
||||||
|
P(Binary, SaveParams::SAVEDATA_BLOCKS, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||||
#undef P
|
#undef P
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveInstance::SaveInstance(int slot_num, OrbisUserServiceUserId user_id, std::string _game_serial,
|
SaveInstance::SaveInstance(int slot_num, OrbisUserServiceUserId user_id, std::string _game_serial,
|
||||||
std::string_view _dir_name, int max_blocks)
|
std::string_view _dir_name, int max_blocks)
|
||||||
: slot_num(slot_num), user_id(user_id), game_serial(std::move(_game_serial)),
|
: slot_num(slot_num), user_id(user_id), game_serial(std::move(_game_serial)),
|
||||||
dir_name(_dir_name), max_blocks(max_blocks) {
|
dir_name(_dir_name),
|
||||||
|
max_blocks(std::clamp(max_blocks, OrbisSaveDataBlocksMin2, OrbisSaveDataBlocksMax)) {
|
||||||
ASSERT(slot_num >= 0 && slot_num < 16);
|
ASSERT(slot_num >= 0 && slot_num < 16);
|
||||||
|
|
||||||
save_path = MakeDirSavePath(user_id, game_serial, dir_name);
|
save_path = MakeDirSavePath(user_id, game_serial, dir_name);
|
||||||
@ -187,7 +184,7 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
max_blocks = GetMaxBlocks(save_path);
|
max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
|
||||||
|
|
||||||
g_mnt->Mount(save_path, mount_point, read_only);
|
g_mnt->Mount(save_path, mount_point, read_only);
|
||||||
mounted = true;
|
mounted = true;
|
||||||
@ -217,16 +214,13 @@ void SaveInstance::CreateFiles() {
|
|||||||
fs::create_directories(sce_sys_dir);
|
fs::create_directories(sce_sys_dir);
|
||||||
|
|
||||||
SetupDefaultParamSFO(param_sfo, dir_name, game_serial);
|
SetupDefaultParamSFO(param_sfo, dir_name, game_serial);
|
||||||
|
param_sfo.AddBinary(std::string{SaveParams::SAVEDATA_BLOCKS}, max_blocks, true);
|
||||||
|
|
||||||
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 std::filesystem::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));
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::FS::IOFile max_block{sce_sys_dir / max_block_file_name,
|
|
||||||
Common::FS::FileAccessMode::Write};
|
|
||||||
max_block.WriteString(std::to_string(max_blocks == 0 ? OrbisSaveDataBlocksMax : max_blocks));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::SaveData
|
} // namespace Libraries::SaveData
|
@ -62,7 +62,7 @@ public:
|
|||||||
std::string_view game_serial,
|
std::string_view game_serial,
|
||||||
std::string_view dir_name);
|
std::string_view dir_name);
|
||||||
|
|
||||||
static int GetMaxBlocks(const std::filesystem::path& save_path);
|
static uint64_t GetMaxBlockFromSFO(const PSF& psf);
|
||||||
|
|
||||||
// Get param.sfo path from a dir_path generated by MakeDirSavePath
|
// Get param.sfo path from a dir_path generated by MakeDirSavePath
|
||||||
static std::filesystem::path GetParamSFOPath(const std::filesystem::path& dir_path);
|
static std::filesystem::path GetParamSFOPath(const std::filesystem::path& dir_path);
|
||||||
|
@ -445,7 +445,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
|
|||||||
fs::create_directories(root_save);
|
fs::create_directories(root_save);
|
||||||
const auto available = fs::space(root_save).available;
|
const auto available = fs::space(root_save).available;
|
||||||
|
|
||||||
auto requested_size = mount_info->blocks * OrbisSaveDataBlockSize;
|
auto requested_size = save_instance.GetMaxBlocks() * OrbisSaveDataBlockSize;
|
||||||
if (requested_size > available) {
|
if (requested_size > available) {
|
||||||
mount_result->required_blocks = (requested_size - available) / OrbisSaveDataBlockSize;
|
mount_result->required_blocks = (requested_size - available) / OrbisSaveDataBlockSize;
|
||||||
return Error::NO_SPACE_FS;
|
return Error::NO_SPACE_FS;
|
||||||
@ -830,10 +830,11 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
|
|||||||
LOG_ERROR(Lib_SaveData, "Failed to read SFO: {}", fmt::UTF(sfo_path.u8string()));
|
LOG_ERROR(Lib_SaveData, "Failed to read SFO: {}", fmt::UTF(sfo_path.u8string()));
|
||||||
ASSERT_MSG(false, "Failed to read SFO");
|
ASSERT_MSG(false, "Failed to read SFO");
|
||||||
}
|
}
|
||||||
map_dir_sfo.emplace(dir_name, std::move(sfo));
|
|
||||||
|
|
||||||
size_t size = Common::FS::GetDirectorySize(dir_path);
|
size_t size = Common::FS::GetDirectorySize(dir_path);
|
||||||
size_t total = SaveInstance::GetMaxBlocks(dir_path);
|
size_t total = SaveInstance::GetMaxBlockFromSFO(sfo);
|
||||||
|
|
||||||
|
map_dir_sfo.emplace(dir_name, std::move(sfo));
|
||||||
map_free_size.emplace(dir_name, total - size / OrbisSaveDataBlockSize);
|
map_free_size.emplace(dir_name, total - size / OrbisSaveDataBlockSize);
|
||||||
map_max_blocks.emplace(dir_name, total);
|
map_max_blocks.emplace(dir_name, total);
|
||||||
}
|
}
|
||||||
|
186
src/core/libraries/share_play/shareplay.cpp
Normal file
186
src/core/libraries/share_play/shareplay.cpp
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "shareplay.h"
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
namespace Libraries::SharePlay {
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayCrashDaemon() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetCurrentConnectionInfo(OrbisSharePlayConnectionInfo* pInfo) {
|
||||||
|
memset(pInfo, 0, sizeof(*pInfo));
|
||||||
|
pInfo->status = ORBIS_SHARE_PLAY_CONNECTION_STATUS_DORMANT;
|
||||||
|
LOG_DEBUG(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetCurrentConnectionInfoA() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetCurrentInfo() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetEvent() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayInitialize() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayNotifyDialogOpen() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayNotifyForceCloseForCdlg() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayNotifyOpenQuickMenu() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayResumeScreenForCdlg() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayServerLock() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayServerUnLock() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlaySetMode() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlaySetProhibition() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlaySetProhibitionModeWithAppId() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStartStandby() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStartStreaming() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStopStandby() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStopStreaming() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayTerminate() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI Func_2E93C0EA6A6B67C4() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI Func_C1C236728D88E177() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI Func_E9E80C474781F115() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI Func_F3DD6199DA15ED44() {
|
||||||
|
LOG_ERROR(Lib_SharePlay, "(STUBBED) called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceSharePlay(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("ggnCfalLU-8", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayCrashDaemon);
|
||||||
|
LIB_FUNCTION("OOrLKB0bSDs", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayGetCurrentConnectionInfo);
|
||||||
|
LIB_FUNCTION("+MCXJlWdi+s", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayGetCurrentConnectionInfoA);
|
||||||
|
LIB_FUNCTION("vUMkWXQff3w", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayGetCurrentInfo);
|
||||||
|
LIB_FUNCTION("Md7Mdkr8LBc", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayGetEvent);
|
||||||
|
LIB_FUNCTION("isruqthpYcw", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayInitialize);
|
||||||
|
LIB_FUNCTION("9zwJpai7jGc", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayNotifyDialogOpen);
|
||||||
|
LIB_FUNCTION("VUW2V9cUTP4", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayNotifyForceCloseForCdlg);
|
||||||
|
LIB_FUNCTION("XL0WwUJoQPg", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayNotifyOpenQuickMenu);
|
||||||
|
LIB_FUNCTION("6-1fKaa5HlY", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayResumeScreenForCdlg);
|
||||||
|
LIB_FUNCTION("U28jAuLHj6c", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayServerLock);
|
||||||
|
LIB_FUNCTION("3Oaux9ITEtY", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayServerUnLock);
|
||||||
|
LIB_FUNCTION("QZy+KmyqKPU", "libSceSharePlay", 1, "libSceSharePlay", 0, 0, sceSharePlaySetMode);
|
||||||
|
LIB_FUNCTION("co2NCj--pnc", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlaySetProhibition);
|
||||||
|
LIB_FUNCTION("KADsbjNCgPo", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlaySetProhibitionModeWithAppId);
|
||||||
|
LIB_FUNCTION("-F6NddfUsa4", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayStartStandby);
|
||||||
|
LIB_FUNCTION("rWVNHNnEx6g", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayStartStreaming);
|
||||||
|
LIB_FUNCTION("zEDkUWLVwFI", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayStopStandby);
|
||||||
|
LIB_FUNCTION("aGlema+JxUU", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayStopStreaming);
|
||||||
|
LIB_FUNCTION("UaLjloJinow", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayTerminate);
|
||||||
|
LIB_FUNCTION("LpPA6mprZ8Q", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
Func_2E93C0EA6A6B67C4);
|
||||||
|
LIB_FUNCTION("wcI2co2I4Xc", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
Func_C1C236728D88E177);
|
||||||
|
LIB_FUNCTION("6egMR0eB8RU", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
Func_E9E80C474781F115);
|
||||||
|
LIB_FUNCTION("891hmdoV7UQ", "libSceSharePlay", 1, "libSceSharePlay", 0, 0,
|
||||||
|
Func_F3DD6199DA15ED44);
|
||||||
|
LIB_FUNCTION("OOrLKB0bSDs", "libSceSharePlayCompat", 1, "libSceSharePlay", 0, 0,
|
||||||
|
sceSharePlayGetCurrentConnectionInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::SharePlay
|
54
src/core/libraries/share_play/shareplay.h
Normal file
54
src/core/libraries/share_play/shareplay.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <core/libraries/np_manager/np_manager.h>
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
namespace Core::Loader {
|
||||||
|
class SymbolsResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::SharePlay {
|
||||||
|
|
||||||
|
constexpr int ORBIS_SHARE_PLAY_CONNECTION_STATUS_DORMANT = 0x00;
|
||||||
|
constexpr int ORBIS_SHARE_PLAY_CONNECTION_STATUS_READY = 0x01;
|
||||||
|
constexpr int ORBIS_SHARE_PLAY_CONNECTION_STATUS_CONNECTED = 0x02;
|
||||||
|
|
||||||
|
struct OrbisSharePlayConnectionInfo {
|
||||||
|
int status;
|
||||||
|
int mode;
|
||||||
|
Libraries::NpManager::OrbisNpOnlineId hostOnlineId;
|
||||||
|
Libraries::NpManager::OrbisNpOnlineId visitorOnlineId;
|
||||||
|
s32 hostUserId;
|
||||||
|
s32 visitorUserId;
|
||||||
|
};
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceSharePlayCrashDaemon();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetCurrentConnectionInfo(OrbisSharePlayConnectionInfo* pInfo);
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetCurrentConnectionInfoA();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetCurrentInfo();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayGetEvent();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayInitialize();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayNotifyDialogOpen();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayNotifyForceCloseForCdlg();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayNotifyOpenQuickMenu();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayResumeScreenForCdlg();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayServerLock();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayServerUnLock();
|
||||||
|
int PS4_SYSV_ABI sceSharePlaySetMode();
|
||||||
|
int PS4_SYSV_ABI sceSharePlaySetProhibition();
|
||||||
|
int PS4_SYSV_ABI sceSharePlaySetProhibitionModeWithAppId();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStartStandby();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStartStreaming();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStopStandby();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayStopStreaming();
|
||||||
|
int PS4_SYSV_ABI sceSharePlayTerminate();
|
||||||
|
int PS4_SYSV_ABI Func_2E93C0EA6A6B67C4();
|
||||||
|
int PS4_SYSV_ABI Func_C1C236728D88E177();
|
||||||
|
int PS4_SYSV_ABI Func_E9E80C474781F115();
|
||||||
|
int PS4_SYSV_ABI Func_F3DD6199DA15ED44();
|
||||||
|
|
||||||
|
void RegisterlibSceSharePlay(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::SharePlay
|
@ -256,7 +256,7 @@ void MsgDialogUi::Draw() {
|
|||||||
std::min(io.DisplaySize.y, 300.0f),
|
std::min(io.DisplaySize.y, 300.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
if (first_render || !io.NavActive) {
|
if (first_render || !io.NavActive) {
|
||||||
|
@ -491,7 +491,7 @@ int PS4_SYSV_ABI sceUserServiceGetImeRunCount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceUserServiceGetInitialUser(int* user_id) {
|
s32 PS4_SYSV_ABI sceUserServiceGetInitialUser(int* user_id) {
|
||||||
LOG_INFO(Lib_UserService, "called");
|
LOG_DEBUG(Lib_UserService, "called");
|
||||||
if (user_id == nullptr) {
|
if (user_id == nullptr) {
|
||||||
LOG_ERROR(Lib_UserService, "user_id is null");
|
LOG_ERROR(Lib_UserService, "user_id is null");
|
||||||
return ORBIS_USER_SERVICE_ERROR_INVALID_ARGUMENT;
|
return ORBIS_USER_SERVICE_ERROR_INVALID_ARGUMENT;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/config.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/memory_management.h"
|
#include "core/libraries/kernel/memory_management.h"
|
||||||
@ -39,8 +40,10 @@ MemoryManager::MemoryManager() {
|
|||||||
MemoryManager::~MemoryManager() = default;
|
MemoryManager::~MemoryManager() = default;
|
||||||
|
|
||||||
void MemoryManager::SetupMemoryRegions(u64 flexible_size) {
|
void MemoryManager::SetupMemoryRegions(u64 flexible_size) {
|
||||||
|
const auto total_size =
|
||||||
|
Config::isNeoMode() ? SCE_KERNEL_MAIN_DMEM_SIZE_PRO : SCE_KERNEL_MAIN_DMEM_SIZE;
|
||||||
total_flexible_size = flexible_size;
|
total_flexible_size = flexible_size;
|
||||||
total_direct_size = SCE_KERNEL_MAIN_DMEM_SIZE - flexible_size;
|
total_direct_size = total_size - flexible_size;
|
||||||
|
|
||||||
// Insert an area that covers direct memory physical block.
|
// Insert an area that covers direct memory physical block.
|
||||||
// Note that this should never be called after direct memory allocations have been made.
|
// Note that this should never be called after direct memory allocations have been made.
|
||||||
@ -242,6 +245,7 @@ int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot)
|
|||||||
new_vma.is_exec = false;
|
new_vma.is_exec = false;
|
||||||
new_vma.phys_base = 0;
|
new_vma.phys_base = 0;
|
||||||
|
|
||||||
|
rasterizer->MapMemory(mapped_addr, size);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ enum class MemoryProt : u32 {
|
|||||||
CpuReadWrite = 2,
|
CpuReadWrite = 2,
|
||||||
GpuRead = 16,
|
GpuRead = 16,
|
||||||
GpuWrite = 32,
|
GpuWrite = 32,
|
||||||
GpuReadWrite = 38,
|
GpuReadWrite = 48,
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(MemoryProt)
|
DECLARE_ENUM_FLAG_OPERATORS(MemoryProt)
|
||||||
|
|
||||||
|
108
src/emulator.cpp
108
src/emulator.cpp
@ -8,9 +8,11 @@
|
|||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
|
#include <QtCore>
|
||||||
#include "common/memory_patcher.h"
|
#include "common/memory_patcher.h"
|
||||||
#endif
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/discord_rpc_handler.h"
|
||||||
#include "common/elf_info.h"
|
#include "common/elf_info.h"
|
||||||
#include "common/ntapi.h"
|
#include "common/ntapi.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
@ -24,6 +26,7 @@
|
|||||||
#include "core/file_format/trp.h"
|
#include "core/file_format/trp.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
|
#include "core/libraries/fiber/fiber.h"
|
||||||
#include "core/libraries/kernel/thread_management.h"
|
#include "core/libraries/kernel/thread_management.h"
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
@ -58,6 +61,7 @@ Emulator::Emulator() {
|
|||||||
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
||||||
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
||||||
|
|
||||||
|
LOG_INFO(Config, "General Logtype: {}", Config::getLogType());
|
||||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
||||||
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
||||||
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
||||||
@ -77,6 +81,17 @@ Emulator::Emulator() {
|
|||||||
|
|
||||||
// Load renderdoc module.
|
// Load renderdoc module.
|
||||||
VideoCore::LoadRenderDoc();
|
VideoCore::LoadRenderDoc();
|
||||||
|
|
||||||
|
// Start the timer (Play Time)
|
||||||
|
#ifdef ENABLE_QT_GUI
|
||||||
|
start_time = std::chrono::steady_clock::now();
|
||||||
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||||
|
LOG_INFO(Loader, "Error opening or creating play_time.txt");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Emulator::~Emulator() {
|
Emulator::~Emulator() {
|
||||||
@ -120,6 +135,14 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
MemoryPatcher::g_game_serial = id;
|
MemoryPatcher::g_game_serial = id;
|
||||||
|
|
||||||
|
// Timer for 'Play Time'
|
||||||
|
QTimer* timer = new QTimer();
|
||||||
|
QObject::connect(timer, &QTimer::timeout, [this, id]() {
|
||||||
|
UpdatePlayTime(id);
|
||||||
|
start_time = std::chrono::steady_clock::now();
|
||||||
|
});
|
||||||
|
timer->start(60000); // 60000 ms = 1 minute
|
||||||
#endif
|
#endif
|
||||||
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
||||||
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
||||||
@ -209,6 +232,15 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Discord RPC
|
||||||
|
if (Config::getEnableDiscordRPC()) {
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
if (rpc->getRPCEnabled() == false) {
|
||||||
|
rpc->init();
|
||||||
|
}
|
||||||
|
rpc->setStatusPlaying(game_info.title, id);
|
||||||
|
}
|
||||||
|
|
||||||
// start execution
|
// start execution
|
||||||
std::jthread mainthread =
|
std::jthread mainthread =
|
||||||
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
||||||
@ -217,13 +249,17 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
window->waitEvent();
|
window->waitEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT_GUI
|
||||||
|
UpdatePlayTime(id);
|
||||||
|
#endif
|
||||||
|
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
||||||
constexpr std::array<SysModules, 13> ModulesToLoad{
|
constexpr std::array<SysModules, 13> ModulesToLoad{
|
||||||
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
||||||
{"libSceFiber.sprx", nullptr},
|
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
|
||||||
{"libSceUlt.sprx", nullptr},
|
{"libSceUlt.sprx", nullptr},
|
||||||
{"libSceJson.sprx", nullptr},
|
{"libSceJson.sprx", nullptr},
|
||||||
{"libSceJson2.sprx", nullptr},
|
{"libSceJson2.sprx", nullptr},
|
||||||
@ -258,4 +294,74 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT_GUI
|
||||||
|
void Emulator::UpdatePlayTime(const std::string& serial) {
|
||||||
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||||
|
LOG_INFO(Loader, "Error opening play_time.txt");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end_time = std::chrono::steady_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time);
|
||||||
|
int totalSeconds = duration.count();
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
QStringList lines;
|
||||||
|
QString content;
|
||||||
|
while (!in.atEnd()) {
|
||||||
|
content += in.readLine() + "\n";
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QStringList existingLines = content.split('\n', Qt::SkipEmptyParts);
|
||||||
|
int accumulatedSeconds = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (const QString& line : existingLines) {
|
||||||
|
QStringList parts = line.split(' ');
|
||||||
|
if (parts.size() == 2 && parts[0] == QString::fromStdString(serial)) {
|
||||||
|
QStringList timeParts = parts[1].split(':');
|
||||||
|
if (timeParts.size() == 3) {
|
||||||
|
int hours = timeParts[0].toInt();
|
||||||
|
int minutes = timeParts[1].toInt();
|
||||||
|
int seconds = timeParts[2].toInt();
|
||||||
|
accumulatedSeconds = hours * 3600 + minutes * 60 + seconds;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accumulatedSeconds += totalSeconds;
|
||||||
|
int hours = accumulatedSeconds / 3600;
|
||||||
|
int minutes = (accumulatedSeconds % 3600) / 60;
|
||||||
|
int seconds = accumulatedSeconds % 60;
|
||||||
|
QString playTimeSaved = QString::number(hours) + ":" +
|
||||||
|
QString::number(minutes).rightJustified(2, '0') + ":" +
|
||||||
|
QString::number(seconds).rightJustified(2, '0');
|
||||||
|
|
||||||
|
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
QTextStream out(&file);
|
||||||
|
bool lineUpdated = false;
|
||||||
|
|
||||||
|
for (const QString& line : existingLines) {
|
||||||
|
if (line.startsWith(QString::fromStdString(serial))) {
|
||||||
|
out << QString::fromStdString(serial) + " " + playTimeSaved + "\n";
|
||||||
|
lineUpdated = true;
|
||||||
|
} else {
|
||||||
|
out << line << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lineUpdated) {
|
||||||
|
out << QString::fromStdString(serial) + " " + playTimeSaved + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_INFO(Loader, "Playing time for {}: {}", serial, playTimeSaved.toStdString());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
~Emulator();
|
~Emulator();
|
||||||
|
|
||||||
void Run(const std::filesystem::path& file);
|
void Run(const std::filesystem::path& file);
|
||||||
|
void UpdatePlayTime(const std::string& serial);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadSystemModules(const std::filesystem::path& file);
|
void LoadSystemModules(const std::filesystem::path& file);
|
||||||
@ -34,6 +35,7 @@ private:
|
|||||||
Input::GameController* controller;
|
Input::GameController* controller;
|
||||||
Core::Linker* linker;
|
Core::Linker* linker;
|
||||||
std::unique_ptr<Frontend::WindowSDL> window;
|
std::unique_ptr<Frontend::WindowSDL> window;
|
||||||
|
std::chrono::steady_clock::time_point start_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 965 B |
Binary file not shown.
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 2.2 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user