mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-13 13:15:59 +00:00
Merge branch 'shadps4-emu:main' into shader_cache
This commit is contained in:
commit
c04f04e648
184 changed files with 5985 additions and 1517 deletions
36
.github/workflows/build.yml
vendored
36
.github/workflows/build.yml
vendored
|
@ -76,18 +76,13 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||
with:
|
||||
append-timestamp: false
|
||||
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
|
||||
|
||||
- name: Setup VS Environment
|
||||
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
with:
|
||||
arch: amd64
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
|
@ -111,7 +106,7 @@ jobs:
|
|||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.9.0
|
||||
version: 6.9.1
|
||||
host: windows
|
||||
target: desktop
|
||||
arch: win64_msvc2022_64
|
||||
|
@ -130,18 +125,13 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-cache-cmake-build
|
||||
with:
|
||||
append-timestamp: false
|
||||
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
|
||||
|
||||
- name: Setup VS Environment
|
||||
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
with:
|
||||
arch: amd64
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
|
@ -186,7 +176,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{runner.os}}-sdl-cache-cmake-build
|
||||
with:
|
||||
|
@ -228,7 +218,7 @@ jobs:
|
|||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.9.0
|
||||
version: 6.9.1
|
||||
host: mac
|
||||
target: desktop
|
||||
arch: clang_64
|
||||
|
@ -247,7 +237,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{runner.os}}-qt-cache-cmake-build
|
||||
with:
|
||||
|
@ -301,7 +291,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||
with:
|
||||
|
@ -362,7 +352,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-cache-cmake-build
|
||||
with:
|
||||
|
@ -409,7 +399,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build
|
||||
with:
|
||||
|
@ -445,7 +435,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-build
|
||||
with:
|
||||
|
@ -494,7 +484,7 @@ jobs:
|
|||
with:
|
||||
token: ${{ secrets.SHADPS4_TOKEN_REPO }}
|
||||
name: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
|
||||
tag: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
|
||||
tag: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.fullhash }}"
|
||||
draft: false
|
||||
prerelease: true
|
||||
body: "Full Changelog: [${{ env.last_release_tag }}...${{ needs.get-info.outputs.shorthash }}](https://github.com/shadps4-emu/shadPS4/compare/${{ env.last_release_tag }}...${{ needs.get-info.outputs.fullhash }})"
|
||||
|
@ -530,14 +520,14 @@ jobs:
|
|||
|
||||
# Check if release already exists and get ID
|
||||
release_id=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$REPO/releases/tags/Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}" | jq -r '.id')
|
||||
"https://api.github.com/repos/$REPO/releases/tags/Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.fullhash }}" | jq -r '.id')
|
||||
|
||||
if [[ "$release_id" == "null" ]]; then
|
||||
echo "Creating release in $REPO for $filename"
|
||||
release_id=$(curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-d '{
|
||||
"tag_name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}",
|
||||
"tag_name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.fullhash }}",
|
||||
"name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}",
|
||||
"draft": false,
|
||||
"prerelease": true,
|
||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -30,10 +30,6 @@
|
|||
path = externals/xbyak
|
||||
url = https://github.com/herumi/xbyak.git
|
||||
shallow = true
|
||||
[submodule "externals/winpthreads"]
|
||||
path = externals/winpthreads
|
||||
url = https://github.com/shadps4-emu/winpthreads.git
|
||||
shallow = true
|
||||
[submodule "externals/magic_enum"]
|
||||
path = externals/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
|
|
|
@ -54,9 +54,9 @@ else()
|
|||
endif()
|
||||
|
||||
if (ARCHITECTURE STREQUAL "x86_64")
|
||||
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility.
|
||||
# Exclude SSE4a as it is only available on AMD CPUs.
|
||||
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a)
|
||||
# Target x86-64-v3 CPU architecture as this is a good balance between supporting performance critical
|
||||
# instructions like AVX2 and maintaining support for older CPUs.
|
||||
add_compile_options(-march=x86-64-v3)
|
||||
endif()
|
||||
|
||||
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
|
@ -134,6 +134,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
|||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
message("got remote: ${GIT_REMOTE_NAME}")
|
||||
endif()
|
||||
|
||||
# If running in GitHub Actions and the above fails
|
||||
|
@ -177,7 +178,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
|||
set(GIT_BRANCH "${GITHUB_BRANCH}")
|
||||
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
|
||||
set(GIT_BRANCH "${GITHUB_REF}")
|
||||
else()
|
||||
elseif("${GIT_BRANCH}" STREQUAL "")
|
||||
message("couldn't find branch")
|
||||
set(GIT_BRANCH "detached-head")
|
||||
endif()
|
||||
|
@ -186,8 +187,8 @@ else()
|
|||
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
|
||||
if (INDEX GREATER -1)
|
||||
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
|
||||
else()
|
||||
# If no remote is present (only a branch name), default to origin
|
||||
elseif("${GIT_REMOTE_NAME}" STREQUAL "")
|
||||
message("reset to origin")
|
||||
set(GIT_REMOTE_NAME "origin")
|
||||
endif()
|
||||
endif()
|
||||
|
@ -202,7 +203,7 @@ execute_process(
|
|||
|
||||
# Set Version
|
||||
set(EMULATOR_VERSION_MAJOR "0")
|
||||
set(EMULATOR_VERSION_MINOR "8")
|
||||
set(EMULATOR_VERSION_MINOR "9")
|
||||
set(EMULATOR_VERSION_PATCH "1")
|
||||
|
||||
set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}")
|
||||
|
@ -226,7 +227,7 @@ find_package(SDL3 3.1.2 CONFIG)
|
|||
find_package(stb MODULE)
|
||||
find_package(toml11 4.2.0 CONFIG)
|
||||
find_package(tsl-robin-map 1.3.0 CONFIG)
|
||||
find_package(VulkanHeaders 1.4.309 CONFIG)
|
||||
find_package(VulkanHeaders 1.4.314 CONFIG)
|
||||
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
|
||||
find_package(xbyak 7.07 CONFIG)
|
||||
find_package(xxHash 0.8.2 MODULE)
|
||||
|
@ -239,13 +240,6 @@ if (APPLE)
|
|||
endif()
|
||||
list(POP_BACK CMAKE_MODULE_PATH)
|
||||
|
||||
# Note: Windows always has these functions through winpthreads
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
|
||||
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32)
|
||||
add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
|
||||
include(CheckCXXSymbolExists)
|
||||
|
@ -302,6 +296,8 @@ set(AJM_LIB src/core/libraries/ajm/ajm.cpp
|
|||
|
||||
set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
|
||||
src/core/libraries/audio/audioin.h
|
||||
src/core/libraries/voice/voice.cpp
|
||||
src/core/libraries/voice/voice.h
|
||||
src/core/libraries/audio/audioout.cpp
|
||||
src/core/libraries/audio/audioout.h
|
||||
src/core/libraries/audio/audioout_backend.h
|
||||
|
@ -416,6 +412,7 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
|||
src/core/libraries/save_data/save_memory.h
|
||||
src/core/libraries/save_data/savedata.cpp
|
||||
src/core/libraries/save_data/savedata.h
|
||||
src/core/libraries/save_data/savedata_error.h
|
||||
src/core/libraries/save_data/dialog/savedatadialog.cpp
|
||||
src/core/libraries/save_data/dialog/savedatadialog.h
|
||||
src/core/libraries/save_data/dialog/savedatadialog_ui.cpp
|
||||
|
@ -601,6 +598,17 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
|||
src/core/libraries/signin_dialog/signindialog.h
|
||||
)
|
||||
|
||||
set(CAMERA_LIBS src/core/libraries/camera/camera.cpp
|
||||
src/core/libraries/camera/camera.h
|
||||
src/core/libraries/camera/camera_error.h
|
||||
)
|
||||
|
||||
set(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp
|
||||
src/core/libraries/companion/companion_httpd.h
|
||||
src/core/libraries/companion/companion_util.cpp
|
||||
src/core/libraries/companion/companion_util.h
|
||||
src/core/libraries/companion/companion_error.h
|
||||
)
|
||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||
src/core/devtools/layer.h
|
||||
src/core/devtools/options.cpp
|
||||
|
@ -618,6 +626,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
|
|||
src/core/devtools/widget/imgui_memory_editor.h
|
||||
src/core/devtools/widget/memory_map.cpp
|
||||
src/core/devtools/widget/memory_map.h
|
||||
src/core/devtools/widget/module_list.cpp
|
||||
src/core/devtools/widget/module_list.h
|
||||
src/core/devtools/widget/reg_popup.cpp
|
||||
src/core/devtools/widget/reg_popup.h
|
||||
src/core/devtools/widget/reg_view.cpp
|
||||
|
@ -671,6 +681,8 @@ set(COMMON src/common/logging/backend.cpp
|
|||
src/common/polyfill_thread.h
|
||||
src/common/rdtsc.cpp
|
||||
src/common/rdtsc.h
|
||||
src/common/recursive_lock.cpp
|
||||
src/common/recursive_lock.h
|
||||
src/common/sha1.h
|
||||
src/common/signal_context.h
|
||||
src/common/signal_context.cpp
|
||||
|
@ -765,6 +777,8 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
${FIBER_LIB}
|
||||
${VDEC_LIB}
|
||||
${VR_LIBS}
|
||||
${CAMERA_LIBS}
|
||||
${COMPANION_LIBS}
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
|
@ -859,6 +873,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||
src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp
|
||||
src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp
|
||||
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
|
||||
src/shader_recompiler/ir/abstract_syntax_list.cpp
|
||||
src/shader_recompiler/ir/abstract_syntax_list.h
|
||||
src/shader_recompiler/ir/attribute.cpp
|
||||
src/shader_recompiler/ir/attribute.h
|
||||
|
@ -1091,9 +1106,13 @@ if (ENABLE_DISCORD_RPC)
|
|||
target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
|
||||
endif()
|
||||
|
||||
# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD)
|
||||
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
|
||||
if (ENABLE_USERFAULTFD)
|
||||
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
|
||||
endif()
|
||||
|
||||
target_link_libraries(shadps4 PRIVATE uuid)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
|
@ -1149,7 +1168,7 @@ if (ENABLE_QT_GUI)
|
|||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(shadps4 PRIVATE mincore winpthreads)
|
||||
target_link_libraries(shadps4 PRIVATE mincore)
|
||||
|
||||
if (MSVC)
|
||||
# MSVC likes putting opinions on what people can use, disable:
|
||||
|
|
5
dist/net.shadps4.shadPS4.metainfo.xml
vendored
5
dist/net.shadps4.shadPS4.metainfo.xml
vendored
|
@ -37,7 +37,10 @@
|
|||
<category translate="no">Game</category>
|
||||
</categories>
|
||||
<releases>
|
||||
<release version="0.8.0" date="2025-05-23">
|
||||
<release version="0.9.0" date="2025-05-22">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.9.0</url>
|
||||
</release>
|
||||
<release version="0.8.0" date="2025-04-23">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url>
|
||||
</release>
|
||||
<release version="0.7.0" date="2025-03-23">
|
||||
|
|
|
@ -21,9 +21,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
||||
- A processor with at least 4 cores and 6 threads
|
||||
- Above 2.5 GHz frequency
|
||||
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
|
||||
- A CPU supporting the x86-64-v3 baseline.
|
||||
- **Intel**: Haswell generation or newer
|
||||
- **AMD**: Jaguar generation or newer
|
||||
- **AMD**: Excavator generation or newer
|
||||
- **Apple**: Rosetta 2 on macOS 15.4 or newer
|
||||
|
||||
### GPU
|
||||
|
@ -55,4 +55,4 @@ To configure the emulator, you can go through the interface and go to "settings"
|
|||
|
||||
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.\
|
||||
For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
|
||||
For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
|
||||
|
|
|
@ -29,7 +29,7 @@ sudo dnf install clang git cmake libatomic alsa-lib-devel \
|
|||
openssl-devel libevdev-devel libudev-devel libXext-devel \
|
||||
qt6-qtbase-devel qt6-qtbase-private-devel \
|
||||
qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel \
|
||||
vulkan-devel vulkan-validation-layers libpng-devel
|
||||
vulkan-devel vulkan-validation-layers libpng-devel libuuid-devel
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
|
|
6
externals/CMakeLists.txt
vendored
6
externals/CMakeLists.txt
vendored
|
@ -137,12 +137,6 @@ if (NOT TARGET Zydis::Zydis)
|
|||
add_subdirectory(zydis)
|
||||
endif()
|
||||
|
||||
# Winpthreads
|
||||
if (WIN32)
|
||||
add_subdirectory(winpthreads)
|
||||
target_include_directories(winpthreads INTERFACE winpthreads/include)
|
||||
endif()
|
||||
|
||||
# sirit
|
||||
add_subdirectory(sirit)
|
||||
if (WIN32)
|
||||
|
|
2
externals/MoltenVK/MoltenVK
vendored
2
externals/MoltenVK/MoltenVK
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946
|
||||
Subproject commit 3a0b07a24a4a681ffe70b461b1f4333b2729e2ef
|
2
externals/MoltenVK/SPIRV-Cross
vendored
2
externals/MoltenVK/SPIRV-Cross
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1
|
||||
Subproject commit 969e75f7cc0718774231d029f9d52fa87d4ae1b2
|
2
externals/sirit
vendored
2
externals/sirit
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 09a1416ab1b59ddfebd2618412f118f2004f3b2c
|
||||
Subproject commit 6b450704f6fedb9413d0c89a9eb59d028eb1e6c0
|
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d
|
||||
Subproject commit 9c77de5c3dd216f28e407eec65ed9c0a296c1f74
|
1
externals/winpthreads
vendored
1
externals/winpthreads
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f
|
|
@ -69,7 +69,7 @@ static bool vkGuestMarkers = false;
|
|||
static bool rdocEnable = false;
|
||||
static bool isFpsColor = true;
|
||||
static bool isSeparateLogFilesEnabled = false;
|
||||
static s16 cursorState = HideCursorState::Idle;
|
||||
static int cursorState = HideCursorState::Idle;
|
||||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
static double trophyNotificationDuration = 6.0;
|
||||
static bool useUnifiedInputConfig = true;
|
||||
|
@ -78,6 +78,7 @@ static int controllerCustomColorRGB[3] = {0, 0, 255};
|
|||
static bool compatibilityData = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
static std::string trophyKey;
|
||||
static bool isPSNSignedIn = false;
|
||||
|
||||
// Gui
|
||||
static bool load_game_size = true;
|
||||
|
@ -154,7 +155,7 @@ bool GetLoadGameSizeEnabled() {
|
|||
|
||||
std::filesystem::path GetSaveDataPath() {
|
||||
if (save_data_path.empty()) {
|
||||
return Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir);
|
||||
return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "savedata";
|
||||
}
|
||||
return save_data_path;
|
||||
}
|
||||
|
@ -730,6 +731,14 @@ void setShowBackgroundImage(bool show) {
|
|||
showBackgroundImage = show;
|
||||
}
|
||||
|
||||
bool getPSNSignedIn() {
|
||||
return isPSNSignedIn;
|
||||
}
|
||||
|
||||
void setPSNSignedIn(bool sign) {
|
||||
isPSNSignedIn = sign;
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path& path) {
|
||||
// If the configuration file does not exist, create it and return
|
||||
std::error_code error;
|
||||
|
@ -754,6 +763,7 @@ void load(const std::filesystem::path& path) {
|
|||
|
||||
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
||||
isDevKit = toml::find_or<bool>(general, "isDevKit", false);
|
||||
isPSNSignedIn = toml::find_or<bool>(general, "isPSNSignedIn", false);
|
||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
|
||||
trophyNotificationDuration =
|
||||
|
@ -953,6 +963,7 @@ void save(const std::filesystem::path& path) {
|
|||
|
||||
data["General"]["isPS4Pro"] = isNeo;
|
||||
data["General"]["isDevKit"] = isDevKit;
|
||||
data["General"]["isPSNSignedIn"] = isPSNSignedIn;
|
||||
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
|
||||
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
|
||||
data["General"]["playBGM"] = playBGM;
|
||||
|
@ -1098,6 +1109,7 @@ void setDefaultValues() {
|
|||
isHDRAllowed = false;
|
||||
isNeo = false;
|
||||
isDevKit = false;
|
||||
isPSNSignedIn = false;
|
||||
isFullscreen = false;
|
||||
isTrophyPopupDisabled = false;
|
||||
playBGM = false;
|
||||
|
|
|
@ -14,7 +14,7 @@ struct GameInstallDir {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
enum HideCursorState : s16 { Never, Idle, Always };
|
||||
enum HideCursorState : int { Never, Idle, Always };
|
||||
|
||||
void load(const std::filesystem::path& path);
|
||||
void save(const std::filesystem::path& path);
|
||||
|
@ -39,6 +39,7 @@ bool getCompatibilityEnabled();
|
|||
bool getCheckCompatibilityOnStartup();
|
||||
int getBackgroundImageOpacity();
|
||||
bool getShowBackgroundImage();
|
||||
bool getPSNSignedIn();
|
||||
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
|
@ -111,6 +112,7 @@ void setCompatibilityEnabled(bool use);
|
|||
void setCheckCompatibilityOnStartup(bool use);
|
||||
void setBackgroundImageOpacity(int opacity);
|
||||
void setShowBackgroundImage(bool show);
|
||||
void setPSNSignedIn(bool sign);
|
||||
|
||||
void setCursorState(s16 cursorState);
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
|
|
|
@ -71,6 +71,7 @@ class ElfInfo {
|
|||
PSFAttributes psf_attributes{};
|
||||
|
||||
std::filesystem::path splash_path{};
|
||||
std::filesystem::path game_folder{};
|
||||
|
||||
public:
|
||||
static constexpr u32 FW_15 = 0x1500000;
|
||||
|
@ -123,6 +124,10 @@ public:
|
|||
[[nodiscard]] const std::filesystem::path& GetSplashPath() const {
|
||||
return splash_path;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::filesystem::path& GetGameFolder() const {
|
||||
return game_folder;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -138,6 +138,10 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Lib, Zlib) \
|
||||
SUB(Lib, Hmd) \
|
||||
SUB(Lib, SigninDialog) \
|
||||
SUB(Lib, Camera) \
|
||||
SUB(Lib, CompanionHttpd) \
|
||||
SUB(Lib, CompanionUtil) \
|
||||
SUB(Lib, Voice) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
|
|
@ -98,6 +98,7 @@ enum class Class : u8 {
|
|||
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
|
||||
Lib_Videodec, ///< The LibSceVideodec implementation.
|
||||
Lib_Voice, ///< The LibSceVoice implementation.
|
||||
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
||||
Lib_Mouse, ///< The LibSceMouse implementation
|
||||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
|
@ -105,6 +106,9 @@ enum class Class : u8 {
|
|||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Lib_Hmd, ///< The LibSceHmd implementation.
|
||||
Lib_SigninDialog, ///< The LibSigninDialog implementation.
|
||||
Lib_Camera, ///< The LibCamera implementation.
|
||||
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
|
||||
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Video Core
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
|
|
|
@ -128,7 +128,6 @@ static auto UserPaths = [] {
|
|||
create_path(PathType::LogDir, user_dir / LOG_DIR);
|
||||
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
|
||||
create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
|
||||
create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
|
||||
create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
|
||||
create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
|
||||
create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR);
|
||||
|
|
|
@ -18,7 +18,6 @@ enum class PathType {
|
|||
LogDir, // Where log files are stored.
|
||||
ScreenshotsDir, // Where screenshots are stored.
|
||||
ShaderDir, // Where shaders are stored.
|
||||
SaveDataDir, // Where guest save data is stored.
|
||||
TempDataDir, // Where game temp data is stored.
|
||||
GameDataDir, // Where game data is stored.
|
||||
SysModuleDir, // Where system modules are stored.
|
||||
|
@ -36,7 +35,6 @@ constexpr auto PORTABLE_DIR = "user";
|
|||
constexpr auto LOG_DIR = "log";
|
||||
constexpr auto SCREENSHOTS_DIR = "screenshots";
|
||||
constexpr auto SHADER_DIR = "shader";
|
||||
constexpr auto SAVEDATA_DIR = "savedata";
|
||||
constexpr auto GAMEDATA_DIR = "data";
|
||||
constexpr auto TEMPDATA_DIR = "temp";
|
||||
constexpr auto SYSMODULES_DIR = "sys_modules";
|
||||
|
|
37
src/common/recursive_lock.cpp
Normal file
37
src/common/recursive_lock.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <unordered_map>
|
||||
#include "common/assert.h"
|
||||
#include "common/recursive_lock.h"
|
||||
|
||||
namespace Common::Detail {
|
||||
|
||||
struct RecursiveLockState {
|
||||
RecursiveLockType type;
|
||||
int count;
|
||||
};
|
||||
|
||||
thread_local std::unordered_map<void*, RecursiveLockState> g_recursive_locks;
|
||||
|
||||
bool IncrementRecursiveLock(void* mutex, RecursiveLockType type) {
|
||||
auto& state = g_recursive_locks[mutex];
|
||||
if (state.count == 0) {
|
||||
ASSERT(state.type == RecursiveLockType::None);
|
||||
state.type = type;
|
||||
}
|
||||
ASSERT(state.type == type);
|
||||
return state.count++ == 0;
|
||||
}
|
||||
|
||||
bool DecrementRecursiveLock(void* mutex, RecursiveLockType type) {
|
||||
auto& state = g_recursive_locks[mutex];
|
||||
ASSERT(state.type == type && state.count > 0);
|
||||
if (--state.count == 0) {
|
||||
g_recursive_locks.erase(mutex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Common::Detail
|
67
src/common/recursive_lock.h
Normal file
67
src/common/recursive_lock.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace Common {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
enum class RecursiveLockType { None, Shared, Exclusive };
|
||||
|
||||
bool IncrementRecursiveLock(void* mutex, RecursiveLockType type);
|
||||
bool DecrementRecursiveLock(void* mutex, RecursiveLockType type);
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
template <typename MutexType>
|
||||
class RecursiveScopedLock {
|
||||
public:
|
||||
explicit RecursiveScopedLock(MutexType& mutex) : m_mutex(mutex), m_locked(false) {
|
||||
if (Detail::IncrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Exclusive)) {
|
||||
m_locked = true;
|
||||
m_lock.emplace(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
~RecursiveScopedLock() {
|
||||
Detail::DecrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Exclusive);
|
||||
if (m_locked) {
|
||||
m_lock.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MutexType& m_mutex;
|
||||
std::optional<std::unique_lock<MutexType>> m_lock;
|
||||
bool m_locked = false;
|
||||
};
|
||||
|
||||
template <typename MutexType>
|
||||
class RecursiveSharedLock {
|
||||
public:
|
||||
explicit RecursiveSharedLock(MutexType& mutex) : m_mutex(mutex), m_locked(false) {
|
||||
if (Detail::IncrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Shared)) {
|
||||
m_locked = true;
|
||||
m_lock.emplace(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
~RecursiveSharedLock() {
|
||||
Detail::DecrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Shared);
|
||||
if (m_locked) {
|
||||
m_lock.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MutexType& m_mutex;
|
||||
std::optional<std::shared_lock<MutexType>> m_lock;
|
||||
bool m_locked = false;
|
||||
};
|
||||
|
||||
} // namespace Common
|
|
@ -1,6 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/scm_rev.h"
|
||||
|
||||
namespace Common {
|
||||
|
@ -15,5 +17,26 @@ constexpr char g_scm_remote_name[] = "@GIT_REMOTE_NAME@";
|
|||
constexpr char g_scm_remote_url[] = "@GIT_REMOTE_URL@";
|
||||
constexpr char g_scm_date[] = "@BUILD_DATE@";
|
||||
|
||||
const std::string GetRemoteNameFromLink() {
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host;
|
||||
try {
|
||||
if (remote_url.starts_with("http")) {
|
||||
if (*remote_url.rbegin() == '/') {
|
||||
remote_url.pop_back();
|
||||
}
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} else if (remote_url.starts_with("git@")) {
|
||||
auto after_comma_pos = remote_url.find(':') + 1, slash_pos = remote_url.find('/');
|
||||
remote_host = remote_url.substr(after_comma_pos, slash_pos - after_comma_pos);
|
||||
} else {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
return remote_host;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Common {
|
||||
|
||||
extern const char g_version[];
|
||||
|
@ -15,4 +17,6 @@ extern const char g_scm_remote_name[];
|
|||
extern const char g_scm_remote_url[];
|
||||
extern const char g_scm_date[];
|
||||
|
||||
const std::string GetRemoteNameFromLink();
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -14,6 +14,9 @@ namespace Common {
|
|||
struct SlotId {
|
||||
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
|
||||
|
||||
SlotId() noexcept = default;
|
||||
constexpr SlotId(u32 index) noexcept : index(index) {}
|
||||
|
||||
constexpr auto operator<=>(const SlotId&) const noexcept = default;
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
|
@ -28,6 +31,63 @@ class SlotVector {
|
|||
constexpr static std::size_t InitialCapacity = 2048;
|
||||
|
||||
public:
|
||||
template <typename ValueType, typename Pointer, typename Reference>
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = ValueType;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = Pointer;
|
||||
using reference = Reference;
|
||||
|
||||
Iterator(SlotVector& vector_, SlotId index_) : vector(vector_), slot(index_) {
|
||||
AdvanceToValid();
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
return vector[slot];
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
return &vector[slot];
|
||||
}
|
||||
|
||||
Iterator& operator++() {
|
||||
++slot.index;
|
||||
AdvanceToValid();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) {
|
||||
Iterator temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& other) const {
|
||||
return slot == other.slot;
|
||||
}
|
||||
|
||||
bool operator!=(const Iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
void AdvanceToValid() {
|
||||
while (slot < vector.values_capacity && !vector.ReadStorageBit(slot.index)) {
|
||||
++slot.index;
|
||||
}
|
||||
}
|
||||
|
||||
SlotVector& vector;
|
||||
SlotId slot;
|
||||
};
|
||||
|
||||
using iterator = Iterator<T, T*, T&>;
|
||||
using const_iterator = Iterator<const T, const T*, const T&>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
SlotVector() {
|
||||
Reserve(InitialCapacity);
|
||||
}
|
||||
|
@ -60,7 +120,7 @@ public:
|
|||
}
|
||||
|
||||
template <typename... Args>
|
||||
[[nodiscard]] SlotId insert(Args&&... args) noexcept {
|
||||
SlotId insert(Args&&... args) noexcept {
|
||||
const u32 index = FreeValueIndex();
|
||||
new (&values[index].object) T(std::forward<Args>(args)...);
|
||||
SetStorageBit(index);
|
||||
|
@ -78,6 +138,54 @@ public:
|
|||
return values_capacity - free_list.size();
|
||||
}
|
||||
|
||||
iterator begin() noexcept {
|
||||
return iterator(*this, 0);
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept {
|
||||
return const_iterator(*this, 0);
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept {
|
||||
return begin();
|
||||
}
|
||||
|
||||
iterator end() noexcept {
|
||||
return iterator(*this, values_capacity);
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept {
|
||||
return const_iterator(*this, values_capacity);
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept {
|
||||
return end();
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() noexcept {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin() const noexcept {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
reverse_iterator rend() noexcept {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const noexcept {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
const_reverse_iterator crend() const noexcept {
|
||||
return rend();
|
||||
}
|
||||
|
||||
private:
|
||||
struct NonTrivialDummy {
|
||||
NonTrivialDummy() noexcept {}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
|
@ -104,14 +105,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
|||
SetThreadPriority(handle, windows_priority);
|
||||
}
|
||||
|
||||
static void AccurateSleep(std::chrono::nanoseconds duration) {
|
||||
bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
|
||||
const bool interruptible) {
|
||||
const auto begin_sleep = std::chrono::high_resolution_clock::now();
|
||||
|
||||
LARGE_INTEGER interval{
|
||||
.QuadPart = -1 * (duration.count() / 100u),
|
||||
};
|
||||
HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL);
|
||||
SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
const auto ret = WaitForSingleObjectEx(timer, INFINITE, interruptible);
|
||||
::CloseHandle(timer);
|
||||
|
||||
if (remaining) {
|
||||
const auto end_sleep = std::chrono::high_resolution_clock::now();
|
||||
const auto sleep_time = end_sleep - begin_sleep;
|
||||
*remaining = duration > sleep_time ? duration - sleep_time : std::chrono::nanoseconds(0);
|
||||
}
|
||||
return ret == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -134,8 +145,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
|||
pthread_setschedparam(this_thread, scheduling_type, ¶ms);
|
||||
}
|
||||
|
||||
static void AccurateSleep(std::chrono::nanoseconds duration) {
|
||||
std::this_thread::sleep_for(duration);
|
||||
bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
|
||||
const bool interruptible) {
|
||||
timespec request = {
|
||||
.tv_sec = duration.count() / 1'000'000'000,
|
||||
.tv_nsec = duration.count() % 1'000'000'000,
|
||||
};
|
||||
timespec remain;
|
||||
int ret;
|
||||
while ((ret = nanosleep(&request, &remain)) < 0 && errno == EINTR) {
|
||||
if (interruptible) {
|
||||
break;
|
||||
}
|
||||
request = remain;
|
||||
}
|
||||
if (remaining) {
|
||||
*remaining = std::chrono::nanoseconds(remain.tv_sec * 1'000'000'000 + remain.tv_nsec);
|
||||
}
|
||||
return ret == 0 || errno != EINTR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -196,9 +223,9 @@ AccurateTimer::AccurateTimer(std::chrono::nanoseconds target_interval)
|
|||
: target_interval(target_interval) {}
|
||||
|
||||
void AccurateTimer::Start() {
|
||||
auto begin_sleep = std::chrono::high_resolution_clock::now();
|
||||
const auto begin_sleep = std::chrono::high_resolution_clock::now();
|
||||
if (total_wait.count() > 0) {
|
||||
AccurateSleep(total_wait);
|
||||
AccurateSleep(total_wait, nullptr, false);
|
||||
}
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
total_wait -= std::chrono::duration_cast<std::chrono::nanoseconds>(start_time - begin_sleep);
|
||||
|
|
|
@ -25,6 +25,9 @@ void SetCurrentThreadName(const char* name);
|
|||
|
||||
void SetThreadName(void* thread, const char* name);
|
||||
|
||||
bool AccurateSleep(std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
|
||||
bool interruptible);
|
||||
|
||||
class AccurateTimer {
|
||||
std::chrono::nanoseconds target_interval{};
|
||||
std::chrono::nanoseconds total_wait{};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#define VA_ARGS \
|
||||
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
|
||||
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
|
||||
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
|
||||
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7
|
||||
|
||||
#define VA_CTX(ctx) \
|
||||
alignas(16)::Common::VaCtx ctx{}; \
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "widget/frame_dump.h"
|
||||
#include "widget/frame_graph.h"
|
||||
#include "widget/memory_map.h"
|
||||
#include "widget/module_list.h"
|
||||
#include "widget/shader_list.h"
|
||||
|
||||
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
||||
|
@ -40,6 +41,7 @@ static bool just_opened_options = false;
|
|||
|
||||
static Widget::MemoryMapViewer memory_map;
|
||||
static Widget::ShaderList shader_list;
|
||||
static Widget::ModuleList module_list;
|
||||
|
||||
// clang-format off
|
||||
static std::string help_text =
|
||||
|
@ -108,6 +110,9 @@ void L::DrawMenuBar() {
|
|||
if (MenuItem("Memory map")) {
|
||||
memory_map.open = true;
|
||||
}
|
||||
if (MenuItem("Module list")) {
|
||||
module_list.open = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
@ -256,6 +261,9 @@ void L::DrawAdvanced() {
|
|||
if (shader_list.open) {
|
||||
shader_list.Draw();
|
||||
}
|
||||
if (module_list.open) {
|
||||
module_list.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
void L::DrawSimple() {
|
||||
|
|
55
src/core/devtools/widget/module_list.cpp
Normal file
55
src/core/devtools/widget/module_list.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "module_list.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
void ModuleList::Draw() {
|
||||
SetNextWindowSize({550.0f, 600.0f}, ImGuiCond_FirstUseEver);
|
||||
if (!Begin("Module List", &open)) {
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (BeginTable("ModuleTable", 3,
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable |
|
||||
ImGuiTableFlags_RowBg)) {
|
||||
TableSetupColumn("Modulname", ImGuiTableColumnFlags_WidthStretch);
|
||||
TableHeadersRow();
|
||||
|
||||
std::scoped_lock lock(modules_mutex);
|
||||
for (const auto& module : modules) {
|
||||
TableNextRow();
|
||||
|
||||
TableSetColumnIndex(0);
|
||||
TextUnformatted(module.name.c_str());
|
||||
|
||||
TableSetColumnIndex(1);
|
||||
if (module.is_sys_module) {
|
||||
TextColored({0.2f, 0.6f, 0.8f, 1.0f}, "System Module");
|
||||
} else {
|
||||
TextColored({0.8f, 0.4f, 0.2f, 1.0f}, "Game Module");
|
||||
}
|
||||
|
||||
TableSetColumnIndex(2);
|
||||
if (module.is_lle) {
|
||||
TextColored({0.4f, 0.7f, 0.4f, 1.0f}, "LLE");
|
||||
} else {
|
||||
TextColored({0.7f, 0.4f, 0.5f, 1.0f}, "HLE");
|
||||
}
|
||||
}
|
||||
EndTable();
|
||||
}
|
||||
|
||||
End();
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
82
src/core/devtools/widget/module_list.h
Normal file
82
src/core/devtools/widget/module_list.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/elf_info.h"
|
||||
#include "common/path_util.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
class ModuleList {
|
||||
public:
|
||||
ModuleList() = default;
|
||||
~ModuleList() = default;
|
||||
|
||||
void Draw();
|
||||
bool open = false;
|
||||
|
||||
static bool IsSystemModule(const std::filesystem::path& path) {
|
||||
const auto sys_modules_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
|
||||
|
||||
const auto abs_path = std::filesystem::absolute(path).lexically_normal();
|
||||
const auto abs_sys_path = std::filesystem::absolute(sys_modules_path).lexically_normal();
|
||||
|
||||
const auto path_str = abs_path.string();
|
||||
const auto sys_path_str = abs_sys_path.string();
|
||||
|
||||
return path_str.starts_with(sys_path_str);
|
||||
}
|
||||
|
||||
static bool IsSystemModule(const std::string& name) {
|
||||
const auto game_modules_path = Common::ElfInfo::Instance().GetGameFolder() / "sce_module";
|
||||
const auto prx_path = game_modules_path / name;
|
||||
|
||||
if (!std::filesystem::exists(prx_path)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AddModule(const std::string& name, std::filesystem::path path) {
|
||||
if (name == "eboot.bin") {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock(modules_mutex);
|
||||
modules.push_back({name, IsSystemModule(path), true});
|
||||
}
|
||||
|
||||
static void AddModule(std::string name) {
|
||||
name = name + ".prx";
|
||||
std::scoped_lock lock(modules_mutex);
|
||||
|
||||
bool is_sys_module = IsSystemModule(name);
|
||||
bool is_lle = false;
|
||||
auto it = std::find_if(modules.begin(), modules.end(),
|
||||
[&name, is_sys_module, is_lle](const ModuleInfo& entry) {
|
||||
return entry.name == name && !entry.is_lle;
|
||||
});
|
||||
|
||||
if (it == modules.end()) {
|
||||
modules.push_back({name, is_sys_module, is_lle});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct ModuleInfo {
|
||||
std::string name;
|
||||
bool is_sys_module;
|
||||
bool is_lle;
|
||||
};
|
||||
|
||||
static inline std::mutex modules_mutex;
|
||||
|
||||
static inline std::vector<ModuleInfo> modules;
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
517
src/core/libraries/camera/camera.cpp
Normal file
517
src/core/libraries/camera/camera.cpp
Normal file
|
@ -0,0 +1,517 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/camera/camera.h"
|
||||
#include "core/libraries/camera/camera_error.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::Camera {
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAccGetData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioClose() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData2() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioOpen() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioReset() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraChangeAppModuleState() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraClose(s32 handle) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraCloseByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraDeviceOpen() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* pAttribute) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibrationData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* pConfig) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* pContrast,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32* pEnable, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfig() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceID() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* pDeviceInfo) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetFrameData(int handle, OrbisCameraFrameData* pFrameData) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* pHue, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetProductInfo() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegister() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegistryInfo() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* pSaturation,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* pSharpness,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraIsConfigChangeDone() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraIsValidFrameData(int handle, OrbisCameraFrameData* pFrameData) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
|
||||
s32 index, OrbisCameraOpenParameter* pParam) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraOpenByModuleId() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* pAttribute) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttributeInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetCalibData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* pConfig) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfigInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetDebugStop() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32 enable, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetForceActivate() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocus() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetRegister() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetTrackerMode() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetUacModeInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* pVideoSync) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* pParam) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStartByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStop(s32 handle) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStopByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceCamera(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("QhjrPkRPUZQ", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAccGetData);
|
||||
LIB_FUNCTION("UFonL7xopFM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioClose);
|
||||
LIB_FUNCTION("fkZE7Hup2ro", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioGetData);
|
||||
LIB_FUNCTION("hftC5A1C8OQ", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioGetData2);
|
||||
LIB_FUNCTION("DhqqFiBU+6g", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioOpen);
|
||||
LIB_FUNCTION("wyU98EXAYxU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioReset);
|
||||
LIB_FUNCTION("Y0pCDajzkVQ", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraChangeAppModuleState);
|
||||
LIB_FUNCTION("OMS9LlcrvBo", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraClose);
|
||||
LIB_FUNCTION("ztqH5qNTpTk", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraCloseByHandle);
|
||||
LIB_FUNCTION("nBH6i2s4Glc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraDeviceOpen);
|
||||
LIB_FUNCTION("0btIPD5hg5A", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetAttribute);
|
||||
LIB_FUNCTION("oEi6vM-3E2c", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetAutoExposureGain);
|
||||
LIB_FUNCTION("qTPRMh4eY60", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetAutoWhiteBalance);
|
||||
LIB_FUNCTION("hHA1frlMxYE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetCalibData);
|
||||
LIB_FUNCTION("5Oie5RArfWs", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetCalibDataFromDevice);
|
||||
LIB_FUNCTION("RHYJ7GKOSMg", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetCalibrationData);
|
||||
LIB_FUNCTION("ZaqmGEtYuL0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetConfig);
|
||||
LIB_FUNCTION("a5xFueMZIMs", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetContrast);
|
||||
LIB_FUNCTION("tslCukqFE+E", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetDefectivePixelCancellation);
|
||||
LIB_FUNCTION("DSOLCrc3Kh8", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceConfig);
|
||||
LIB_FUNCTION("n+rFeP1XXyM", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetDeviceConfigWithoutHandle);
|
||||
LIB_FUNCTION("jTJCdyv9GLU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceID);
|
||||
LIB_FUNCTION("-H3UwGQvNZI", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetDeviceIDWithoutOpen);
|
||||
LIB_FUNCTION("WZpxnSAM-ds", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceInfo);
|
||||
LIB_FUNCTION("ObIste7hqdk", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetExposureGain);
|
||||
LIB_FUNCTION("mxgMmR+1Kr0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetFrameData);
|
||||
LIB_FUNCTION("WVox2rwGuSc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetGamma);
|
||||
LIB_FUNCTION("zrIUDKZx0iE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetHue);
|
||||
LIB_FUNCTION("XqYRHc4aw3w", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetLensCorrection);
|
||||
LIB_FUNCTION("B260o9pSzM8", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetMmapConnectedCount);
|
||||
LIB_FUNCTION("ULxbwqiYYuU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetProductInfo);
|
||||
LIB_FUNCTION("olojYZKYiYs", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetRegister);
|
||||
LIB_FUNCTION("hawKak+Auw4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetRegistryInfo);
|
||||
LIB_FUNCTION("RTDOsWWqdME", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetSaturation);
|
||||
LIB_FUNCTION("c6Fp9M1EXXc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetSharpness);
|
||||
LIB_FUNCTION("IAz2HgZQWzE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetVrCaptureInfo);
|
||||
LIB_FUNCTION("HX5524E5tMY", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetWhiteBalance);
|
||||
LIB_FUNCTION("0wnf2a60FqI", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraInitializeRegistryCalibData);
|
||||
LIB_FUNCTION("p6n3Npi3YY4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraIsAttached);
|
||||
LIB_FUNCTION("wQfd7kfRZvo", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraIsConfigChangeDone);
|
||||
LIB_FUNCTION("U3BVwQl2R5Q", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraIsValidFrameData);
|
||||
LIB_FUNCTION("BHn83xrF92E", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraOpen);
|
||||
LIB_FUNCTION("eTywOSWsEiI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraOpenByModuleId);
|
||||
LIB_FUNCTION("py8p6kZcHmA", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraRemoveAppModuleFocus);
|
||||
LIB_FUNCTION("j5isFVIlZLk", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAppModuleFocus);
|
||||
LIB_FUNCTION("doPlf33ab-U", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetAttribute);
|
||||
LIB_FUNCTION("96F7zp1Xo+k", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAttributeInternal);
|
||||
LIB_FUNCTION("yfSdswDaElo", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAutoExposureGain);
|
||||
LIB_FUNCTION("zIKL4kZleuc", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAutoWhiteBalance);
|
||||
LIB_FUNCTION("LEMk5cTHKEA", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetCalibData);
|
||||
LIB_FUNCTION("VQ+5kAqsE2Q", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetConfig);
|
||||
LIB_FUNCTION("9+SNhbctk64", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetConfigInternal);
|
||||
LIB_FUNCTION("3i5MEzrC1pg", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetContrast);
|
||||
LIB_FUNCTION("vejouEusC7g", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetDebugStop);
|
||||
LIB_FUNCTION("jMv40y2A23g", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetDefectivePixelCancellation);
|
||||
LIB_FUNCTION("vER3cIMBHqI", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetDefectivePixelCancellationInternal);
|
||||
LIB_FUNCTION("wgBMXJJA6K4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetExposureGain);
|
||||
LIB_FUNCTION("jeTpU0MqKU0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetForceActivate);
|
||||
LIB_FUNCTION("lhEIsHzB8r4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetGamma);
|
||||
LIB_FUNCTION("QI8GVJUy2ZY", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetHue);
|
||||
LIB_FUNCTION("K7W7H4ZRwbc", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetLensCorrection);
|
||||
LIB_FUNCTION("eHa3vhGu2rQ", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetLensCorrectionInternal);
|
||||
LIB_FUNCTION("lS0tM6n+Q5E", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetProcessFocus);
|
||||
LIB_FUNCTION("NVITuK83Z7o", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetProcessFocusByHandle);
|
||||
LIB_FUNCTION("8MjO05qk5hA", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetRegister);
|
||||
LIB_FUNCTION("bSKEi2PzzXI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetSaturation);
|
||||
LIB_FUNCTION("P-7MVfzvpsM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetSharpness);
|
||||
LIB_FUNCTION("3VJOpzKoIeM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetTrackerMode);
|
||||
LIB_FUNCTION("nnR7KAIDPv8", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetUacModeInternal);
|
||||
LIB_FUNCTION("wpeyFwJ+UEI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetVideoSync);
|
||||
LIB_FUNCTION("8WtmqmE4edw", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetVideoSyncInternal);
|
||||
LIB_FUNCTION("k3zPIcgFNv0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetWhiteBalance);
|
||||
LIB_FUNCTION("9EpRYMy7rHU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStart);
|
||||
LIB_FUNCTION("cLxF1QtHch0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStartByHandle);
|
||||
LIB_FUNCTION("2G2C0nmd++M", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStop);
|
||||
LIB_FUNCTION("+X1Kgnn3bzg", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStopByHandle);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Camera
|
308
src/core/libraries/camera/camera.h
Normal file
308
src/core/libraries/camera/camera.h
Normal file
|
@ -0,0 +1,308 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/libraries/system/userservice.h>
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::Camera {
|
||||
|
||||
constexpr int ORBIS_CAMERA_MAX_DEVICE_NUM = 2;
|
||||
constexpr int ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM = 4;
|
||||
|
||||
enum OrbisCameraChannel {
|
||||
ORBIS_CAMERA_CHANNEL_0 = 1,
|
||||
ORBIS_CAMERA_CHANNEL_1 = 2,
|
||||
ORBIS_CAMERA_CHANNEL_BOTH = 3,
|
||||
};
|
||||
|
||||
struct OrbisCameraOpenParameter {
|
||||
u32 sizeThis;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
};
|
||||
|
||||
enum OrbisCameraConfigType {
|
||||
ORBIS_CAMERA_CONFIG_TYPE1 = 0x01,
|
||||
ORBIS_CAMERA_CONFIG_TYPE2 = 0x02,
|
||||
ORBIS_CAMERA_CONFIG_TYPE3 = 0x03,
|
||||
ORBIS_CAMERA_CONFIG_TYPE4 = 0x04,
|
||||
ORBIS_CAMERA_CONFIG_TYPE5 = 0x05,
|
||||
ORBIS_CAMERA_CONFIG_EXTENTION = 0x10,
|
||||
};
|
||||
|
||||
enum OrbisCameraResolution {
|
||||
ORBIS_CAMERA_RESOLUTION_1280X800 = 0x0,
|
||||
ORBIS_CAMERA_RESOLUTION_640X400 = 0x1,
|
||||
ORBIS_CAMERA_RESOLUTION_320X200 = 0x2,
|
||||
ORBIS_CAMERA_RESOLUTION_160X100 = 0x3,
|
||||
ORBIS_CAMERA_RESOLUTION_320X192 = 0x4,
|
||||
ORBIS_CAMERA_RESOLUTION_SPECIFIED_WIDTH_HEIGHT,
|
||||
ORBIS_CAMERA_RESOLUTION_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
enum OrbisCameraFramerate {
|
||||
ORBIS_CAMERA_FRAMERATE_UNKNOWN = 0,
|
||||
ORBIS_CAMERA_FRAMERATE_7_5 = 7,
|
||||
ORBIS_CAMERA_FRAMERATE_15 = 15,
|
||||
ORBIS_CAMERA_FRAMERATE_30 = 30,
|
||||
ORBIS_CAMERA_FRAMERATE_60 = 60,
|
||||
ORBIS_CAMERA_FRAMERATE_120 = 120,
|
||||
ORBIS_CAMERA_FRAMERATE_240 = 240,
|
||||
};
|
||||
|
||||
enum OrbisCameraBaseFormat {
|
||||
ORBIS_CAMERA_FORMAT_YUV422 = 0x0,
|
||||
ORBIS_CAMERA_FORMAT_RAW16,
|
||||
ORBIS_CAMERA_FORMAT_RAW8,
|
||||
ORBIS_CAMERA_FORMAT_NO_USE = 0x10,
|
||||
ORBIS_CAMERA_FORMAT_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
enum OrbisCameraScaleFormat {
|
||||
ORBIS_CAMERA_SCALE_FORMAT_YUV422 = 0x0,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_Y16 = 0x3,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_Y8,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_NO_USE = 0x10,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
struct OrbisCameraFormat {
|
||||
OrbisCameraBaseFormat formatLevel0;
|
||||
OrbisCameraScaleFormat formatLevel1;
|
||||
OrbisCameraScaleFormat formatLevel2;
|
||||
OrbisCameraScaleFormat formatLevel3;
|
||||
};
|
||||
|
||||
struct OrbisCameraConfigExtention {
|
||||
OrbisCameraFormat format;
|
||||
OrbisCameraResolution resolution;
|
||||
OrbisCameraFramerate framerate;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 reserved1;
|
||||
void* pBaseOption;
|
||||
};
|
||||
|
||||
struct OrbisCameraConfig {
|
||||
u32 sizeThis;
|
||||
OrbisCameraConfigType configType;
|
||||
OrbisCameraConfigExtention configExtention[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
};
|
||||
|
||||
enum OrbisCameraAecAgcTarget {
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF = 0x00,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_2_0 = 0x20,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_6 = 0x16,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_4 = 0x14,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_2 = 0x12,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_0 = 0x10,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_8 = 0x08,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_6 = 0x06,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_4 = 0x04,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_2 = 0x02,
|
||||
};
|
||||
|
||||
struct OrbisCameraDeviceInfo {
|
||||
u32 sizeThis;
|
||||
u32 infoRevision;
|
||||
u32 deviceRevision;
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
struct OrbisCameraStartParameter {
|
||||
u32 sizeThis;
|
||||
u32 formatLevel[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
void* pStartOption;
|
||||
};
|
||||
|
||||
struct OrbisCameraVideoSyncParameter {
|
||||
u32 sizeThis;
|
||||
u32 videoSyncMode;
|
||||
void* pModeOption;
|
||||
};
|
||||
|
||||
struct OrbisCameraFramePosition {
|
||||
u32 x;
|
||||
u32 y;
|
||||
u32 xSize;
|
||||
u32 ySize;
|
||||
};
|
||||
|
||||
struct OrbisCameraAutoExposureGainTarget {
|
||||
u32 sizeThis;
|
||||
OrbisCameraAecAgcTarget target;
|
||||
};
|
||||
|
||||
struct OrbisCameraExposureGain {
|
||||
u32 exposureControl;
|
||||
u32 exposure;
|
||||
u32 gain;
|
||||
u32 mode;
|
||||
};
|
||||
|
||||
struct OrbisCameraWhiteBalance {
|
||||
u32 whiteBalanceControl;
|
||||
u32 gainRed;
|
||||
u32 gainBlue;
|
||||
u32 gainGreen;
|
||||
};
|
||||
|
||||
struct OrbisCameraGamma {
|
||||
u32 gammaControl;
|
||||
u32 value;
|
||||
u8 reserved[16];
|
||||
};
|
||||
|
||||
struct OrbisCameraMeta {
|
||||
u32 metaMode;
|
||||
u32 format[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
u64 frame[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
u64 timestamp[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
u32 deviceTimestamp[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraExposureGain exposureGain[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraWhiteBalance whiteBalance[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraGamma gamma[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
u32 luminance[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
float acceleration_x;
|
||||
float acceleration_y;
|
||||
float acceleration_z;
|
||||
u64 vcounter;
|
||||
u32 reserved[14];
|
||||
};
|
||||
|
||||
struct OrbisCameraFrameData {
|
||||
u32 sizeThis;
|
||||
u32 readMode;
|
||||
OrbisCameraFramePosition framePosition[ORBIS_CAMERA_MAX_DEVICE_NUM]
|
||||
[ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
void* pFramePointerList[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
u32 frameSize[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
u32 status[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraMeta meta;
|
||||
void* pFramePointerListGarlic[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
};
|
||||
|
||||
struct OrbisCameraAttribute {
|
||||
u32 sizeThis;
|
||||
OrbisCameraChannel channel;
|
||||
OrbisCameraFramePosition framePosition;
|
||||
OrbisCameraExposureGain exposureGain;
|
||||
OrbisCameraWhiteBalance whiteBalance;
|
||||
OrbisCameraGamma gamma;
|
||||
u32 saturation;
|
||||
u32 contrast;
|
||||
u32 sharpness;
|
||||
s32 hue;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
u32 reserved4;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAccGetData();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioClose();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData2();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioOpen();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioReset();
|
||||
s32 PS4_SYSV_ABI sceCameraChangeAppModuleState();
|
||||
s32 PS4_SYSV_ABI sceCameraClose(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceCameraCloseByHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraDeviceOpen();
|
||||
s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* pAttribute);
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibData();
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice();
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibrationData();
|
||||
s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* pConfig);
|
||||
s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* pContrast,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32* pEnable, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfig();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceID();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* pDeviceInfo);
|
||||
s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetFrameData(int handle, OrbisCameraFrameData* pFrameData);
|
||||
s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* pHue, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount();
|
||||
s32 PS4_SYSV_ABI sceCameraGetProductInfo();
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegister();
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegistryInfo();
|
||||
s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* pSaturation,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* pSharpness,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo();
|
||||
s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData();
|
||||
s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index);
|
||||
s32 PS4_SYSV_ABI sceCameraIsConfigChangeDone();
|
||||
s32 PS4_SYSV_ABI sceCameraIsValidFrameData(int handle, OrbisCameraFrameData* pFrameData);
|
||||
s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
|
||||
s32 index, OrbisCameraOpenParameter* pParam);
|
||||
s32 PS4_SYSV_ABI sceCameraOpenByModuleId();
|
||||
s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus();
|
||||
s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus();
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* pAttribute);
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttributeInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetCalibData();
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* pConfig);
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfigInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetDebugStop();
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32 enable, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetForceActivate();
|
||||
s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocus();
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraSetRegister();
|
||||
s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetTrackerMode();
|
||||
s32 PS4_SYSV_ABI sceCameraSetUacModeInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* pVideoSync);
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* pParam);
|
||||
s32 PS4_SYSV_ABI sceCameraStartByHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraStop(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceCameraStopByHandle();
|
||||
|
||||
void RegisterlibSceCamera(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Camera
|
29
src/core/libraries/camera/camera_error.h
Normal file
29
src/core/libraries/camera/camera_error.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
constexpr int ORBIS_CAMERA_ERROR_PARAM = 0x802E0000;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_INIT = 0x802E0001;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_INIT = 0x802E0002;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_OPEN = 0x802E0003;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_OPEN = 0x802E0004;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_START = 0x802E0005;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_START = 0x802E0006;
|
||||
constexpr int ORBIS_CAMERA_ERROR_FORMAT_UNKNOWN = 0x802E0007;
|
||||
constexpr int ORBIS_CAMERA_ERROR_RESOLUTION_UNKNOWN = 0x802E0008;
|
||||
constexpr int ORBIS_CAMERA_ERROR_BAD_FRAMERATE = 0x802E0009;
|
||||
constexpr int ORBIS_CAMERA_ERROR_TIMEOUT = 0x802E000A;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ATTRIBUTE_UNKNOWN = 0x802E000B;
|
||||
constexpr int ORBIS_CAMERA_ERROR_BUSY = 0x802E000C;
|
||||
constexpr int ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG = 0x802E000D;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_READ = 0x802E000F;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_CONNECTED = 0x802E0010;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_SUPPORTED = 0x802E0011;
|
||||
constexpr int ORBIS_CAMERA_ERROR_INVALID_CONFIG = 0x802E0013;
|
||||
constexpr int ORBIS_CAMERA_ERROR_MAX_HANDLE = 0x802E0014;
|
||||
constexpr int ORBIS_CAMERA_ERROR_MAX_PROCESS = 0x802E00FB;
|
||||
constexpr int ORBIS_CAMERA_ERROR_COPYOUT_FAILED = 0x802E00FC;
|
||||
constexpr int ORBIS_CAMERA_ERROR_COPYIN_FAILED = 0x802E00FD;
|
||||
constexpr int ORBIS_CAMERA_ERROR_KPROC_CREATE = 0x802E00FE;
|
||||
constexpr int ORBIS_CAMERA_ERROR_FATAL = 0x802E00FF;
|
27
src/core/libraries/companion/companion_error.h
Normal file
27
src/core/libraries/companion/companion_error.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
// companion_httpd error codes
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_UNKNOWN = 0x80E40001;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_FATAL = 0x80E40002;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOMEM = 0x80E40003;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_INVALID_PARAM = 0x80E40004;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_INVALID_OPERATION = 0x80E40005;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_INITIALIZED = 0x80E40006;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_INITIALIZED = 0x80E40007;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NO_EVENT = 0x80E40008;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_GENERATE_RESPONSE = 0x80E40009;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_STARTED = 0x80E4000A;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_STARTED = 0x80E4000B;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_REGISTERED = 0x80E4000;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_CONNECTED = 0x80E4000D;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_ERROR_USER_NOT_FOUND = 0x80E4000E;
|
||||
|
||||
// companion_util error codes
|
||||
constexpr u32 ORBIS_COMPANION_UTIL_INVALID_ARGUMENT = 0x80AD0004;
|
||||
constexpr u32 ORBIS_COMPANION_UTIL_INVALID_POINTER = 0x80AD0006;
|
||||
constexpr u32 ORBIS_COMPANION_UTIL_NO_EVENT = 0x80AD0008;
|
142
src/core/libraries/companion/companion_httpd.cpp
Normal file
142
src/core/libraries/companion/companion_httpd.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "companion_error.h"
|
||||
#include "core/libraries/companion/companion_httpd.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::CompanionHttpd {
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdAddHeader(const char* key, const char* value,
|
||||
OrbisCompanionHttpdResponse* response) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceCompanionHttpdGet2ndScreenStatus(Libraries::UserService::OrbisUserServiceUserId) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdGetEvent(OrbisCompanionHttpdEvent* pEvent) {
|
||||
pEvent->event = ORBIS_COMPANION_HTTPD_EVENT_DISCONNECT; // disconnected
|
||||
LOG_DEBUG(Lib_CompanionHttpd, "device disconnected");
|
||||
return ORBIS_COMPANION_HTTPD_ERROR_NO_EVENT; // No events to obtain
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceCompanionHttpdGetUserId(u32 addr, Libraries::UserService::OrbisUserServiceUserId* userId) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize2() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdOptParamInitialize() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestBodyReceptionCallback(
|
||||
OrbisCompanionHttpdRequestBodyReceptionCallback function, void* param) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceCompanionHttpdRegisterRequestCallback(OrbisCompanionHttpdRequestCallback function, void* param) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestCallback2(
|
||||
OrbisCompanionHttpdRequestCallback function, void* param) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdSetBody(const char* body, u64 bodySize,
|
||||
OrbisCompanionHttpdResponse* response) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdSetStatus(s32 status, OrbisCompanionHttpdResponse* response) {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdStart() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdStop() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdTerminate() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestBodyReceptionCallback() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestCallback() {
|
||||
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceCompanionHttpd(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("8pWltDG7h6A", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdAddHeader);
|
||||
LIB_FUNCTION("B-QBMeFdNgY", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdGet2ndScreenStatus);
|
||||
LIB_FUNCTION("Vku4big+IYM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdGetEvent);
|
||||
LIB_FUNCTION("0SySxcuVNG0", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdGetUserId);
|
||||
LIB_FUNCTION("ykNpWs3ktLY", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdInitialize);
|
||||
LIB_FUNCTION("OA6FbORefbo", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdInitialize2);
|
||||
LIB_FUNCTION("r-2-a0c7Kfc", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdOptParamInitialize);
|
||||
LIB_FUNCTION("fHNmij7kAUM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdRegisterRequestBodyReceptionCallback);
|
||||
LIB_FUNCTION("OaWw+IVEdbI", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdRegisterRequestCallback);
|
||||
LIB_FUNCTION("-0c9TCTwnGs", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdRegisterRequestCallback2);
|
||||
LIB_FUNCTION("h3OvVxzX4qM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdSetBody);
|
||||
LIB_FUNCTION("w7oz0AWHpT4", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdSetStatus);
|
||||
LIB_FUNCTION("k7F0FcDM-Xc", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdStart);
|
||||
LIB_FUNCTION("0SCgzfVQHpo", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdStop);
|
||||
LIB_FUNCTION("+-du9tWgE9s", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdTerminate);
|
||||
LIB_FUNCTION("ZSHiUfYK+QI", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdUnregisterRequestBodyReceptionCallback);
|
||||
LIB_FUNCTION("xweOi2QT-BE", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
|
||||
sceCompanionHttpdUnregisterRequestCallback);
|
||||
};
|
||||
|
||||
} // namespace Libraries::CompanionHttpd
|
91
src/core/libraries/companion/companion_httpd.h
Normal file
91
src/core/libraries/companion/companion_httpd.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "core/libraries/system/userservice.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::CompanionHttpd {
|
||||
|
||||
// OrbisCompanionHttpdEvent event codes
|
||||
constexpr int ORBIS_COMPANION_HTTPD_EVENT_CONNECT = 0x10000001;
|
||||
constexpr int ORBIS_COMPANION_HTTPD_EVENT_DISCONNECT = 0x10000002;
|
||||
|
||||
struct OrbisCompanionHttpdHeader {
|
||||
char* key;
|
||||
char* value;
|
||||
struct OrbisCompanionHttpdHeader* header;
|
||||
};
|
||||
|
||||
struct OrbisCompanionHttpdRequest {
|
||||
s32 method;
|
||||
char* url;
|
||||
OrbisCompanionHttpdHeader* header;
|
||||
char* body;
|
||||
u64 bodySize;
|
||||
};
|
||||
|
||||
struct OrbisCompanionHttpdResponse {
|
||||
s32 status;
|
||||
OrbisCompanionHttpdHeader* header;
|
||||
char* body;
|
||||
u64 bodySize;
|
||||
};
|
||||
|
||||
using OrbisCompanionHttpdRequestBodyReceptionCallback =
|
||||
PS4_SYSV_ABI s32 (*)(s32 event, Libraries::UserService::OrbisUserServiceUserId userId,
|
||||
const OrbisCompanionHttpdRequest* httpRequest, void* param);
|
||||
|
||||
using OrbisCompanionHttpdRequestCallback =
|
||||
PS4_SYSV_ABI s32 (*)(Libraries::UserService::OrbisUserServiceUserId userId,
|
||||
const OrbisCompanionHttpdRequest* httpRequest,
|
||||
OrbisCompanionHttpdResponse* httpResponse, void* param);
|
||||
|
||||
struct OrbisCompanionUtilDeviceInfo {
|
||||
Libraries::UserService::OrbisUserServiceUserId userId;
|
||||
Libraries::Net::OrbisNetSockaddrIn addr;
|
||||
char reserved[236];
|
||||
};
|
||||
|
||||
struct OrbisCompanionHttpdEvent {
|
||||
s32 event;
|
||||
union {
|
||||
OrbisCompanionUtilDeviceInfo deviceInfo;
|
||||
Libraries::UserService::OrbisUserServiceUserId userId;
|
||||
char reserved[256];
|
||||
} data;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdAddHeader(const char* key, const char* value,
|
||||
OrbisCompanionHttpdResponse* response);
|
||||
s32 PS4_SYSV_ABI
|
||||
sceCompanionHttpdGet2ndScreenStatus(Libraries::UserService::OrbisUserServiceUserId userId);
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdGetEvent(OrbisCompanionHttpdEvent* pEvent);
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdGetUserId(u32 addr,
|
||||
Libraries::UserService::OrbisUserServiceUserId* userId);
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize2();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdOptParamInitialize();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestBodyReceptionCallback(
|
||||
OrbisCompanionHttpdRequestBodyReceptionCallback function, void* param);
|
||||
s32 PS4_SYSV_ABI
|
||||
sceCompanionHttpdRegisterRequestCallback(OrbisCompanionHttpdRequestCallback function, void* param);
|
||||
s32 PS4_SYSV_ABI
|
||||
sceCompanionHttpdRegisterRequestCallback2(OrbisCompanionHttpdRequestCallback function, void* param);
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdSetBody(const char* body, u64 bodySize,
|
||||
OrbisCompanionHttpdResponse* response);
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdSetStatus(s32 status, OrbisCompanionHttpdResponse* response);
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdStart();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdStop();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdTerminate();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestBodyReceptionCallback();
|
||||
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestCallback();
|
||||
|
||||
void RegisterlibSceCompanionHttpd(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::CompanionHttpd
|
72
src/core/libraries/companion/companion_util.cpp
Normal file
72
src/core/libraries/companion/companion_util.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "companion_error.h"
|
||||
#include "core/libraries/companion/companion_util.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::CompanionUtil {
|
||||
|
||||
u32 PS4_SYSV_ABI getEvent(sceCompanionUtilContext* ctx, sceCompanionUtilEvent* outEvent,
|
||||
s32 param_3) {
|
||||
if (outEvent == 0) {
|
||||
return ORBIS_COMPANION_UTIL_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (ctx == nullptr) {
|
||||
return ORBIS_COMPANION_UTIL_INVALID_POINTER;
|
||||
}
|
||||
|
||||
uint8_t* base = ctx->blob;
|
||||
int flag = *reinterpret_cast<int*>(base + 0x178);
|
||||
if (flag == 0) {
|
||||
return ORBIS_COMPANION_UTIL_NO_EVENT;
|
||||
}
|
||||
|
||||
return ORBIS_COMPANION_UTIL_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilGetEvent(sceCompanionUtilEvent* outEvent) {
|
||||
sceCompanionUtilContext* ctx = nullptr;
|
||||
u32 ret = getEvent(ctx, outEvent, 1);
|
||||
|
||||
LOG_DEBUG(Lib_CompanionUtil, "(STUBBED) called ret: {}", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilGetRemoteOskEvent() {
|
||||
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilInitialize() {
|
||||
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilOptParamInitialize() {
|
||||
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilTerminate() {
|
||||
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceCompanionUtil(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("cE5Msy11WhU", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
|
||||
sceCompanionUtilGetEvent);
|
||||
LIB_FUNCTION("MaVrz79mT5o", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
|
||||
sceCompanionUtilGetRemoteOskEvent);
|
||||
LIB_FUNCTION("xb1xlIhf0QY", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
|
||||
sceCompanionUtilInitialize);
|
||||
LIB_FUNCTION("IPN-FRSrafk", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
|
||||
sceCompanionUtilOptParamInitialize);
|
||||
LIB_FUNCTION("H1fYQd5lFAI", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
|
||||
sceCompanionUtilTerminate);
|
||||
};
|
||||
|
||||
} // namespace Libraries::CompanionUtil
|
33
src/core/libraries/companion/companion_util.h
Normal file
33
src/core/libraries/companion/companion_util.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::CompanionUtil {
|
||||
|
||||
constexpr u32 ORBIS_COMPANION_UTIL_OK = 0;
|
||||
|
||||
struct sceCompanionUtilEvent {
|
||||
std::uint8_t blob[0x104]{}; /// 0x104 bytes of data, dont know what it is exactly
|
||||
};
|
||||
|
||||
struct sceCompanionUtilContext {
|
||||
std::uint8_t blob[0x27B]{}; /// 0x27B bytes of data, dont know what it is exactly
|
||||
};
|
||||
|
||||
u32 PS4_SYSV_ABI getEvent(sceCompanionUtilContext* ctx, sceCompanionUtilEvent* outEvent,
|
||||
s32 param_3);
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilGetEvent(sceCompanionUtilEvent* outEvent);
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilGetRemoteOskEvent();
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilInitialize();
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilOptParamInitialize();
|
||||
s32 PS4_SYSV_ABI sceCompanionUtilTerminate();
|
||||
|
||||
void RegisterlibSceCompanionUtil(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::CompanionUtil
|
|
@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t add
|
|||
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
|
||||
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
|
||||
wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u);
|
||||
wait_reg_mem->poll_addr_lo = u32(addr & addr_mask);
|
||||
wait_reg_mem->poll_addr_lo_raw = u32(addr & addr_mask);
|
||||
wait_reg_mem->poll_addr_hi = u32(addr >> 32u);
|
||||
wait_reg_mem->ref = ref;
|
||||
wait_reg_mem->mask = mask;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Libraries::Kernel {
|
|||
static s32* id_state;
|
||||
static s32 id_index;
|
||||
|
||||
s32 sceKernelAioInitializeImpl(void* p, s32 size) {
|
||||
s32 PS4_SYSV_ABI sceKernelAioInitializeImpl(void* p, s32 size) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,12 +12,25 @@
|
|||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
extern boost::asio::io_context io_context;
|
||||
extern void KernelSignalRequest();
|
||||
|
||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
||||
|
||||
// Events are uniquely identified by id and filter.
|
||||
|
||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
event.time_added = std::chrono::steady_clock::now();
|
||||
if (event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer) {
|
||||
// HrTimer events are offset by the threshold of time at the end that we spinlock for
|
||||
// greater accuracy.
|
||||
const auto offset =
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer ? HrTimerSpinlockThresholdUs : 0u;
|
||||
event.timer_interval = std::chrono::microseconds(event.event.data - offset);
|
||||
}
|
||||
|
||||
const auto& it = std::ranges::find(m_events, event);
|
||||
if (it != m_events.cend()) {
|
||||
|
@ -29,6 +42,47 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
|
||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&)) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
if (it == m_events.cend()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& event = *it;
|
||||
ASSERT(event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer);
|
||||
|
||||
if (!it->timer) {
|
||||
it->timer = std::make_unique<boost::asio::steady_timer>(io_context, event.timer_interval);
|
||||
} else {
|
||||
// If the timer already exists we are scheduling a reoccurrence after the next period.
|
||||
// Set the expiration time to the previous occurrence plus the period.
|
||||
it->timer->expires_at(it->timer->expiry() + event.timer_interval);
|
||||
}
|
||||
|
||||
it->timer->async_wait(
|
||||
[this, event_data = event.event, callback](const boost::system::error_code& ec) {
|
||||
if (ec) {
|
||||
if (ec != boost::system::errc::operation_canceled) {
|
||||
LOG_ERROR(Kernel_Event, "Timer callback error: {}", ec.message());
|
||||
} else {
|
||||
// Timer was cancelled (removed) before it triggered
|
||||
LOG_DEBUG(Kernel_Event, "Timer cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
callback(this, event_data);
|
||||
});
|
||||
KernelSignalRequest();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
|
||||
bool has_found = false;
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
@ -44,6 +98,11 @@ bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
|
|||
}
|
||||
|
||||
int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
|
||||
if (HasSmallTimer()) {
|
||||
// If a small timer is set, just wait for it to expire.
|
||||
return WaitForSmallTimer(ev, num, micros);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
const auto predicate = [&] {
|
||||
|
@ -86,6 +145,8 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||
if (event.event.ident == ident && event.event.filter == filter) {
|
||||
if (filter == SceKernelEvent::Filter::VideoOut) {
|
||||
event.TriggerDisplay(trigger_data);
|
||||
} else if (filter == SceKernelEvent::Filter::User) {
|
||||
event.TriggerUser(trigger_data);
|
||||
} else {
|
||||
event.Trigger(trigger_data);
|
||||
}
|
||||
|
@ -133,7 +194,8 @@ int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
|
|||
ASSERT(num == 1);
|
||||
|
||||
auto curr_clock = std::chrono::steady_clock::now();
|
||||
const auto wait_end_us = curr_clock + std::chrono::microseconds{micros};
|
||||
const auto wait_end_us = (micros == 0) ? std::chrono::steady_clock::time_point::max()
|
||||
: curr_clock + std::chrono::microseconds{micros};
|
||||
|
||||
do {
|
||||
curr_clock = std::chrono::steady_clock::now();
|
||||
|
@ -152,18 +214,14 @@ int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
|
|||
return count;
|
||||
}
|
||||
|
||||
extern boost::asio::io_context io_context;
|
||||
extern void KernelSignalRequest();
|
||||
bool EqueueInternal::EventExists(u64 id, s16 filter) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
|
||||
static void SmallTimerCallback(const boost::system::error_code& error, SceKernelEqueue eq,
|
||||
SceKernelEvent kevent) {
|
||||
static EqueueEvent event;
|
||||
event.event = kevent;
|
||||
event.event.data = HrTimerSpinlockThresholdUs;
|
||||
eq->AddSmallTimer(event);
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||
return it != m_events.cend();
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||
|
@ -216,24 +274,15 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (eq->HasSmallTimer()) {
|
||||
ASSERT(timo && *timo);
|
||||
*out = eq->WaitForSmallTimer(ev, num, *timo);
|
||||
if (timo == nullptr) {
|
||||
// When the timeout is nullptr, we wait indefinitely
|
||||
*out = eq->WaitForEvents(ev, num, 0);
|
||||
} else if (*timo == 0) {
|
||||
// Only events that have already arrived at the time of this function call can be received
|
||||
*out = eq->GetTriggeredEvents(ev, num);
|
||||
} else {
|
||||
if (timo == nullptr) { // wait until an event arrives without timing out
|
||||
*out = eq->WaitForEvents(ev, num, 0);
|
||||
}
|
||||
|
||||
if (timo != nullptr) {
|
||||
// Only events that have already arrived at the time of this function call can be
|
||||
// received
|
||||
if (*timo == 0) {
|
||||
*out = eq->GetTriggeredEvents(ev, num);
|
||||
} else {
|
||||
// Wait until an event arrives with timing out
|
||||
*out = eq->WaitForEvents(ev, num, *timo);
|
||||
}
|
||||
}
|
||||
// Wait for up to the specified timeout value
|
||||
*out = eq->WaitForEvents(ev, num, *timo);
|
||||
}
|
||||
|
||||
if (*out == 0) {
|
||||
|
@ -243,6 +292,14 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||
static EqueueEvent event;
|
||||
event.event = kevent;
|
||||
event.event.data = HrTimerSpinlockThresholdUs;
|
||||
eq->AddSmallTimer(event);
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -273,17 +330,10 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
|
|||
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
event.timer = std::make_unique<boost::asio::steady_timer>(
|
||||
io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs));
|
||||
|
||||
event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event));
|
||||
|
||||
if (!eq->AddEvent(event)) {
|
||||
if (!eq->AddEvent(event) ||
|
||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
KernelSignalRequest();
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -300,6 +350,57 @@ int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
}
|
||||
|
||||
static void TimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||
if (eq->EventExists(kevent.ident, kevent.filter)) {
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::Timer, kevent.udata);
|
||||
|
||||
if (!(kevent.flags & SceKernelEvent::Flags::OneShot)) {
|
||||
// Reschedule the event for its next period.
|
||||
eq->ScheduleEvent(kevent.ident, kevent.filter, TimerCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAddTimerEvent(SceKernelEqueue eq, int id, SceKernelUseconds usec,
|
||||
void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
EqueueEvent event{};
|
||||
event.event.ident = static_cast<u64>(id);
|
||||
event.event.filter = SceKernelEvent::Filter::Timer;
|
||||
event.event.flags = SceKernelEvent::Flags::Add;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = usec;
|
||||
event.event.udata = udata;
|
||||
|
||||
if (eq->EventExists(event.event.ident, event.event.filter)) {
|
||||
eq->RemoveEvent(id, SceKernelEvent::Filter::Timer);
|
||||
LOG_DEBUG(Kernel_Event,
|
||||
"Timer event already exists, removing it: queue name={}, queue id={}",
|
||||
eq->GetName(), event.event.ident);
|
||||
}
|
||||
|
||||
LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}",
|
||||
eq->GetName(), event.event.ident, usec, reinterpret_cast<uintptr_t>(udata));
|
||||
|
||||
if (!eq->AddEvent(event) ||
|
||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::Timer, TimerCallback)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
return eq->RemoveEvent(id, SceKernelEvent::Filter::Timer) ? ORBIS_OK
|
||||
: ORBIS_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -380,6 +481,8 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
|
||||
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
|
||||
LIB_FUNCTION("J+LF6LwObXU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteHRTimerEvent);
|
||||
LIB_FUNCTION("57ZK+ODEXWY", "libkernel", 1, "libkernel", 1, 1, sceKernelAddTimerEvent);
|
||||
LIB_FUNCTION("YWQFUyXIVdU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteTimerEvent);
|
||||
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
|
||||
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
||||
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace Libraries::Kernel {
|
|||
class EqueueInternal;
|
||||
struct EqueueEvent;
|
||||
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = EqueueInternal*;
|
||||
|
||||
struct SceKernelEvent {
|
||||
enum Filter : s16 {
|
||||
None = 0,
|
||||
|
@ -77,6 +80,7 @@ struct EqueueEvent {
|
|||
SceKernelEvent event;
|
||||
void* data = nullptr;
|
||||
std::chrono::steady_clock::time_point time_added;
|
||||
std::chrono::microseconds timer_interval;
|
||||
std::unique_ptr<boost::asio::steady_timer> timer;
|
||||
|
||||
void ResetTriggerState() {
|
||||
|
@ -94,6 +98,12 @@ struct EqueueEvent {
|
|||
event.data = reinterpret_cast<uintptr_t>(data);
|
||||
}
|
||||
|
||||
void TriggerUser(void* data) {
|
||||
is_triggered = true;
|
||||
event.fflags++;
|
||||
event.udata = data;
|
||||
}
|
||||
|
||||
void TriggerDisplay(void* data) {
|
||||
is_triggered = true;
|
||||
if (data != nullptr) {
|
||||
|
@ -133,6 +143,8 @@ public:
|
|||
}
|
||||
|
||||
bool AddEvent(EqueueEvent& event);
|
||||
bool ScheduleEvent(u64 id, s16 filter,
|
||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&));
|
||||
bool RemoveEvent(u64 id, s16 filter);
|
||||
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||
|
@ -152,6 +164,8 @@ public:
|
|||
|
||||
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
|
||||
|
||||
bool EventExists(u64 id, s16 filter);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::mutex m_mutex;
|
||||
|
@ -160,9 +174,6 @@ private:
|
|||
std::condition_variable m_cond;
|
||||
};
|
||||
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = EqueueInternal*;
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
|
||||
|
||||
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
||||
|
|
|
@ -28,8 +28,12 @@
|
|||
|
||||
#ifdef _WIN64
|
||||
#include <Rpc.h>
|
||||
#else
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
#include <common/singleton.h>
|
||||
#include <core/libraries/network/net_error.h>
|
||||
#include <core/libraries/network/sockets.h>
|
||||
#include "aio.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
@ -104,6 +108,9 @@ void SetPosixErrno(int e) {
|
|||
case EACCES:
|
||||
g_posix_errno = POSIX_EACCES;
|
||||
break;
|
||||
case EFAULT:
|
||||
g_posix_errno = POSIX_EFAULT;
|
||||
break;
|
||||
case EINVAL:
|
||||
g_posix_errno = POSIX_EINVAL;
|
||||
break;
|
||||
|
@ -150,23 +157,23 @@ struct OrbisKernelUuid {
|
|||
u8 clockSeqLow;
|
||||
u8 node[6];
|
||||
};
|
||||
static_assert(sizeof(OrbisKernelUuid) == 0x10);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
|
||||
if (!orbisUuid) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
#ifdef _WIN64
|
||||
UUID uuid;
|
||||
UuidCreate(&uuid);
|
||||
orbisUuid->timeLow = uuid.Data1;
|
||||
orbisUuid->timeMid = uuid.Data2;
|
||||
orbisUuid->timeHiAndVersion = uuid.Data3;
|
||||
orbisUuid->clockSeqHiAndReserved = uuid.Data4[0];
|
||||
orbisUuid->clockSeqLow = uuid.Data4[1];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
orbisUuid->node[i] = uuid.Data4[2 + i];
|
||||
if (UuidCreate(&uuid) != RPC_S_OK) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
#else
|
||||
LOG_ERROR(Kernel, "sceKernelUuidCreate: Add linux");
|
||||
uuid_t uuid;
|
||||
uuid_generate(uuid);
|
||||
#endif
|
||||
return 0;
|
||||
std::memcpy(orbisUuid, &uuid, sizeof(OrbisKernelUuid));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
|
||||
|
@ -205,6 +212,24 @@ int PS4_SYSV_ABI posix_getpagesize() {
|
|||
return 16_KB;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
|
||||
Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
auto* netcall = Common::Singleton<Libraries::Net::NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->GetSocketAddress(addr, paddrlen);
|
||||
if (returncode >= 0) {
|
||||
LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode);
|
||||
return 0;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = 0x20;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
|
||||
service_thread = std::jthread{KernelServiceThread};
|
||||
|
||||
|
@ -242,13 +267,16 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom);
|
||||
LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sys_setsockopt);
|
||||
LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sys_getsockname);
|
||||
// LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname);
|
||||
LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
|
||||
LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ...
|
||||
LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ...
|
||||
LIB_FUNCTION("XVL8So3QJUk", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_connect);
|
||||
LIB_FUNCTION("3e+4Iv7IJ8U", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_accept);
|
||||
LIB_FUNCTION("aNeavPDNKzA", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendmsg);
|
||||
LIB_FUNCTION("pxnCmagrtao", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_listen);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <fmt/core.h>
|
||||
#include "common/string_literal.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
|
||||
|
@ -20,26 +17,21 @@ int ErrnoToSceKernelError(int e);
|
|||
void SetPosixErrno(int e);
|
||||
int* PS4_SYSV_ABI __Error();
|
||||
|
||||
template <StringLiteral name, class F, F f>
|
||||
struct WrapperImpl;
|
||||
template <class F, F f>
|
||||
struct OrbisWrapperImpl;
|
||||
|
||||
template <StringLiteral name, class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
|
||||
struct WrapperImpl<name, PS4_SYSV_ABI R (*)(Args...), f> {
|
||||
static constexpr StringLiteral Name{name};
|
||||
template <class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
|
||||
struct OrbisWrapperImpl<PS4_SYSV_ABI R (*)(Args...), f> {
|
||||
static R PS4_SYSV_ABI wrap(Args... args) {
|
||||
u32 ret = f(args...);
|
||||
if (ret != 0) {
|
||||
// LOG_ERROR(Lib_Kernel, "Function {} returned {}", std::string_view{name.value}, ret);
|
||||
ret += ORBIS_KERNEL_ERROR_UNKNOWN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <StringLiteral name, class F, F f>
|
||||
constexpr auto OrbisWrapper = WrapperImpl<name, F, f>::wrap;
|
||||
|
||||
#define ORBIS(func) WrapperImpl<#func, decltype(&func), func>::wrap
|
||||
#define ORBIS(func) (Libraries::Kernel::OrbisWrapperImpl<decltype(&(func)), func>::wrap)
|
||||
|
||||
int* PS4_SYSV_ABI __Error();
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/memory.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
|
@ -152,7 +151,8 @@ s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u
|
|||
const VAddr in_addr = reinterpret_cast<VAddr>(*addr);
|
||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
|
||||
s32 result = memory->Reserve(addr, in_addr, len, map_flags, alignment);
|
||||
s32 result = memory->MapMemory(addr, in_addr, len, Core::MemoryProt::NoAccess, map_flags,
|
||||
Core::VMAType::Reserved, "anon", false, -1, alignment);
|
||||
if (result == 0) {
|
||||
LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr));
|
||||
}
|
||||
|
@ -209,9 +209,23 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
|||
"anon");
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||
int flags, const char* name) {
|
||||
s32 PS4_SYSV_ABI sceKernelMapDirectMemory2(void** addr, u64 len, s32 type, s32 prot, s32 flags,
|
||||
s64 phys_addr, u64 alignment) {
|
||||
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
|
||||
const s32 ret =
|
||||
sceKernelMapNamedDirectMemory(addr, len, prot, flags, phys_addr, alignment, "anon");
|
||||
|
||||
if (ret == 0) {
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->SetDirectMemoryType(phys_addr, type);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, u64 len, s32 prot, s32 flags,
|
||||
const char* name) {
|
||||
LOG_INFO(Kernel_Vmm, "in_addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}, name = '{}'",
|
||||
fmt::ptr(*addr_in_out), len, prot, flags, name);
|
||||
if (len == 0 || !Common::Is16KBAligned(len)) {
|
||||
LOG_ERROR(Kernel_Vmm, "len is 0 or not 16kb multiple");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
|
@ -230,18 +244,14 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t
|
|||
const VAddr in_addr = reinterpret_cast<VAddr>(*addr_in_out);
|
||||
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
|
||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
SCOPE_EXIT {
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
"in_addr = {:#x}, out_addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}",
|
||||
in_addr, fmt::ptr(*addr_in_out), len, prot, flags);
|
||||
};
|
||||
auto* memory = Core::Memory::Instance();
|
||||
return memory->MapMemory(addr_in_out, in_addr, len, mem_prot, map_flags,
|
||||
Core::VMAType::Flexible, name);
|
||||
const auto ret = memory->MapMemory(addr_in_out, in_addr, len, mem_prot, map_flags,
|
||||
Core::VMAType::Flexible, name);
|
||||
LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr_in_out));
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||
int flags) {
|
||||
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, u64 len, s32 prot, s32 flags) {
|
||||
return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, "anon");
|
||||
}
|
||||
|
||||
|
@ -250,13 +260,26 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void**
|
|||
return memory->QueryProtection(std::bit_cast<VAddr>(addr), start, end, prot);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMProtect(const void* addr, size_t size, int prot) {
|
||||
s32 PS4_SYSV_ABI sceKernelMprotect(const void* addr, u64 size, s32 prot) {
|
||||
LOG_INFO(Kernel_Vmm, "called addr = {}, size = {:#x}, prot = {:#x}", fmt::ptr(addr), size,
|
||||
prot);
|
||||
Core::MemoryManager* memory_manager = Core::Memory::Instance();
|
||||
Core::MemoryProt protection_flags = static_cast<Core::MemoryProt>(prot);
|
||||
return memory_manager->Protect(std::bit_cast<VAddr>(addr), size, protection_flags);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMTypeProtect(const void* addr, size_t size, int mtype, int prot) {
|
||||
s32 PS4_SYSV_ABI posix_mprotect(const void* addr, u64 size, s32 prot) {
|
||||
s32 result = sceKernelMprotect(addr, size, prot);
|
||||
if (result < 0) {
|
||||
ErrSceToPosix(result);
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMtypeprotect(const void* addr, u64 size, s32 mtype, s32 prot) {
|
||||
LOG_INFO(Kernel_Vmm, "called addr = {}, size = {:#x}, prot = {:#x}", fmt::ptr(addr), size,
|
||||
prot);
|
||||
Core::MemoryManager* memory_manager = Core::Memory::Instance();
|
||||
Core::MemoryProt protection_flags = static_cast<Core::MemoryProt>(prot);
|
||||
return memory_manager->Protect(std::bit_cast<VAddr>(addr), size, protection_flags);
|
||||
|
@ -290,6 +313,12 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
|
|||
directMemoryEndOut);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
|
||||
LOG_DEBUG(Kernel_Vmm, "called, addr = {}", fmt::ptr(addr));
|
||||
auto* memory = Core::Memory::Instance();
|
||||
return memory->IsStack(std::bit_cast<VAddr>(addr), start, end);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut) {
|
||||
return sceKernelBatchMap2(entries, numEntries, numEntriesOut,
|
||||
|
@ -325,7 +354,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
break;
|
||||
}
|
||||
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_PROTECT: {
|
||||
result = sceKernelMProtect(entries[i].start, entries[i].length, entries[i].protection);
|
||||
result = sceKernelMprotect(entries[i].start, entries[i].length, entries[i].protection);
|
||||
LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i,
|
||||
entries[i].operation, entries[i].length, result);
|
||||
break;
|
||||
|
@ -340,7 +369,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
break;
|
||||
}
|
||||
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_TYPE_PROTECT: {
|
||||
result = sceKernelMTypeProtect(entries[i].start, entries[i].length, entries[i].type,
|
||||
result = sceKernelMtypeprotect(entries[i].start, entries[i].length, entries[i].type,
|
||||
entries[i].protection);
|
||||
LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i,
|
||||
entries[i].operation, entries[i].length, result);
|
||||
|
@ -361,7 +390,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name) {
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, u64 len, const char* name) {
|
||||
if (name == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "name is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
|
@ -377,19 +406,18 @@ s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, cons
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_t len,
|
||||
size_t alignment, u64* physAddrOut) {
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, u64 len, u64 alignment,
|
||||
u64* physAddrOut) {
|
||||
if (searchStart < 0 || searchEnd <= searchStart) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
const bool is_in_range = searchEnd - searchStart >= len;
|
||||
if (len <= 0 || !Common::Is64KBAligned(len) || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
if (len <= 0 || !Common::Is64KBAligned(len)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided length {:#x} is invalid!", len);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (alignment != 0 && !Common::Is64KBAligned(alignment)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment {:#x} is invalid!", alignment);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (physAddrOut == nullptr) {
|
||||
|
@ -397,8 +425,21 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
|
|||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const bool is_in_range = searchEnd - searchStart >= len;
|
||||
if (searchEnd <= searchStart || searchEnd < len || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm,
|
||||
"Provided address range is too small!"
|
||||
" searchStart = {:#x}, searchEnd = {:#x}, length = {:#x}",
|
||||
searchStart, searchEnd, len);
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
PAddr phys_addr = memory->PoolExpand(searchStart, searchEnd, len, alignment);
|
||||
if (phys_addr == -1) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
*physAddrOut = static_cast<s64>(phys_addr);
|
||||
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
|
@ -408,15 +449,11 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t alignment, int flags,
|
||||
void** addrOut) {
|
||||
LOG_INFO(Kernel_Vmm, "addrIn = {}, len = {:#x}, alignment = {:#x}, flags = {:#x}",
|
||||
fmt::ptr(addrIn), len, alignment, flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addr_in, u64 len, u64 alignment, s32 flags,
|
||||
void** addr_out) {
|
||||
LOG_INFO(Kernel_Vmm, "addr_in = {}, len = {:#x}, alignment = {:#x}, flags = {:#x}",
|
||||
fmt::ptr(addr_in), len, alignment, flags);
|
||||
|
||||
if (addrIn == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (len == 0 || !Common::Is2MBAligned(len)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 2MB aligned!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
|
@ -429,14 +466,16 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t ali
|
|||
}
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
const VAddr in_addr = reinterpret_cast<VAddr>(addrIn);
|
||||
const VAddr in_addr = reinterpret_cast<VAddr>(addr_in);
|
||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
memory->PoolReserve(addrOut, in_addr, len, map_flags, alignment);
|
||||
u64 map_alignment = alignment == 0 ? 2_MB : alignment;
|
||||
|
||||
return ORBIS_OK;
|
||||
return memory->MapMemory(addr_out, std::bit_cast<VAddr>(addr_in), len,
|
||||
Core::MemoryProt::NoAccess, map_flags, Core::VMAType::PoolReserved,
|
||||
"anon", false, -1, map_alignment);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags) {
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, u64 len, s32 type, s32 prot, s32 flags) {
|
||||
if (addr == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
|
@ -455,7 +494,7 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int
|
|||
return memory->PoolCommit(in_addr, len, mem_prot);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags) {
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, u64 len, s32 flags) {
|
||||
if (addr == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
|
@ -469,35 +508,105 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags)
|
|||
|
||||
const VAddr pool_addr = reinterpret_cast<VAddr>(addr);
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->PoolDecommit(pool_addr, len);
|
||||
|
||||
return ORBIS_OK;
|
||||
return memory->PoolDecommit(pool_addr, len);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset,
|
||||
void** res) {
|
||||
LOG_INFO(Kernel_Vmm, "called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, offset = {}",
|
||||
fmt::ptr(addr), len, prot, flags, fd, offset);
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
|
||||
s32* num_processed, s32 flags) {
|
||||
if (entries == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
s32 result = ORBIS_OK;
|
||||
s32 processed = 0;
|
||||
|
||||
for (s32 i = 0; i < count; i++, processed++) {
|
||||
OrbisKernelMemoryPoolBatchEntry entry = entries[i];
|
||||
switch (entry.opcode) {
|
||||
case OrbisKernelMemoryPoolOpcode::Commit: {
|
||||
result = sceKernelMemoryPoolCommit(entry.commit_params.addr, entry.commit_params.len,
|
||||
entry.commit_params.type, entry.commit_params.prot,
|
||||
entry.flags);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::Decommit: {
|
||||
result = sceKernelMemoryPoolDecommit(entry.decommit_params.addr,
|
||||
entry.decommit_params.len, entry.flags);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::Protect: {
|
||||
result = sceKernelMprotect(entry.protect_params.addr, entry.protect_params.len,
|
||||
entry.protect_params.prot);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::TypeProtect: {
|
||||
result = sceKernelMtypeprotect(
|
||||
entry.type_protect_params.addr, entry.type_protect_params.len,
|
||||
entry.type_protect_params.type, entry.type_protect_params.prot);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::Move: {
|
||||
UNREACHABLE_MSG("Unimplemented sceKernelMemoryPoolBatch opcode Move");
|
||||
}
|
||||
default: {
|
||||
result = ORBIS_KERNEL_ERROR_EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != ORBIS_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_processed != nullptr) {
|
||||
*num_processed = processed;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, s32 prot, s32 flags, s32 fd, s64 phys_addr) {
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
"called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, phys_addr = {}",
|
||||
fmt::ptr(addr), len, prot, flags, fd, phys_addr);
|
||||
|
||||
void* addr_out;
|
||||
auto* memory = Core::Memory::Instance();
|
||||
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
|
||||
const auto mem_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
|
||||
s32 result = ORBIS_OK;
|
||||
if (fd == -1) {
|
||||
return memory->MapMemory(res, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags,
|
||||
Core::VMAType::Flexible);
|
||||
result = memory->MapMemory(&addr_out, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags,
|
||||
Core::VMAType::Flexible);
|
||||
} else {
|
||||
const uintptr_t handle = h->GetFile(fd)->f.GetFileMapping();
|
||||
return memory->MapFile(res, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags, handle,
|
||||
offset);
|
||||
result = memory->MapFile(&addr_out, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags,
|
||||
fd, phys_addr);
|
||||
}
|
||||
|
||||
if (result != ORBIS_OK) {
|
||||
// If the memory mappings fail, mmap sets errno to the appropriate error code,
|
||||
// then returns (void*)-1;
|
||||
ErrSceToPosix(result);
|
||||
return reinterpret_cast<void*>(-1);
|
||||
}
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
|
||||
void* ptr;
|
||||
LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap");
|
||||
int result = sceKernelMmap(addr, len, prot, flags, fd, offset, &ptr);
|
||||
ASSERT(result == 0);
|
||||
return ptr;
|
||||
s32 PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, s32 prot, s32 flags, s32 fd, s64 phys_addr,
|
||||
void** res) {
|
||||
void* addr_out = posix_mmap(addr, len, prot, flags, fd, phys_addr);
|
||||
|
||||
if (addr_out == reinterpret_cast<void*>(-1)) {
|
||||
// posix_mmap failed, calculate and return the appropriate kernel error code using errno.
|
||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
|
||||
// Set the outputted address
|
||||
*res = addr_out;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelConfiguredFlexibleMemorySize(u64* sizeOut) {
|
||||
|
@ -576,8 +685,10 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange);
|
||||
LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType);
|
||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
||||
LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack);
|
||||
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
|
||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
||||
LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2);
|
||||
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
|
||||
LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery);
|
||||
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);
|
||||
|
@ -597,14 +708,16 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("n1-v6FgU7MQ", "libkernel", 1, "libkernel", 1, 1,
|
||||
sceKernelConfiguredFlexibleMemorySize);
|
||||
|
||||
LIB_FUNCTION("9bfdLIyuwCY", "libkernel", 1, "libkernel", 1, 1, sceKernelMTypeProtect);
|
||||
LIB_FUNCTION("vSMAm3cxYTY", "libkernel", 1, "libkernel", 1, 1, sceKernelMProtect);
|
||||
LIB_FUNCTION("vSMAm3cxYTY", "libkernel", 1, "libkernel", 1, 1, sceKernelMprotect);
|
||||
LIB_FUNCTION("YQOfxL4QfeU", "libScePosix", 1, "libkernel", 1, 1, posix_mprotect);
|
||||
LIB_FUNCTION("9bfdLIyuwCY", "libkernel", 1, "libkernel", 1, 1, sceKernelMtypeprotect);
|
||||
|
||||
// Memory pool
|
||||
LIB_FUNCTION("qCSfqDILlns", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolExpand);
|
||||
LIB_FUNCTION("pU-QydtGcGY", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolReserve);
|
||||
LIB_FUNCTION("Vzl66WmfLvk", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolCommit);
|
||||
LIB_FUNCTION("LXo1tpFqJGs", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolDecommit);
|
||||
LIB_FUNCTION("YN878uKRBbE", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolBatch);
|
||||
|
||||
LIB_FUNCTION("BPE9s9vQQXo", "libkernel", 1, "libkernel", 1, 1, posix_mmap);
|
||||
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);
|
||||
|
|
|
@ -61,13 +61,15 @@ struct OrbisVirtualQueryInfo {
|
|||
size_t offset;
|
||||
s32 protection;
|
||||
s32 memory_type;
|
||||
u32 is_flexible : 1;
|
||||
u32 is_direct : 1;
|
||||
u32 is_stack : 1;
|
||||
u32 is_pooled : 1;
|
||||
u32 is_committed : 1;
|
||||
u8 is_flexible : 1;
|
||||
u8 is_direct : 1;
|
||||
u8 is_stack : 1;
|
||||
u8 is_pooled : 1;
|
||||
u8 is_committed : 1;
|
||||
char name[ORBIS_KERNEL_MAXIMUM_NAME_LENGTH];
|
||||
};
|
||||
static_assert(sizeof(OrbisVirtualQueryInfo) == 72,
|
||||
"OrbisVirtualQueryInfo struct size is incorrect");
|
||||
|
||||
struct OrbisKernelBatchMapEntry {
|
||||
void* start;
|
||||
|
@ -79,6 +81,48 @@ struct OrbisKernelBatchMapEntry {
|
|||
int operation;
|
||||
};
|
||||
|
||||
enum class OrbisKernelMemoryPoolOpcode : u32 {
|
||||
Commit = 1,
|
||||
Decommit = 2,
|
||||
Protect = 3,
|
||||
TypeProtect = 4,
|
||||
Move = 5,
|
||||
};
|
||||
|
||||
struct OrbisKernelMemoryPoolBatchEntry {
|
||||
OrbisKernelMemoryPoolOpcode opcode;
|
||||
u32 flags;
|
||||
union {
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
u8 prot;
|
||||
u8 type;
|
||||
} commit_params;
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
} decommit_params;
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
u8 prot;
|
||||
} protect_params;
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
u8 prot;
|
||||
u8 type;
|
||||
} type_protect_params;
|
||||
struct {
|
||||
void* dest_addr;
|
||||
void* src_addr;
|
||||
u64 len;
|
||||
} move_params;
|
||||
uintptr_t padding[3];
|
||||
};
|
||||
};
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
||||
u64 alignment, int memoryType, s64* physAddrOut);
|
||||
|
@ -97,15 +141,14 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
|
|||
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
|
||||
size_t infoSize);
|
||||
s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment);
|
||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addrInOut, std::size_t len, int prot,
|
||||
int flags, const char* name);
|
||||
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||
int flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, u64 len, s32 prot, s32 flags,
|
||||
const char* name);
|
||||
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, u64 len, s32 prot, s32 flags);
|
||||
int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMProtect(const void* addr, size_t size, int prot);
|
||||
s32 PS4_SYSV_ABI sceKernelMprotect(const void* addr, u64 size, s32 prot);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMTypeProtect(const void* addr, size_t size, int mtype, int prot);
|
||||
s32 PS4_SYSV_ABI sceKernelMtypeprotect(const void* addr, u64 size, s32 mtype, s32 prot);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
|
||||
size_t infoSize);
|
||||
|
@ -114,20 +157,23 @@ void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
|
|||
int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
|
||||
void** directMemoryStartOut,
|
||||
void** directMemoryEndOut);
|
||||
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut);
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut, int flags);
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name);
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, u64 len, const char* name);
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_t len,
|
||||
size_t alignment, u64* physAddrOut);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t alignment, int flags,
|
||||
void** addrOut);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, u64 len, u64 alignment,
|
||||
u64* physAddrOut);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addr_in, u64 len, u64 alignment, s32 flags,
|
||||
void** addr_out);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, u64 len, s32 type, s32 prot, s32 flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, u64 len, s32 flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
|
||||
s32* num_processed, s32 flags);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
|
||||
|
||||
|
|
|
@ -17,6 +17,12 @@ int PS4_SYSV_ABI posix_pthread_attr_init(PthreadAttrT* attr);
|
|||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_destroy(PthreadAttrT* attr);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, size_t cpusetsize,
|
||||
Cpuset* cpusetp);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t cpusetsize,
|
||||
const Cpuset* cpusetp);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr,
|
||||
PthreadEntryFunc start_routine, void* arg);
|
||||
|
||||
|
@ -35,7 +41,7 @@ public:
|
|||
this->func = std::move(func);
|
||||
PthreadAttrT attr{};
|
||||
posix_pthread_attr_init(&attr);
|
||||
posix_pthread_create(&thread, &attr, RunWrapper, this);
|
||||
posix_pthread_create(&thread, &attr, HOST_CALL(RunWrapper), this);
|
||||
posix_pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
|||
auto result = ef->Poll(bitPattern, wait, clear, pResultPat);
|
||||
|
||||
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_EBUSY) {
|
||||
LOG_ERROR(Kernel_Event, "returned {}", result);
|
||||
LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -361,7 +361,7 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
|||
u32 result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout);
|
||||
|
||||
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_ETIMEDOUT) {
|
||||
LOG_ERROR(Kernel_Event, "returned {:#x}", result);
|
||||
LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -426,6 +426,7 @@ void RegisterMutex(Core::Loader::SymbolsResolver* sym) {
|
|||
// Posix
|
||||
LIB_FUNCTION("ttHNfU+qDBU", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_init);
|
||||
LIB_FUNCTION("7H0iTOciTLo", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
|
||||
LIB_FUNCTION("Io9+nTKXZtA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_timedlock);
|
||||
LIB_FUNCTION("2Z+PpY6CaJg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_unlock);
|
||||
LIB_FUNCTION("ltCfaGr2JGE", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_destroy);
|
||||
LIB_FUNCTION("dQHWEsJtoE4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutexattr_init);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "core/debug_state.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/posix_error.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
#include "core/libraries/kernel/threads/thread_state.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
@ -535,8 +536,6 @@ int Pthread::SetAffinity(const Cpuset* cpuset) {
|
|||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
u64 mask = cpuset->bits;
|
||||
|
||||
uintptr_t handle = native_thr.GetHandle();
|
||||
if (handle == 0) {
|
||||
return POSIX_ESRCH;
|
||||
|
@ -545,6 +544,7 @@ int Pthread::SetAffinity(const Cpuset* cpuset) {
|
|||
// We don't use this currently because some games gets performance problems
|
||||
// when applying affinity even on strong hardware
|
||||
/*
|
||||
u64 mask = cpuset->bits;
|
||||
#ifdef _WIN64
|
||||
DWORD_PTR affinity_mask = static_cast<DWORD_PTR>(mask);
|
||||
if (!SetThreadAffinityMask(reinterpret_cast<HANDLE>(handle), affinity_mask)) {
|
||||
|
@ -572,21 +572,61 @@ int Pthread::SetAffinity(const Cpuset* cpuset) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_getaffinity_np(PthreadT thread, size_t cpusetsize, Cpuset* cpusetp) {
|
||||
if (thread == nullptr || cpusetp == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
auto* thread_state = ThrState::Instance();
|
||||
if (thread == g_curthread) {
|
||||
g_curthread->lock.lock();
|
||||
} else if (auto ret = thread_state->FindThread(thread, /*include dead*/ 0); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto* attr_ptr = &thread->attr;
|
||||
auto ret = posix_pthread_attr_getaffinity_np(&attr_ptr, cpusetsize, cpusetp);
|
||||
|
||||
thread->lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_setaffinity_np(PthreadT thread, size_t cpusetsize,
|
||||
const Cpuset* cpusetp) {
|
||||
if (thread == nullptr || cpusetp == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
thread->attr.cpusetsize = cpusetsize;
|
||||
return thread->SetAffinity(cpusetp);
|
||||
|
||||
auto* thread_state = ThrState::Instance();
|
||||
if (thread == g_curthread) {
|
||||
g_curthread->lock.lock();
|
||||
} else if (auto ret = thread_state->FindThread(thread, /*include dead*/ 0); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto* attr_ptr = &thread->attr;
|
||||
auto ret = posix_pthread_attr_setaffinity_np(&attr_ptr, cpusetsize, cpusetp);
|
||||
|
||||
if (ret == ORBIS_OK) {
|
||||
ret = thread->SetAffinity(thread->attr.cpuset);
|
||||
}
|
||||
|
||||
thread->lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadSetaffinity(PthreadT thread, const Cpuset mask) {
|
||||
int result = posix_pthread_setaffinity_np(thread, 0x10, &mask);
|
||||
if (result != 0) {
|
||||
return ErrnoToSceKernelError(result);
|
||||
int PS4_SYSV_ABI scePthreadGetaffinity(PthreadT thread, u64* mask) {
|
||||
Cpuset cpuset;
|
||||
const int ret = posix_pthread_getaffinity_np(thread, sizeof(Cpuset), &cpuset);
|
||||
if (ret == 0) {
|
||||
*mask = cpuset.bits;
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadSetaffinity(PthreadT thread, const u64 mask) {
|
||||
const Cpuset cpuset = {.bits = mask};
|
||||
return posix_pthread_setaffinity_np(thread, sizeof(Cpuset), &cpuset);
|
||||
}
|
||||
|
||||
void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
||||
|
@ -612,6 +652,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once);
|
||||
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
LIB_FUNCTION("Jb2uGFMr688", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getaffinity_np);
|
||||
LIB_FUNCTION("5KWrg7-ZqvE", "libkernel", 1, "libkernel", 1, 1, posix_pthread_setaffinity_np);
|
||||
|
||||
// Orbis
|
||||
|
@ -635,7 +676,8 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_setprio));
|
||||
LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors);
|
||||
LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield);
|
||||
LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, scePthreadSetaffinity)
|
||||
LIB_FUNCTION("rcrVFJsQWRY", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadGetaffinity));
|
||||
LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadSetaffinity));
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -159,6 +159,7 @@ enum class SchedPolicy : u32 {
|
|||
|
||||
struct Cpuset {
|
||||
u64 bits;
|
||||
u64 _reserved;
|
||||
};
|
||||
|
||||
struct PthreadAttr {
|
||||
|
@ -269,7 +270,7 @@ struct Pthread {
|
|||
bool no_cancel;
|
||||
bool cancel_async;
|
||||
bool cancelling;
|
||||
Cpuset sigmask;
|
||||
u64 sigmask;
|
||||
bool unblock_sigcancel;
|
||||
bool in_sigsuspend;
|
||||
bool force_exit;
|
||||
|
|
|
@ -243,7 +243,7 @@ int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, si
|
|||
if (attr->cpuset != nullptr)
|
||||
memcpy(cpusetp, attr->cpuset, std::min(cpusetsize, attr->cpusetsize));
|
||||
else
|
||||
memset(cpusetp, -1, sizeof(Cpuset));
|
||||
memset(cpusetp, -1, cpusetsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -259,30 +259,31 @@ int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t c
|
|||
if (cpusetsize == 0 || cpusetp == nullptr) {
|
||||
if (attr->cpuset != nullptr) {
|
||||
free(attr->cpuset);
|
||||
attr->cpuset = NULL;
|
||||
attr->cpuset = nullptr;
|
||||
attr->cpusetsize = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (attr->cpuset == nullptr) {
|
||||
attr->cpuset = (Cpuset*)calloc(1, sizeof(Cpuset));
|
||||
attr->cpuset = static_cast<Cpuset*>(calloc(1, sizeof(Cpuset)));
|
||||
attr->cpusetsize = sizeof(Cpuset);
|
||||
}
|
||||
memcpy(attr->cpuset, cpusetp, sizeof(Cpuset));
|
||||
memcpy(attr->cpuset, cpusetp, std::min(cpusetsize, sizeof(Cpuset)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* param_1, Cpuset* mask) {
|
||||
int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* attr, u64* mask) {
|
||||
Cpuset cpuset;
|
||||
const int ret = posix_pthread_attr_getaffinity_np(param_1, 0x10, &cpuset);
|
||||
const int ret = posix_pthread_attr_getaffinity_np(attr, sizeof(Cpuset), &cpuset);
|
||||
if (ret == 0) {
|
||||
*mask = cpuset;
|
||||
*mask = cpuset.bits;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const Cpuset mask) {
|
||||
return posix_pthread_attr_setaffinity_np(attr, 0x10, &mask);
|
||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask) {
|
||||
const Cpuset cpuset = {.bits = mask};
|
||||
return posix_pthread_attr_setaffinity_np(attr, sizeof(Cpuset), &cpuset);
|
||||
}
|
||||
|
||||
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
|
||||
|
@ -305,6 +306,8 @@ void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
|
|||
posix_pthread_attr_getdetachstate);
|
||||
LIB_FUNCTION("JKyG3SWyA10", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_setguardsize);
|
||||
LIB_FUNCTION("qlk9pSLsUmM", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_getschedparam);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1,
|
||||
|
|
|
@ -5,24 +5,23 @@
|
|||
|
||||
#include "common/assert.h"
|
||||
#include "common/native_clock.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
#include "core/libraries/kernel/posix_error.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <pthread_time.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "common/ntapi.h"
|
||||
|
||||
#else
|
||||
#if __APPLE__
|
||||
#include <date/tz.h>
|
||||
#endif
|
||||
#include <ctime>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
@ -52,88 +51,116 @@ u64 PS4_SYSV_ABI sceKernelReadTsc() {
|
|||
return clock->GetUptime();
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
|
||||
#ifdef _WIN64
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
auto total_wait_time = std::chrono::microseconds(microseconds);
|
||||
static s32 posix_nanosleep_impl(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp,
|
||||
const bool interruptible) {
|
||||
if (!rqtp || rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1'000'000'000) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
const auto duration = std::chrono::nanoseconds(rqtp->tv_sec * 1'000'000'000 + rqtp->tv_nsec);
|
||||
std::chrono::nanoseconds remain;
|
||||
const auto uninterrupted = Common::AccurateSleep(duration, &remain, interruptible);
|
||||
if (rmtp) {
|
||||
rmtp->tv_sec = remain.count() / 1'000'000'000;
|
||||
rmtp->tv_nsec = remain.count() % 1'000'000'000;
|
||||
}
|
||||
if (!uninterrupted) {
|
||||
SetPosixErrno(EINTR);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (total_wait_time.count() > 0) {
|
||||
auto wait_time = std::chrono::ceil<std::chrono::milliseconds>(total_wait_time).count();
|
||||
u64 res = SleepEx(static_cast<u64>(wait_time), true);
|
||||
if (res == WAIT_IO_COMPLETION) {
|
||||
auto elapsedTime = std::chrono::high_resolution_clock::now() - start_time;
|
||||
auto elapsedMicroseconds =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(elapsedTime).count();
|
||||
total_wait_time = std::chrono::microseconds(microseconds - elapsedMicroseconds);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
s32 PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
return posix_nanosleep_impl(rqtp, rmtp, true);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
if (const auto ret = posix_nanosleep_impl(rqtp, rmtp, false); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_usleep(u32 microseconds) {
|
||||
const OrbisKernelTimespec ts = {
|
||||
.tv_sec = microseconds / 1'000'000,
|
||||
.tv_nsec = (microseconds % 1'000'000) * 1'000,
|
||||
};
|
||||
return posix_nanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
|
||||
const OrbisKernelTimespec ts = {
|
||||
.tv_sec = microseconds / 1'000'000,
|
||||
.tv_nsec = (microseconds % 1'000'000) * 1'000,
|
||||
};
|
||||
return sceKernelNanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI posix_sleep(u32 seconds) {
|
||||
const OrbisKernelTimespec ts = {
|
||||
.tv_sec = seconds,
|
||||
.tv_nsec = 0,
|
||||
};
|
||||
OrbisKernelTimespec rm;
|
||||
if (const auto ret = posix_nanosleep(&ts, &rm); ret < 0) {
|
||||
return *__Error() == POSIX_EINTR ? rm.tv_sec + (rm.tv_nsec == 0 ? 0 : 1) : seconds;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
|
||||
return sceKernelUsleep(seconds * 1'000'000);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_clock_gettime(u32 clock_id, OrbisKernelTimespec* ts) {
|
||||
if (ts == nullptr) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
timespec start;
|
||||
timespec remain;
|
||||
start.tv_sec = microseconds / 1000000;
|
||||
start.tv_nsec = (microseconds % 1000000) * 1000;
|
||||
timespec* requested = &start;
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = nanosleep(requested, &remain);
|
||||
requested = &remain;
|
||||
} while (ret != 0);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
if (clock_id == ORBIS_CLOCK_PROCTIME) {
|
||||
const auto us = sceKernelGetProcessTime();
|
||||
ts->tv_sec = static_cast<s64>(us / 1'000'000);
|
||||
ts->tv_nsec = static_cast<s64>((us % 1'000'000) * 1000);
|
||||
return 0;
|
||||
}
|
||||
if (clock_id == ORBIS_CLOCK_EXT_NETWORK || clock_id == ORBIS_CLOCK_EXT_DEBUG_NETWORK ||
|
||||
clock_id == ORBIS_CLOCK_EXT_AD_NETWORK || clock_id == ORBIS_CLOCK_EXT_RAW_NETWORK) {
|
||||
LOG_ERROR(Lib_Kernel, "Unsupported clock type {}, using CLOCK_MONOTONIC", clock_id);
|
||||
clock_id = ORBIS_CLOCK_MONOTONIC;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_usleep(u32 microseconds) {
|
||||
return sceKernelUsleep(microseconds);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(seconds));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 0
|
||||
#endif
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 1
|
||||
#endif
|
||||
#ifndef CLOCK_PROCESS_CPUTIME_ID
|
||||
#define CLOCK_PROCESS_CPUTIME_ID 2
|
||||
#endif
|
||||
#ifndef CLOCK_THREAD_CPUTIME_ID
|
||||
#define CLOCK_THREAD_CPUTIME_ID 3
|
||||
#endif
|
||||
#ifndef CLOCK_REALTIME_COARSE
|
||||
#define CLOCK_REALTIME_COARSE 5
|
||||
#endif
|
||||
#ifndef CLOCK_MONOTONIC_COARSE
|
||||
#define CLOCK_MONOTONIC_COARSE 6
|
||||
#endif
|
||||
|
||||
#define DELTA_EPOCH_IN_100NS 116444736000000000ULL
|
||||
|
||||
static u64 FileTimeTo100Ns(FILETIME& ft) {
|
||||
return *reinterpret_cast<u64*>(&ft);
|
||||
}
|
||||
|
||||
static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
|
||||
#ifdef _WIN32
|
||||
static const auto FileTimeTo100Ns = [](FILETIME& ft) { return *reinterpret_cast<u64*>(&ft); };
|
||||
switch (clock_id) {
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_REALTIME_COARSE: {
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE: {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
const u64 ns = FileTimeTo100Ns(ft) - DELTA_EPOCH_IN_100NS;
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
static constexpr u64 DeltaEpochIn100ns = 116444736000000000ULL;
|
||||
const u64 ns = FileTimeTo100Ns(ft) - DeltaEpochIn100ns;
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_MONOTONIC_COARSE: {
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST: {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
static constexpr u64 DeltaEpochIn100ns = 116444736000000000ULL;
|
||||
const u64 ns = FileTimeTo100Ns(ft) - DeltaEpochIn100ns;
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_UPTIME:
|
||||
case ORBIS_CLOCK_UPTIME_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC:
|
||||
case ORBIS_CLOCK_MONOTONIC_PRECISE:
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST: {
|
||||
static LARGE_INTEGER pf = [] {
|
||||
LARGE_INTEGER res{};
|
||||
QueryPerformanceFrequency(&pf);
|
||||
|
@ -141,43 +168,53 @@ static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
|
|||
}();
|
||||
|
||||
LARGE_INTEGER pc{};
|
||||
QueryPerformanceCounter(&pc);
|
||||
if (!QueryPerformanceCounter(&pc)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
ts->tv_sec = pc.QuadPart / pf.QuadPart;
|
||||
ts->tv_nsec = ((pc.QuadPart % pf.QuadPart) * 1000'000'000) / pf.QuadPart;
|
||||
return 0;
|
||||
}
|
||||
case CLOCK_PROCESS_CPUTIME_ID: {
|
||||
case ORBIS_CLOCK_THREAD_CPUTIME_ID: {
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case CLOCK_THREAD_CPUTIME_ID: {
|
||||
case ORBIS_CLOCK_VIRTUAL: {
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
|
||||
const u64 ns = FileTimeTo100Ns(ut);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_PROF: {
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(kt);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return EINVAL;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* ts) {
|
||||
if (ts == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
clockid_t pclock_id = CLOCK_MONOTONIC;
|
||||
#else
|
||||
clockid_t pclock_id;
|
||||
switch (clock_id) {
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE:
|
||||
|
@ -185,7 +222,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
|
|||
break;
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST:
|
||||
#ifndef __APPLE__
|
||||
#ifdef CLOCK_REALTIME_COARSE
|
||||
pclock_id = CLOCK_REALTIME_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_REALTIME;
|
||||
|
@ -199,7 +236,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
|
|||
break;
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST:
|
||||
#ifndef __APPLE__
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
pclock_id = CLOCK_MONOTONIC_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
|
@ -208,196 +245,226 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
|
|||
case ORBIS_CLOCK_THREAD_CPUTIME_ID:
|
||||
pclock_id = CLOCK_THREAD_CPUTIME_ID;
|
||||
break;
|
||||
case ORBIS_CLOCK_PROCTIME: {
|
||||
const auto us = sceKernelGetProcessTime();
|
||||
ts->tv_sec = us / 1'000'000;
|
||||
ts->tv_nsec = (us % 1'000'000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_VIRTUAL: {
|
||||
#ifdef _WIN64
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(ut);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
#else
|
||||
struct rusage ru;
|
||||
rusage ru;
|
||||
const auto res = getrusage(RUSAGE_SELF, &ru);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
ts->tv_sec = ru.ru_utime.tv_sec;
|
||||
ts->tv_nsec = ru.ru_utime.tv_usec * 1000;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_PROF: {
|
||||
#ifdef _WIN64
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(kt);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
#else
|
||||
struct rusage ru;
|
||||
rusage ru;
|
||||
const auto res = getrusage(RUSAGE_SELF, &ru);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
ts->tv_sec = ru.ru_stime.tv_sec;
|
||||
ts->tv_nsec = ru.ru_stime.tv_usec * 1000;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_EXT_NETWORK:
|
||||
case ORBIS_CLOCK_EXT_DEBUG_NETWORK:
|
||||
case ORBIS_CLOCK_EXT_AD_NETWORK:
|
||||
case ORBIS_CLOCK_EXT_RAW_NETWORK:
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
LOG_ERROR(Lib_Kernel, "unsupported = {} using CLOCK_MONOTONIC", clock_id);
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
timespec t{};
|
||||
int result = clock_gettime(pclock_id, &t);
|
||||
const auto result = clock_gettime(pclock_id, &t);
|
||||
ts->tv_sec = t.tv_sec;
|
||||
ts->tv_nsec = t.tv_nsec;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) {
|
||||
const auto res = orbis_clock_gettime(clock_id, tp);
|
||||
if (res < 0) {
|
||||
return ErrnoToSceKernelError(res);
|
||||
if (result < 0) {
|
||||
SetPosixErrno(errno);
|
||||
return -1;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
const auto* request = reinterpret_cast<const timespec*>(rqtp);
|
||||
auto* remain = reinterpret_cast<timespec*>(rmtp);
|
||||
return nanosleep(request, remain);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
if (!rqtp || !rmtp) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
return posix_nanosleep(rqtp, rmtp);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
|
||||
if (!tp) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
FILETIME filetime;
|
||||
GetSystemTimePreciseAsFileTime(&filetime);
|
||||
|
||||
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
||||
constexpr u64 TICKS_PER_SECOND = 1000000;
|
||||
|
||||
u64 ticks = filetime.dwHighDateTime;
|
||||
ticks <<= 32;
|
||||
ticks |= filetime.dwLowDateTime;
|
||||
ticks /= 10;
|
||||
ticks -= UNIX_TIME_START;
|
||||
|
||||
tp->tv_sec = ticks / TICKS_PER_SECOND;
|
||||
tp->tv_usec = ticks % TICKS_PER_SECOND;
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_usec = tv.tv_usec;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelClockGettime(const u32 clock_id, OrbisKernelTimespec* ts) {
|
||||
if (const auto ret = posix_clock_gettime(clock_id, ts); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
|
||||
// FreeBSD docs mention that the kernel generally does not track these values
|
||||
// and they are usually returned as zero.
|
||||
if (tz) {
|
||||
tz->tz_minuteswest = 0;
|
||||
tz->tz_dsttime = 0;
|
||||
}
|
||||
return sceKernelGettimeofday(tp);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
|
||||
#ifdef _WIN64
|
||||
ASSERT(tz);
|
||||
static int tzflag = 0;
|
||||
if (!tzflag) {
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
#else
|
||||
struct timezone tzz;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, &tzz);
|
||||
tz->tz_dsttime = tzz.tz_dsttime;
|
||||
tz->tz_minuteswest = tzz.tz_minuteswest;
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
|
||||
s32 PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
|
||||
if (res == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
clockid_t pclock_id = CLOCK_REALTIME;
|
||||
|
||||
if (clock_id == ORBIS_CLOCK_EXT_NETWORK || clock_id == ORBIS_CLOCK_EXT_DEBUG_NETWORK ||
|
||||
clock_id == ORBIS_CLOCK_EXT_AD_NETWORK || clock_id == ORBIS_CLOCK_EXT_RAW_NETWORK) {
|
||||
LOG_ERROR(Lib_Kernel, "Unsupported clock type {}, using CLOCK_MONOTONIC", clock_id);
|
||||
clock_id = ORBIS_CLOCK_MONOTONIC;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
switch (clock_id) {
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST: {
|
||||
DWORD timeAdjustment;
|
||||
DWORD timeIncrement;
|
||||
BOOL isTimeAdjustmentDisabled;
|
||||
if (!GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
res->tv_sec = 0;
|
||||
res->tv_nsec = timeIncrement * 100;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE:
|
||||
case ORBIS_CLOCK_UPTIME:
|
||||
case ORBIS_CLOCK_UPTIME_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC:
|
||||
case ORBIS_CLOCK_MONOTONIC_PRECISE:
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST: {
|
||||
LARGE_INTEGER pf;
|
||||
if (!QueryPerformanceFrequency(&pf)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
res->tv_sec = 0;
|
||||
res->tv_nsec =
|
||||
std::max(static_cast<s32>((1000000000 + (pf.QuadPart >> 1)) / pf.QuadPart), 1);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#else
|
||||
clockid_t pclock_id;
|
||||
switch (clock_id) {
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE:
|
||||
case ORBIS_CLOCK_REALTIME_FAST:
|
||||
pclock_id = CLOCK_REALTIME;
|
||||
break;
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST:
|
||||
#ifdef CLOCK_REALTIME_COARSE
|
||||
pclock_id = CLOCK_REALTIME_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_REALTIME;
|
||||
#endif
|
||||
break;
|
||||
case ORBIS_CLOCK_UPTIME:
|
||||
case ORBIS_CLOCK_UPTIME_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC:
|
||||
case ORBIS_CLOCK_MONOTONIC_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST:
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST:
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
pclock_id = CLOCK_MONOTONIC_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
timespec t{};
|
||||
int result = clock_getres(pclock_id, &t);
|
||||
const auto result = clock_getres(pclock_id, &t);
|
||||
res->tv_sec = t.tv_sec;
|
||||
res->tv_nsec = t.tv_nsec;
|
||||
if (result == 0) {
|
||||
return ORBIS_OK;
|
||||
if (result < 0) {
|
||||
SetPosixErrno(errno);
|
||||
return -1;
|
||||
}
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, int* dst_seconds) {
|
||||
s32 PS4_SYSV_ABI sceKernelClockGetres(const u32 clock_id, OrbisKernelTimespec* res) {
|
||||
if (const auto ret = posix_clock_getres(clock_id, res); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
|
||||
#ifdef _WIN64
|
||||
if (tp) {
|
||||
FILETIME filetime;
|
||||
GetSystemTimePreciseAsFileTime(&filetime);
|
||||
|
||||
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
||||
constexpr u64 TICKS_PER_SECOND = 1000000;
|
||||
|
||||
u64 ticks = filetime.dwHighDateTime;
|
||||
ticks <<= 32;
|
||||
ticks |= filetime.dwLowDateTime;
|
||||
ticks /= 10;
|
||||
ticks -= UNIX_TIME_START;
|
||||
|
||||
tp->tv_sec = ticks / TICKS_PER_SECOND;
|
||||
tp->tv_usec = ticks % TICKS_PER_SECOND;
|
||||
}
|
||||
if (tz) {
|
||||
static int tzflag = 0;
|
||||
if (!tzflag) {
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
struct timezone tzz;
|
||||
timeval tv;
|
||||
const auto ret = gettimeofday(&tv, &tzz);
|
||||
if (tp) {
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_usec = tv.tv_usec;
|
||||
}
|
||||
if (tz) {
|
||||
tz->tz_dsttime = tzz.tz_dsttime;
|
||||
tz->tz_minuteswest = tzz.tz_minuteswest;
|
||||
}
|
||||
if (ret < 0) {
|
||||
SetPosixErrno(errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
|
||||
if (const auto ret = posix_gettimeofday(tp, nullptr); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
|
||||
if (const auto ret = posix_gettimeofday(nullptr, tz); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, s32* dst_seconds) {
|
||||
LOG_INFO(Kernel, "called");
|
||||
if (timezone) {
|
||||
sceKernelGettimezone(timezone);
|
||||
param_1 -= (timezone->tz_minuteswest + timezone->tz_dsttime) * 60;
|
||||
if (seconds)
|
||||
if (seconds) {
|
||||
*seconds = param_1;
|
||||
if (dst_seconds)
|
||||
}
|
||||
if (dst_seconds) {
|
||||
*dst_seconds = timezone->tz_dsttime * 60;
|
||||
}
|
||||
} else {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
@ -415,7 +482,7 @@ Common::NativeClock* GetClock() {
|
|||
|
||||
} // namespace Dev
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
|
||||
s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
|
||||
struct OrbisTimesec* st, u64* dst_sec) {
|
||||
LOG_TRACE(Kernel, "Called");
|
||||
#ifdef __APPLE__
|
||||
|
@ -444,28 +511,35 @@ int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
|
|||
void RegisterTime(Core::Loader::SymbolsResolver* sym) {
|
||||
clock = std::make_unique<Common::NativeClock>();
|
||||
initial_ptc = clock->GetUptime();
|
||||
|
||||
// POSIX
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("0wu33hunNdE", "libkernel", 1, "libkernel", 1, 1, posix_sleep);
|
||||
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, posix_sleep);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, posix_clock_gettime);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, posix_clock_gettime);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libkernel", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, posix_gettimeofday);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, posix_gettimeofday);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime);
|
||||
LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter);
|
||||
LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1,
|
||||
sceKernelGetProcessTimeCounterFrequency);
|
||||
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
|
||||
LIB_FUNCTION("1j3S3n-tTW4", "libkernel", 1, "libkernel", 1, 1, sceKernelGetTscFrequency);
|
||||
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, gettimeofday);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, gettimeofday);
|
||||
LIB_FUNCTION("QvsZxomvUHs", "libkernel", 1, "libkernel", 1, 1, sceKernelNanosleep);
|
||||
LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep);
|
||||
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, sceKernelSleep);
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime);
|
||||
LIB_FUNCTION("wRYVA5Zolso", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGetres);
|
||||
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
|
||||
LIB_FUNCTION("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, orbis_clock_gettime);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, orbis_clock_gettime);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("0NTHN1NKONI", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertLocaltimeToUtc);
|
||||
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
|
||||
}
|
||||
|
|
|
@ -75,14 +75,14 @@ u64 PS4_SYSV_ABI sceKernelGetProcessTime();
|
|||
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter();
|
||||
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency();
|
||||
u64 PS4_SYSV_ABI sceKernelReadTsc();
|
||||
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp);
|
||||
s32 PS4_SYSV_ABI sceKernelClockGettime(u32 clock_id, OrbisKernelTimespec* tp);
|
||||
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz);
|
||||
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, int* dst_seconds);
|
||||
s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, s32* dst_seconds);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st,
|
||||
s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st,
|
||||
u64* dst_sec);
|
||||
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
|
||||
s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
|
||||
|
||||
void RegisterTime(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio3d/audio3d.h"
|
||||
#include "core/libraries/avplayer/avplayer.h"
|
||||
#include "core/libraries/camera/camera.h"
|
||||
#include "core/libraries/companion/companion_httpd.h"
|
||||
#include "core/libraries/companion/companion_util.h"
|
||||
#include "core/libraries/disc_map/disc_map.h"
|
||||
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
|
||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||
|
@ -57,6 +60,7 @@
|
|||
#include "core/libraries/videodec/videodec.h"
|
||||
#include "core/libraries/videodec/videodec2.h"
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
#include "core/libraries/voice/voice.h"
|
||||
#include "core/libraries/web_browser_dialog/webbrowserdialog.h"
|
||||
#include "core/libraries/zlib/zlib_sce.h"
|
||||
#include "fiber/fiber.h"
|
||||
|
@ -122,6 +126,10 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||
Libraries::DiscMap::RegisterlibSceDiscMap(sym);
|
||||
Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym);
|
||||
Libraries::SigninDialog::RegisterlibSceSigninDialog(sym);
|
||||
Libraries::Camera::RegisterlibSceCamera(sym);
|
||||
Libraries::CompanionHttpd::RegisterlibSceCompanionHttpd(sym);
|
||||
Libraries::CompanionUtil::RegisterlibSceCompanionUtil(sym);
|
||||
Libraries::Voice::RegisterlibSceVoice(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
|
|
@ -3,13 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/loader/elf.h"
|
||||
#include "core/loader/symbols_resolver.h"
|
||||
|
||||
#define W(foo) foo
|
||||
#include "core/tls.h"
|
||||
|
||||
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||
{ \
|
||||
|
@ -21,11 +17,11 @@
|
|||
sr.module_version_major = moduleVersionMajor; \
|
||||
sr.module_version_minor = moduleVersionMinor; \
|
||||
sr.type = Core::Loader::SymbolType::Function; \
|
||||
auto func = reinterpret_cast<u64>(function); \
|
||||
auto func = reinterpret_cast<u64>(HOST_CALL(function)); \
|
||||
sym->AddSymbol(sr, func); \
|
||||
}
|
||||
|
||||
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, obj) \
|
||||
{ \
|
||||
Core::Loader::SymbolResolver sr{}; \
|
||||
sr.name = nid; \
|
||||
|
@ -35,8 +31,7 @@
|
|||
sr.module_version_major = moduleVersionMajor; \
|
||||
sr.module_version_minor = moduleVersionMinor; \
|
||||
sr.type = Core::Loader::SymbolType::Object; \
|
||||
auto func = reinterpret_cast<u64>(function); \
|
||||
sym->AddSymbol(sr, func); \
|
||||
sym->AddSymbol(sr, reinterpret_cast<u64>(obj)); \
|
||||
}
|
||||
|
||||
namespace Libraries {
|
||||
|
|
|
@ -886,6 +886,7 @@ int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* pa
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
|
||||
LOG_INFO(Lib_Net, "s={} level={} optname={}", s, level, optname);
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
|
@ -954,16 +955,148 @@ u16 PS4_SYSV_ABI sceNetHtons(u16 host16) {
|
|||
return htons(host16);
|
||||
}
|
||||
|
||||
const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 size) {
|
||||
#ifdef WIN32
|
||||
const char* res = InetNtopA(af, src, dst, size);
|
||||
#else
|
||||
const char* res = inet_ntop(af, src, dst, size);
|
||||
#endif
|
||||
if (res == nullptr) {
|
||||
UNREACHABLE();
|
||||
// there isn't a strlcpy function in windows so implement one
|
||||
u64 strlcpy(char* dst, const char* src, u64 size) {
|
||||
u64 src_len = strlen(src);
|
||||
|
||||
if (size > 0) {
|
||||
u64 copy_len = (src_len >= size) ? (size - 1) : src_len;
|
||||
memcpy(dst, src, copy_len);
|
||||
dst[copy_len] = '\0';
|
||||
}
|
||||
return dst;
|
||||
|
||||
return src_len;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const char* freebsd_inet_ntop4(const char* src, char* dst, u64 size) {
|
||||
static const char fmt[] = "%u.%u.%u.%u";
|
||||
char tmp[sizeof "255.255.255.255"];
|
||||
int l;
|
||||
|
||||
l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
|
||||
if (l <= 0 || (socklen_t)l >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
strlcpy(dst, tmp, size);
|
||||
return (dst);
|
||||
}
|
||||
|
||||
const char* freebsd_inet_ntop6(const char* src, char* dst, u64 size) {
|
||||
/*
|
||||
* Note that int32_t and int16_t need only be "at least" large enough
|
||||
* to contain a value of the specified size. On some systems, like
|
||||
* Crays, there is no such thing as an integer variable with 16 bits.
|
||||
* Keep this in mind if you think this function should have been coded
|
||||
* to use pointer overlays. All the world's not a VAX.
|
||||
*/
|
||||
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
|
||||
struct {
|
||||
int base, len;
|
||||
} best, cur;
|
||||
#define NS_IN6ADDRSZ 16
|
||||
#define NS_INT16SZ 2
|
||||
u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Preprocess:
|
||||
* Copy the input (bytewise) array into a wordwise array.
|
||||
* Find the longest run of 0x00's in src[] for :: shorthanding.
|
||||
*/
|
||||
memset(words, '\0', sizeof words);
|
||||
for (i = 0; i < NS_IN6ADDRSZ; i++)
|
||||
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
|
||||
best.base = -1;
|
||||
best.len = 0;
|
||||
cur.base = -1;
|
||||
cur.len = 0;
|
||||
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
|
||||
if (words[i] == 0) {
|
||||
if (cur.base == -1)
|
||||
cur.base = i, cur.len = 1;
|
||||
else
|
||||
cur.len++;
|
||||
} else {
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
cur.base = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
}
|
||||
if (best.base != -1 && best.len < 2)
|
||||
best.base = -1;
|
||||
|
||||
/*
|
||||
* Format the result.
|
||||
*/
|
||||
tp = tmp;
|
||||
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
|
||||
/* Are we inside the best run of 0x00's? */
|
||||
if (best.base != -1 && i >= best.base && i < (best.base + best.len)) {
|
||||
if (i == best.base)
|
||||
*tp++ = ':';
|
||||
continue;
|
||||
}
|
||||
/* Are we following an initial run of 0x00s or any real hex? */
|
||||
if (i != 0)
|
||||
*tp++ = ':';
|
||||
/* Is this address an encapsulated IPv4? */
|
||||
if (i == 6 && best.base == 0 &&
|
||||
(best.len == 6 || (best.len == 7 && words[7] != 0x0001) ||
|
||||
(best.len == 5 && words[5] == 0xffff))) {
|
||||
if (!freebsd_inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
|
||||
return nullptr;
|
||||
tp += strlen(tp);
|
||||
break;
|
||||
}
|
||||
tp += sprintf(tp, "%x", words[i]);
|
||||
}
|
||||
/* Was it a trailing run of 0x00's? */
|
||||
if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ))
|
||||
*tp++ = ':';
|
||||
*tp++ = '\0';
|
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done.
|
||||
*/
|
||||
if ((u64)(tp - tmp) > size) {
|
||||
return nullptr;
|
||||
}
|
||||
strcpy(dst, tmp);
|
||||
return (dst);
|
||||
}
|
||||
const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 size) {
|
||||
if (!(src && dst)) {
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ENOSPC;
|
||||
LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC");
|
||||
return nullptr;
|
||||
}
|
||||
const char* returnvalue = nullptr;
|
||||
switch (af) {
|
||||
case ORBIS_NET_AF_INET:
|
||||
returnvalue = freebsd_inet_ntop4((const char*)src, dst, size);
|
||||
break;
|
||||
case ORBIS_NET_AF_INET6:
|
||||
returnvalue = freebsd_inet_ntop6((const char*)src, dst, size);
|
||||
break;
|
||||
default:
|
||||
*sceNetErrnoLoc() = ORBIS_NET_EAFNOSUPPORT;
|
||||
LOG_ERROR(Lib_Net, "returned ORBIS_NET_EAFNOSUPPORT");
|
||||
return nullptr;
|
||||
}
|
||||
if (returnvalue == nullptr) {
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ENOSPC;
|
||||
LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC");
|
||||
}
|
||||
return returnvalue;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetInetNtopWithScopeId() {
|
||||
|
@ -1449,6 +1582,7 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() {
|
|||
|
||||
int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
|
||||
u32 optlen) {
|
||||
LOG_INFO(Lib_Net, "s={} level={} optname={} optlen={}", s, level, optname, optlen);
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::Net {
|
||||
|
||||
enum OrbisNetFamily : u32 {
|
||||
ORBIS_NET_AF_INET = 2,
|
||||
ORBIS_NET_AF_INET6 = 28,
|
||||
};
|
||||
enum OrbisNetSocketType : u32 {
|
||||
ORBIS_NET_SOCK_STREAM = 1,
|
||||
ORBIS_NET_SOCK_DGRAM = 2,
|
||||
|
|
|
@ -10,25 +10,25 @@ namespace Libraries::Net {
|
|||
|
||||
int P2PSocket::Close() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
int P2PSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
int P2PSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::Listen(int backlog) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
|
@ -49,12 +49,12 @@ SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
|||
|
||||
int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
|
@ -143,6 +143,7 @@ static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) {
|
|||
}
|
||||
|
||||
int PosixSocket::Close() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
#ifdef _WIN32
|
||||
auto out = closesocket(sock);
|
||||
#else
|
||||
|
@ -152,17 +153,20 @@ int PosixSocket::Close() {
|
|||
}
|
||||
|
||||
int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
convertOrbisNetSockaddrToPosix(addr, &addr2);
|
||||
return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in)));
|
||||
}
|
||||
|
||||
int PosixSocket::Listen(int backlog) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return ConvertReturnErrorCode(::listen(sock, backlog));
|
||||
}
|
||||
|
||||
int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (to != nullptr) {
|
||||
sockaddr addr;
|
||||
convertOrbisNetSockaddrToPosix(to, &addr);
|
||||
|
@ -175,6 +179,7 @@ int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetS
|
|||
|
||||
int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from,
|
||||
u32* fromlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (from != nullptr) {
|
||||
sockaddr addr;
|
||||
int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen);
|
||||
|
@ -187,6 +192,7 @@ int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr*
|
|||
}
|
||||
|
||||
SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen);
|
||||
#ifdef _WIN32
|
||||
|
@ -202,12 +208,14 @@ SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
|||
}
|
||||
|
||||
int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
convertOrbisNetSockaddrToPosix(addr, &addr2);
|
||||
return ::connect(sock, &addr2, sizeof(sockaddr_in));
|
||||
}
|
||||
|
||||
int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr;
|
||||
convertOrbisNetSockaddrToPosix(name, &addr);
|
||||
if (name != nullptr) {
|
||||
|
@ -234,13 +242,15 @@ int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
|||
return 0
|
||||
|
||||
int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
level = ConvertLevels(level);
|
||||
::linger native_linger;
|
||||
if (level == SOL_SOCKET) {
|
||||
switch (optname) {
|
||||
CASE_SETSOCKOPT(SO_REUSEADDR);
|
||||
CASE_SETSOCKOPT(SO_KEEPALIVE);
|
||||
CASE_SETSOCKOPT(SO_BROADCAST);
|
||||
CASE_SETSOCKOPT(SO_LINGER);
|
||||
// CASE_SETSOCKOPT(SO_LINGER);
|
||||
CASE_SETSOCKOPT(SO_SNDBUF);
|
||||
CASE_SETSOCKOPT(SO_RCVBUF);
|
||||
CASE_SETSOCKOPT(SO_SNDTIMEO);
|
||||
|
@ -251,6 +261,24 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3
|
|||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, &sockopt_so_onesbcast);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, &sockopt_so_usecrypto);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, &sockopt_so_usesignature);
|
||||
case ORBIS_NET_SO_LINGER: {
|
||||
if (socket_type != ORBIS_NET_SOCK_STREAM) {
|
||||
return ORBIS_NET_EPROCUNAVAIL;
|
||||
}
|
||||
if (optlen < sizeof(OrbisNetLinger)) {
|
||||
LOG_ERROR(Lib_Net, "size missmatched! optlen = {} OrbisNetLinger={}", optlen,
|
||||
sizeof(OrbisNetLinger));
|
||||
return ORBIS_NET_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const void* native_val = &native_linger;
|
||||
u32 native_len = sizeof(native_linger);
|
||||
native_linger.l_onoff = reinterpret_cast<const OrbisNetLinger*>(optval)->l_onoff;
|
||||
native_linger.l_linger = reinterpret_cast<const OrbisNetLinger*>(optval)->l_linger;
|
||||
return ConvertReturnErrorCode(
|
||||
setsockopt(sock, level, SO_LINGER, (const char*)native_val, native_len));
|
||||
}
|
||||
|
||||
case ORBIS_NET_SO_NAME:
|
||||
return ORBIS_NET_ERROR_EINVAL; // don't support set for name
|
||||
case ORBIS_NET_SO_NBIO: {
|
||||
|
@ -269,7 +297,7 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3
|
|||
}
|
||||
} else if (level == IPPROTO_IP) {
|
||||
switch (optname) {
|
||||
CASE_SETSOCKOPT(IP_HDRINCL);
|
||||
// CASE_SETSOCKOPT(IP_HDRINCL);
|
||||
CASE_SETSOCKOPT(IP_TOS);
|
||||
CASE_SETSOCKOPT(IP_TTL);
|
||||
CASE_SETSOCKOPT(IP_MULTICAST_IF);
|
||||
|
@ -279,6 +307,13 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3
|
|||
CASE_SETSOCKOPT(IP_DROP_MEMBERSHIP);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, &sockopt_ip_ttlchk);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, &sockopt_ip_maxttl);
|
||||
case ORBIS_NET_IP_HDRINCL: {
|
||||
if (socket_type != ORBIS_NET_SOCK_RAW) {
|
||||
return ORBIS_NET_EPROCUNAVAIL;
|
||||
}
|
||||
return ConvertReturnErrorCode(
|
||||
setsockopt(sock, level, optname, (const char*)optval, optlen));
|
||||
}
|
||||
}
|
||||
} else if (level == IPPROTO_TCP) {
|
||||
switch (optname) {
|
||||
|
@ -311,6 +346,7 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3
|
|||
return 0;
|
||||
|
||||
int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
level = ConvertLevels(level);
|
||||
if (level == SOL_SOCKET) {
|
||||
switch (optname) {
|
||||
|
|
|
@ -32,6 +32,10 @@ struct Socket;
|
|||
|
||||
typedef std::shared_ptr<Socket> SocketPtr;
|
||||
|
||||
struct OrbisNetLinger {
|
||||
s32 l_onoff;
|
||||
s32 l_linger;
|
||||
};
|
||||
struct Socket {
|
||||
explicit Socket(int domain, int type, int protocol) {}
|
||||
virtual ~Socket() = default;
|
||||
|
@ -47,6 +51,7 @@ struct Socket {
|
|||
u32* fromlen) = 0;
|
||||
virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0;
|
||||
virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
struct PosixSocket : public Socket {
|
||||
|
@ -59,8 +64,11 @@ struct PosixSocket : public Socket {
|
|||
int sockopt_ip_ttlchk = 0;
|
||||
int sockopt_ip_maxttl = 0;
|
||||
int sockopt_tcp_mss_to_advertise = 0;
|
||||
int socket_type;
|
||||
explicit PosixSocket(int domain, int type, int protocol)
|
||||
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {}
|
||||
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {
|
||||
socket_type = type;
|
||||
}
|
||||
explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {}
|
||||
int Close() override;
|
||||
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include "sys_net.h"
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
|
@ -380,8 +380,7 @@ s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
|
|||
|
||||
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
|
||||
u32 numSpeakers) {
|
||||
LOG_ERROR(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
|
||||
unitAngle, numSpeakers);
|
||||
LOG_ERROR(Lib_Ngs2, "unitAngle = {}, numSpeakers = {}", unitAngle, numSpeakers);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
@ -10,6 +11,8 @@
|
|||
|
||||
namespace Libraries::NpManager {
|
||||
|
||||
#define SIGNEDIN_STATUS (Config::getPSNSignedIn() ? ORBIS_OK : ORBIS_NP_ERROR_SIGNED_OUT)
|
||||
|
||||
int PS4_SYSV_ABI Func_EF4378573542A508() {
|
||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
|
@ -921,9 +924,16 @@ int PS4_SYSV_ABI sceNpGetAccountCountry() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA() {
|
||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA(OrbisUserServiceUserId user_id,
|
||||
OrbisNpCountryCode* country_code) {
|
||||
LOG_INFO(Lib_NpManager, "(STUBBED) called, user_id = {}", user_id);
|
||||
if (country_code == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
::memset(country_code, 0, sizeof(OrbisNpCountryCode));
|
||||
// TODO: get NP country code from config
|
||||
::memcpy(country_code->country_code, "us", 2);
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirth() {
|
||||
|
@ -941,8 +951,8 @@ int PS4_SYSV_ABI sceNpGetAccountId(OrbisNpOnlineId* online_id, u64* account_id)
|
|||
if (online_id == nullptr || account_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*account_id = 0;
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
*account_id = 0xFEEDFACE;
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountIdA(OrbisUserServiceUserId user_id, u64* account_id) {
|
||||
|
@ -950,8 +960,8 @@ int PS4_SYSV_ABI sceNpGetAccountIdA(OrbisUserServiceUserId user_id, u64* account
|
|||
if (account_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*account_id = 0;
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
*account_id = 0xFEEDFACE;
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountLanguage() {
|
||||
|
@ -984,7 +994,9 @@ int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id)
|
|||
if (np_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
memset(np_id, 0, sizeof(OrbisNpId));
|
||||
strncpy(np_id->handle.data, Config::getUserName().c_str(), sizeof(np_id->handle.data));
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
||||
|
@ -997,7 +1009,9 @@ int PS4_SYSV_ABI sceNpGetOnlineId(OrbisUserServiceUserId user_id, OrbisNpOnlineI
|
|||
if (online_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
memset(online_id, 0, sizeof(OrbisNpOnlineId));
|
||||
strncpy(online_id->data, Config::getUserName().c_str(), sizeof(online_id->data));
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
||||
|
@ -1014,8 +1028,8 @@ int PS4_SYSV_ABI sceNpGetState(OrbisUserServiceUserId user_id, OrbisNpState* sta
|
|||
if (state == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*state = OrbisNpState::SignedOut;
|
||||
LOG_DEBUG(Lib_NpManager, "Signed out");
|
||||
*state = Config::getPSNSignedIn() ? OrbisNpState::SignedIn : OrbisNpState::SignedOut;
|
||||
LOG_DEBUG(Lib_NpManager, "Signed {}", Config::getPSNSignedIn() ? "in" : "out");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,12 @@ struct OrbisNpId {
|
|||
u8 reserved[8];
|
||||
};
|
||||
|
||||
struct OrbisNpCountryCode {
|
||||
char country_code[2];
|
||||
char end;
|
||||
char pad;
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI Func_EF4378573542A508();
|
||||
int PS4_SYSV_ABI _sceNpIpcCreateMemoryFromKernel();
|
||||
int PS4_SYSV_ABI _sceNpIpcCreateMemoryFromPool();
|
||||
|
@ -215,7 +221,8 @@ int PS4_SYSV_ABI sceNpCreateRequest();
|
|||
int PS4_SYSV_ABI sceNpDeleteRequest(int reqId);
|
||||
int PS4_SYSV_ABI sceNpGetAccountAge();
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountry();
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA(OrbisUserServiceUserId user_id,
|
||||
OrbisNpCountryCode* country_code);
|
||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirth();
|
||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirthA();
|
||||
int PS4_SYSV_ABI sceNpGetAccountId(OrbisNpOnlineId* online_id, u64* account_id);
|
||||
|
|
|
@ -206,6 +206,10 @@ s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(OrbisNpTrophyHandle handle) {
|
|||
if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE)
|
||||
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||
|
||||
if (handle >= trophy_handles.size()) {
|
||||
LOG_ERROR(Lib_NpTrophy, "Invalid handle {}", handle);
|
||||
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (!trophy_handles.is_allocated({static_cast<u32>(handle)})) {
|
||||
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
|
|
@ -316,22 +316,79 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||
pData[i].orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
if (engine) {
|
||||
pData[i].acceleration.x = states[i].acceleration.x * 0.098;
|
||||
pData[i].acceleration.y = states[i].acceleration.y * 0.098;
|
||||
pData[i].acceleration.z = states[i].acceleration.z * 0.098;
|
||||
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||
|
||||
if (engine && handle == 1) {
|
||||
const auto gyro_poll_rate = engine->GetAccelPollRate();
|
||||
if (gyro_poll_rate != 0.0f) {
|
||||
GameController::CalculateOrientation(pData[i].acceleration,
|
||||
pData[i].angularVelocity,
|
||||
1.0f / gyro_poll_rate, pData[i].orientation);
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
float deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
now - controller->GetLastUpdate())
|
||||
.count() /
|
||||
1000000.0f;
|
||||
controller->SetLastUpdate(now);
|
||||
Libraries::Pad::OrbisFQuaternion lastOrientation = controller->GetLastOrientation();
|
||||
Libraries::Pad::OrbisFQuaternion outputOrientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
deltaTime, lastOrientation, outputOrientation);
|
||||
pData[i].orientation = outputOrientation;
|
||||
controller->SetLastOrientation(outputOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
pData[i].touchData.touchNum =
|
||||
(states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0);
|
||||
|
||||
if (handle == 1) {
|
||||
if (controller->GetTouchCount() >= 127) {
|
||||
controller->SetTouchCount(0);
|
||||
}
|
||||
|
||||
if (controller->GetSecondaryTouchCount() >= 127) {
|
||||
controller->SetSecondaryTouchCount(0);
|
||||
}
|
||||
|
||||
if (pData->touchData.touchNum == 1 && controller->GetPreviousTouchNum() == 0) {
|
||||
controller->SetTouchCount(controller->GetTouchCount() + 1);
|
||||
controller->SetSecondaryTouchCount(controller->GetTouchCount());
|
||||
} else if (pData->touchData.touchNum == 2 && controller->GetPreviousTouchNum() == 1) {
|
||||
controller->SetSecondaryTouchCount(controller->GetSecondaryTouchCount() + 1);
|
||||
} else if (pData->touchData.touchNum == 0 && controller->GetPreviousTouchNum() > 0) {
|
||||
if (controller->GetTouchCount() < controller->GetSecondaryTouchCount()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
} else {
|
||||
if (controller->WasSecondaryTouchReset()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
controller->UnsetSecondaryTouchResetBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller->SetPreviousTouchNum(pData->touchData.touchNum);
|
||||
|
||||
if (pData->touchData.touchNum == 1) {
|
||||
states[i].touchpad[0].ID = controller->GetTouchCount();
|
||||
states[i].touchpad[1].ID = 0;
|
||||
} else if (pData->touchData.touchNum == 2) {
|
||||
states[i].touchpad[0].ID = controller->GetTouchCount();
|
||||
states[i].touchpad[1].ID = controller->GetSecondaryTouchCount();
|
||||
}
|
||||
} else {
|
||||
states[i].touchpad[0].ID = 1;
|
||||
states[i].touchpad[1].ID = 2;
|
||||
}
|
||||
|
||||
pData[i].touchData.touch[0].x = states[i].touchpad[0].x;
|
||||
pData[i].touchData.touch[0].y = states[i].touchpad[0].y;
|
||||
pData[i].touchData.touch[0].id = 1;
|
||||
pData[i].touchData.touch[0].id = states[i].touchpad[0].ID;
|
||||
pData[i].touchData.touch[1].x = states[i].touchpad[1].x;
|
||||
pData[i].touchData.touch[1].y = states[i].touchpad[1].y;
|
||||
pData[i].touchData.touch[1].id = 2;
|
||||
pData[i].touchData.touch[1].id = states[i].touchpad[1].ID;
|
||||
pData[i].connected = connected;
|
||||
pData[i].timestamp = states[i].time;
|
||||
pData[i].connectedCount = connected_count;
|
||||
|
@ -376,31 +433,85 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||
pData->leftStick.x = state.axes[static_cast<int>(Input::Axis::LeftX)];
|
||||
pData->leftStick.y = state.axes[static_cast<int>(Input::Axis::LeftY)];
|
||||
pData->rightStick.x = state.axes[static_cast<int>(Input::Axis::RightX)];
|
||||
pData->rightStick.x = state.axes[static_cast<int>(Input::Axis::RightX)];
|
||||
pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)];
|
||||
pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||
pData->acceleration.x = state.acceleration.x;
|
||||
pData->acceleration.y = state.acceleration.y;
|
||||
pData->acceleration.z = state.acceleration.z;
|
||||
pData->acceleration.x = state.acceleration.x * 0.098;
|
||||
pData->acceleration.y = state.acceleration.y * 0.098;
|
||||
pData->acceleration.z = state.acceleration.z * 0.098;
|
||||
pData->angularVelocity.x = state.angularVelocity.x;
|
||||
pData->angularVelocity.y = state.angularVelocity.y;
|
||||
pData->angularVelocity.z = state.angularVelocity.z;
|
||||
pData->orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
if (engine) {
|
||||
|
||||
// Only do this on handle 1 for now
|
||||
if (engine && handle == 1) {
|
||||
const auto gyro_poll_rate = engine->GetAccelPollRate();
|
||||
if (gyro_poll_rate != 0.0f) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
float deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
now - controller->GetLastUpdate())
|
||||
.count() /
|
||||
1000000.0f;
|
||||
controller->SetLastUpdate(now);
|
||||
Libraries::Pad::OrbisFQuaternion lastOrientation = controller->GetLastOrientation();
|
||||
Libraries::Pad::OrbisFQuaternion outputOrientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
1.0f / gyro_poll_rate, pData->orientation);
|
||||
deltaTime, lastOrientation, outputOrientation);
|
||||
pData->orientation = outputOrientation;
|
||||
controller->SetLastOrientation(outputOrientation);
|
||||
}
|
||||
}
|
||||
pData->touchData.touchNum =
|
||||
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
||||
|
||||
// Only do this on handle 1 for now
|
||||
if (handle == 1) {
|
||||
if (controller->GetTouchCount() >= 127) {
|
||||
controller->SetTouchCount(0);
|
||||
}
|
||||
|
||||
if (controller->GetSecondaryTouchCount() >= 127) {
|
||||
controller->SetSecondaryTouchCount(0);
|
||||
}
|
||||
|
||||
if (pData->touchData.touchNum == 1 && controller->GetPreviousTouchNum() == 0) {
|
||||
controller->SetTouchCount(controller->GetTouchCount() + 1);
|
||||
controller->SetSecondaryTouchCount(controller->GetTouchCount());
|
||||
} else if (pData->touchData.touchNum == 2 && controller->GetPreviousTouchNum() == 1) {
|
||||
controller->SetSecondaryTouchCount(controller->GetSecondaryTouchCount() + 1);
|
||||
} else if (pData->touchData.touchNum == 0 && controller->GetPreviousTouchNum() > 0) {
|
||||
if (controller->GetTouchCount() < controller->GetSecondaryTouchCount()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
} else {
|
||||
if (controller->WasSecondaryTouchReset()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
controller->UnsetSecondaryTouchResetBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller->SetPreviousTouchNum(pData->touchData.touchNum);
|
||||
|
||||
if (pData->touchData.touchNum == 1) {
|
||||
state.touchpad[0].ID = controller->GetTouchCount();
|
||||
state.touchpad[1].ID = 0;
|
||||
} else if (pData->touchData.touchNum == 2) {
|
||||
state.touchpad[0].ID = controller->GetTouchCount();
|
||||
state.touchpad[1].ID = controller->GetSecondaryTouchCount();
|
||||
}
|
||||
} else {
|
||||
state.touchpad[0].ID = 1;
|
||||
state.touchpad[1].ID = 2;
|
||||
}
|
||||
|
||||
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 = state.touchpad[0].ID;
|
||||
pData->touchData.touch[1].x = state.touchpad[1].x;
|
||||
pData->touchData.touch[1].y = state.touchpad[1].y;
|
||||
pData->touchData.touch[1].id = 2;
|
||||
pData->touchData.touch[1].id = state.touchpad[1].ID;
|
||||
pData->timestamp = state.time;
|
||||
pData->connected = true; // isConnected; //TODO fix me proper
|
||||
pData->connectedCount = 1; // connectedCount;
|
||||
|
|
|
@ -155,7 +155,7 @@ SaveDialogState::SaveDialogState(const OrbisSaveDataDialogParam& param) {
|
|||
|
||||
if (item->focusPos != FocusPos::DIRNAME) {
|
||||
this->focus_pos = item->focusPos;
|
||||
} else {
|
||||
} else if (item->focusPosDirName != nullptr) {
|
||||
this->focus_pos = item->focusPosDirName->data.to_string();
|
||||
}
|
||||
this->style = item->itemStyle;
|
||||
|
|
|
@ -10,15 +10,14 @@
|
|||
#include <utility>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <core/libraries/system/msgdialog_ui.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "boost/icl/concept/interval.hpp"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/system/msgdialog_ui.h"
|
||||
#include "save_instance.h"
|
||||
|
||||
using Common::FS::IOFile;
|
||||
|
@ -35,11 +34,12 @@ namespace Libraries::SaveData::SaveMemory {
|
|||
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
|
||||
struct SlotData {
|
||||
OrbisUserServiceUserId user_id;
|
||||
OrbisUserServiceUserId user_id{};
|
||||
std::string game_serial;
|
||||
std::filesystem::path folder_path;
|
||||
PSF sfo;
|
||||
std::vector<u8> memory_cache;
|
||||
size_t memory_cache_size{};
|
||||
};
|
||||
|
||||
static std::mutex g_slot_mtx;
|
||||
|
@ -97,7 +97,8 @@ std::filesystem::path GetSavePath(OrbisUserServiceUserId user_id, u32 slot_id,
|
|||
return SaveInstance::MakeDirSavePath(user_id, Common::ElfInfo::Instance().GameSerial(), dir);
|
||||
}
|
||||
|
||||
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial) {
|
||||
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial,
|
||||
size_t memory_size) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
|
||||
const auto save_dir = GetSavePath(user_id, slot_id, game_serial);
|
||||
|
@ -109,6 +110,7 @@ size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_
|
|||
.folder_path = save_dir,
|
||||
.sfo = {},
|
||||
.memory_cache = {},
|
||||
.memory_cache_size = memory_size,
|
||||
};
|
||||
|
||||
SaveInstance::SetupDefaultParamSFO(data.sfo, GetSaveDir(slot_id), std::string{game_serial});
|
||||
|
@ -196,9 +198,9 @@ void ReadMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
|
|||
auto& data = g_attached_slots[slot_id];
|
||||
auto& memory = data.memory_cache;
|
||||
if (memory.empty()) { // Load file
|
||||
memory.resize(data.memory_cache_size);
|
||||
IOFile f{data.folder_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read};
|
||||
if (f.IsOpen()) {
|
||||
memory.resize(f.GetSize());
|
||||
f.Seek(0);
|
||||
f.ReadSpan(std::span{memory});
|
||||
}
|
||||
|
@ -222,5 +224,4 @@ void WriteMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
|
|||
Backup::NewRequest(data.user_id, data.game_serial, GetSaveDir(slot_id),
|
||||
Backup::OrbisSaveDataEventType::__DO_NOT_SAVE);
|
||||
}
|
||||
|
||||
} // namespace Libraries::SaveData::SaveMemory
|
|
@ -4,13 +4,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "save_backup.h"
|
||||
#include "core/libraries/save_data/save_backup.h"
|
||||
|
||||
class PSF;
|
||||
|
||||
namespace Libraries::SaveData {
|
||||
using OrbisUserServiceUserId = s32;
|
||||
}
|
||||
} // namespace Libraries::SaveData
|
||||
|
||||
namespace Libraries::SaveData::SaveMemory {
|
||||
|
||||
|
@ -22,7 +22,8 @@ void PersistMemory(u32 slot_id, bool lock = true);
|
|||
std::string_view game_serial);
|
||||
|
||||
// returns the size of the save memory if exists
|
||||
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial);
|
||||
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial,
|
||||
size_t memory_size);
|
||||
|
||||
// Write the icon. Set buf to null to read the standard icon.
|
||||
void SetIcon(u32 slot_id, void* buf = nullptr, size_t buf_size = 0);
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <core/libraries/system/msgdialog_ui.h>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/cstring.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/enum.h"
|
||||
|
@ -20,7 +20,9 @@
|
|||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/save_data/savedata.h"
|
||||
#include "core/libraries/save_data/savedata_error.h"
|
||||
#include "core/libraries/system/msgdialog.h"
|
||||
#include "core/libraries/system/msgdialog_ui.h"
|
||||
#include "save_backup.h"
|
||||
#include "save_instance.h"
|
||||
#include "save_memory.h"
|
||||
|
@ -33,27 +35,6 @@ using Common::ElfInfo;
|
|||
|
||||
namespace Libraries::SaveData {
|
||||
|
||||
enum class Error : u32 {
|
||||
OK = 0,
|
||||
USER_SERVICE_NOT_INITIALIZED = 0x80960002,
|
||||
PARAMETER = 0x809F0000,
|
||||
NOT_INITIALIZED = 0x809F0001,
|
||||
OUT_OF_MEMORY = 0x809F0002,
|
||||
BUSY = 0x809F0003,
|
||||
NOT_MOUNTED = 0x809F0004,
|
||||
EXISTS = 0x809F0007,
|
||||
NOT_FOUND = 0x809F0008,
|
||||
NO_SPACE_FS = 0x809F000A,
|
||||
INTERNAL = 0x809F000B,
|
||||
MOUNT_FULL = 0x809F000C,
|
||||
BAD_MOUNTED = 0x809F000D,
|
||||
BROKEN = 0x809F000F,
|
||||
INVALID_LOGIN_USER = 0x809F0011,
|
||||
MEMORY_NOT_READY = 0x809F0012,
|
||||
BACKUP_BUSY = 0x809F0013,
|
||||
BUSY_FOR_SAVING = 0x809F0016,
|
||||
};
|
||||
|
||||
enum class OrbisSaveDataSaveDataMemoryOption : u32 {
|
||||
NONE = 0,
|
||||
SET_PARAM = 1 << 0,
|
||||
|
@ -336,7 +317,9 @@ static std::array<std::optional<SaveInstance>, 16> g_mount_slots;
|
|||
|
||||
static void initialize() {
|
||||
g_initialized = true;
|
||||
g_game_serial = ElfInfo::Instance().GameSerial();
|
||||
g_game_serial = Common::Singleton<PSF>::Instance()
|
||||
->GetString("INSTALL_DIR_SAVEDATA")
|
||||
.value_or(ElfInfo::Instance().GameSerial());
|
||||
g_fw_ver = ElfInfo::Instance().FirmwareVer();
|
||||
Backup::StartThread();
|
||||
}
|
||||
|
@ -456,7 +439,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
|
|||
LOG_INFO(Lib_SaveData, "called with invalid block size");
|
||||
}
|
||||
|
||||
const auto root_save = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir);
|
||||
const auto root_save = Config::GetSaveDataPath();
|
||||
fs::create_directories(root_save);
|
||||
const auto available = fs::space(root_save).available;
|
||||
|
||||
|
@ -1593,8 +1576,8 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
|||
}
|
||||
|
||||
try {
|
||||
size_t existed_size =
|
||||
SaveMemory::SetupSaveMemory(setupParam->userId, slot_id, g_game_serial);
|
||||
size_t existed_size = SaveMemory::SetupSaveMemory(setupParam->userId, slot_id,
|
||||
g_game_serial, setupParam->memorySize);
|
||||
if (existed_size == 0) { // Just created
|
||||
if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
|
||||
auto& sfo = SaveMemory::GetParamSFO(slot_id);
|
||||
|
|
27
src/core/libraries/save_data/savedata_error.h
Normal file
27
src/core/libraries/save_data/savedata_error.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Libraries::SaveData {
|
||||
enum class Error : u32 {
|
||||
OK = 0,
|
||||
USER_SERVICE_NOT_INITIALIZED = 0x80960002,
|
||||
PARAMETER = 0x809F0000,
|
||||
NOT_INITIALIZED = 0x809F0001,
|
||||
OUT_OF_MEMORY = 0x809F0002,
|
||||
BUSY = 0x809F0003,
|
||||
NOT_MOUNTED = 0x809F0004,
|
||||
EXISTS = 0x809F0007,
|
||||
NOT_FOUND = 0x809F0008,
|
||||
NO_SPACE_FS = 0x809F000A,
|
||||
INTERNAL = 0x809F000B,
|
||||
MOUNT_FULL = 0x809F000C,
|
||||
BAD_MOUNTED = 0x809F000D,
|
||||
BROKEN = 0x809F000F,
|
||||
INVALID_LOGIN_USER = 0x809F0011,
|
||||
MEMORY_NOT_READY = 0x809F0012,
|
||||
BACKUP_BUSY = 0x809F0013,
|
||||
BUSY_FOR_SAVING = 0x809F0016,
|
||||
};
|
||||
} // namespace Libraries::SaveData
|
|
@ -17,10 +17,12 @@ int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInf
|
|||
LOG_INFO(Lib_Videodec, "called");
|
||||
|
||||
if (!pCfgInfoIn || !pRsrcInfoIn || !pCtrlOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) ||
|
||||
pRsrcInfoIn->thisSize != sizeof(OrbisVideodecResourceInfo)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -37,15 +39,18 @@ int PS4_SYSV_ABI sceVideodecDecode(OrbisVideodecCtrl* pCtrlIn,
|
|||
OrbisVideodecPictureInfo* pPictureInfoOut) {
|
||||
LOG_TRACE(Lib_Videodec, "called");
|
||||
if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pCtrlIn->thisSize != sizeof(OrbisVideodecCtrl) ||
|
||||
pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
|
||||
return ORBIS_VIDEODEC_ERROR_HANDLE;
|
||||
}
|
||||
return decoder->Decode(*pInputDataIn, *pFrameBufferInOut, *pPictureInfoOut);
|
||||
|
@ -56,6 +61,7 @@ int PS4_SYSV_ABI sceVideodecDeleteDecoder(OrbisVideodecCtrl* pCtrlIn) {
|
|||
|
||||
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
|
||||
return ORBIS_VIDEODEC_ERROR_HANDLE;
|
||||
}
|
||||
delete decoder;
|
||||
|
@ -68,15 +74,18 @@ int PS4_SYSV_ABI sceVideodecFlush(OrbisVideodecCtrl* pCtrlIn,
|
|||
LOG_INFO(Lib_Videodec, "called");
|
||||
|
||||
if (!pFrameBufferInOut || !pPictureInfoOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer) ||
|
||||
pPictureInfoOut->thisSize != sizeof(OrbisVideodecPictureInfo)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
|
||||
return ORBIS_VIDEODEC_ERROR_HANDLE;
|
||||
}
|
||||
return decoder->Flush(*pFrameBufferInOut, *pPictureInfoOut);
|
||||
|
@ -92,10 +101,12 @@ int PS4_SYSV_ABI sceVideodecQueryResourceInfo(const OrbisVideodecConfigInfo* pCf
|
|||
LOG_INFO(Lib_Videodec, "called");
|
||||
|
||||
if (!pCfgInfoIn || !pRsrcInfoOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) ||
|
||||
pRsrcInfoOut->thisSize != sizeof(OrbisVideodecResourceInfo)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,11 @@ sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemIn
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!computeMemInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -47,10 +49,12 @@ sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decode
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoderCfgInfo || !decoderMemInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
|
||||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -74,10 +78,12 @@ s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoderCfgInfo || !decoderMemInfo || !decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
|
||||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -89,6 +95,7 @@ s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) {
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
|
||||
|
@ -103,13 +110,16 @@ s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
|
|||
LOG_TRACE(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
if (!inputData || !frameBuffer || !outputInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (inputData->thisSize != sizeof(OrbisVideodec2InputData) ||
|
||||
frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -122,13 +132,16 @@ s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
if (!frameBuffer || !outputInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
|
||||
outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -139,6 +152,7 @@ s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) {
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
|
||||
|
@ -150,12 +164,15 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
|
|||
LOG_TRACE(Lib_Vdec2, "called");
|
||||
|
||||
if (!outputInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) {
|
||||
LOG_ERROR(Lib_Vdec2, "No picture info available");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -163,6 +180,7 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
|
|||
OrbisVideodec2AvcPictureInfo* picInfo =
|
||||
static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut);
|
||||
if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
*picInfo = gPictureInfos.back();
|
||||
|
|
|
@ -282,7 +282,12 @@ s32 PS4_SYSV_ABI sceVideoOutGetVblankStatus(int handle, SceVideoOutVblankStatus*
|
|||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status) {
|
||||
LOG_INFO(Lib_VideoOut, "called");
|
||||
*status = driver->GetPort(handle)->resolution;
|
||||
auto* port = driver->GetPort(handle);
|
||||
if (!port || !port->is_open) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
*status = port->resolution;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
203
src/core/libraries/voice/voice.cpp
Normal file
203
src/core/libraries/voice/voice.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/voice/voice.h"
|
||||
|
||||
namespace Libraries::Voice {
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceConnectIPortToOPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceCreatePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceDeletePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceDisconnectIPortFromOPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceEnd() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetBitRate(u32 port_id, u32* bitrate) {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
*bitrate = 48000;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetMuteFlag() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortAttr() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortInfo(u32 port_id, OrbisVoicePortInfo* info) {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
info->port_type = 0;
|
||||
info->state = 3;
|
||||
info->byte_count = 0;
|
||||
info->frame_size = 1;
|
||||
info->edge_count = 0;
|
||||
info->reserved = 0;
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetResourceInfo() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetVolume() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceInit() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceInitHQ() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoicePausePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoicePausePortAll() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceReadFromOPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceResetPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePortAll() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetBitRate() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlag() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlagAll() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetThreadsParams() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetVolume() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceStart() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceStop() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceUpdatePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceVADAdjustment() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceVADSetVersion() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceWriteToIPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceVoice(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("oV9GAdJ23Gw", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceConnectIPortToOPort);
|
||||
LIB_FUNCTION("nXpje5yNpaE", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceCreatePort);
|
||||
LIB_FUNCTION("b7kJI+nx2hg", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceDeletePort);
|
||||
LIB_FUNCTION("ajVj3QG2um4", "libSceVoice", 1, "libSceVoice", 0, 0,
|
||||
sceVoiceDisconnectIPortFromOPort);
|
||||
LIB_FUNCTION("Oo0S5PH7FIQ", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceEnd);
|
||||
LIB_FUNCTION("cJLufzou6bc", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetBitRate);
|
||||
LIB_FUNCTION("Pc4z1QjForU", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetMuteFlag);
|
||||
LIB_FUNCTION("elcxZTEfHZM", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetPortAttr);
|
||||
LIB_FUNCTION("CrLqDwWLoXM", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetPortInfo);
|
||||
LIB_FUNCTION("Z6QV6j7igvE", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetResourceInfo);
|
||||
LIB_FUNCTION("jjkCjneOYSs", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetVolume);
|
||||
LIB_FUNCTION("9TrhuGzberQ", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceInit);
|
||||
LIB_FUNCTION("IPHvnM5+g04", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceInitHQ);
|
||||
LIB_FUNCTION("x0slGBQW+wY", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoicePausePort);
|
||||
LIB_FUNCTION("Dinob0yMRl8", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoicePausePortAll);
|
||||
LIB_FUNCTION("cQ6DGsQEjV4", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceReadFromOPort);
|
||||
LIB_FUNCTION("udAxvCePkUs", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceResetPort);
|
||||
LIB_FUNCTION("gAgN+HkiEzY", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceResumePort);
|
||||
LIB_FUNCTION("jbkJFmOZ9U0", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceResumePortAll);
|
||||
LIB_FUNCTION("TexwmOHQsDg", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetBitRate);
|
||||
LIB_FUNCTION("gwUynkEgNFY", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetMuteFlag);
|
||||
LIB_FUNCTION("oUha0S-Ij9Q", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetMuteFlagAll);
|
||||
LIB_FUNCTION("clyKUyi3RYU", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetThreadsParams);
|
||||
LIB_FUNCTION("QBFoAIjJoXQ", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetVolume);
|
||||
LIB_FUNCTION("54phPH2LZls", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceStart);
|
||||
LIB_FUNCTION("Ao2YNSA7-Qo", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceStop);
|
||||
LIB_FUNCTION("jSZNP7xJrcw", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceUpdatePort);
|
||||
LIB_FUNCTION("hg9T73LlRiU", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceVADAdjustment);
|
||||
LIB_FUNCTION("wFeAxEeEi-8", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceVADSetVersion);
|
||||
LIB_FUNCTION("YeJl6yDlhW0", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceWriteToIPort);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Voice
|
56
src/core/libraries/voice/voice.h
Normal file
56
src/core/libraries/voice/voice.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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::Voice {
|
||||
|
||||
struct OrbisVoicePortInfo {
|
||||
s32 port_type;
|
||||
s32 state;
|
||||
u32* edge;
|
||||
u32 byte_count;
|
||||
u32 frame_size;
|
||||
u16 edge_count;
|
||||
u16 reserved;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceConnectIPortToOPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceCreatePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceDeletePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceDisconnectIPortFromOPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceEnd();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetBitRate(u32 port_id, u32* bitrate);
|
||||
s32 PS4_SYSV_ABI sceVoiceGetMuteFlag();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortAttr();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortInfo(u32 port_id, OrbisVoicePortInfo* info);
|
||||
s32 PS4_SYSV_ABI sceVoiceGetResourceInfo();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetVolume();
|
||||
s32 PS4_SYSV_ABI sceVoiceInit();
|
||||
s32 PS4_SYSV_ABI sceVoiceInitHQ();
|
||||
s32 PS4_SYSV_ABI sceVoicePausePort();
|
||||
s32 PS4_SYSV_ABI sceVoicePausePortAll();
|
||||
s32 PS4_SYSV_ABI sceVoiceReadFromOPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceResetPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePortAll();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetBitRate();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlag();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlagAll();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetThreadsParams();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetVolume();
|
||||
s32 PS4_SYSV_ABI sceVoiceStart();
|
||||
s32 PS4_SYSV_ABI sceVoiceStop();
|
||||
s32 PS4_SYSV_ABI sceVoiceUpdatePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceVADAdjustment();
|
||||
s32 PS4_SYSV_ABI sceVoiceVADSetVersion();
|
||||
s32 PS4_SYSV_ABI sceVoiceWriteToIPort();
|
||||
|
||||
void RegisterlibSceVoice(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Voice
|
|
@ -51,7 +51,7 @@ void ZlibTaskThread(const std::stop_token& stop) {
|
|||
if (!task_queue_cv.wait(lock, stop, [&] { return !task_queue.empty(); })) {
|
||||
break;
|
||||
}
|
||||
task = task_queue.back();
|
||||
task = task_queue.front();
|
||||
task_queue.pop();
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout) {
|
|||
} else {
|
||||
done_queue_cv.wait(lock, pred);
|
||||
}
|
||||
*request_id = done_queue.back();
|
||||
*request_id = done_queue.front();
|
||||
done_queue.pop();
|
||||
}
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "common/thread.h"
|
||||
#include "core/aerolib/aerolib.h"
|
||||
#include "core/aerolib/stubs.h"
|
||||
#include "core/devtools/widget/module_list.h"
|
||||
#include "core/libraries/kernel/memory.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/linker.h"
|
||||
|
@ -116,6 +117,18 @@ void Linker::Execute(const std::vector<std::string> args) {
|
|||
Common::SetCurrentThreadName("GAME_MainThread");
|
||||
LoadSharedLibraries();
|
||||
|
||||
// Simulate libSceGnmDriver initialization, which maps a chunk of direct memory.
|
||||
// Some games fail without accurately emulating this behavior.
|
||||
s64 phys_addr{};
|
||||
s32 result = Libraries::Kernel::sceKernelAllocateDirectMemory(
|
||||
0, Libraries::Kernel::sceKernelGetDirectMemorySize(), 0x10000, 0x10000, 3, &phys_addr);
|
||||
if (result == 0) {
|
||||
void* addr{reinterpret_cast<void*>(0xfe0000000)};
|
||||
result = Libraries::Kernel::sceKernelMapNamedDirectMemory(
|
||||
&addr, 0x10000, 0x13, 0, phys_addr, 0x10000, "SceGnmDriver");
|
||||
}
|
||||
ASSERT_MSG(result == 0, "Unable to emulate libSceGnmDriver initialization");
|
||||
|
||||
// Start main module.
|
||||
EntryParams params{};
|
||||
params.argc = 1;
|
||||
|
@ -127,7 +140,7 @@ void Linker::Execute(const std::vector<std::string> args) {
|
|||
}
|
||||
}
|
||||
params.entry_addr = module->GetEntryAddress();
|
||||
RunMainEntry(¶ms);
|
||||
ExecuteGuest(RunMainEntry, ¶ms);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -147,6 +160,9 @@ s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
|
|||
|
||||
num_static_modules += !is_dynamic;
|
||||
m_modules.emplace_back(std::move(module));
|
||||
|
||||
Core::Devtools::Widget::ModuleList::AddModule(elf_name.filename().string(), elf_name);
|
||||
|
||||
return m_modules.size() - 1;
|
||||
}
|
||||
|
||||
|
@ -325,6 +341,9 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
|
|||
}
|
||||
if (record) {
|
||||
*return_info = *record;
|
||||
|
||||
Core::Devtools::Widget::ModuleList::AddModule(sr.library);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -366,7 +385,8 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
|||
if (!addr) {
|
||||
// Module was just loaded by above code. Allocate TLS block for it.
|
||||
const u32 init_image_size = module->tls.init_image_size;
|
||||
u8* dest = reinterpret_cast<u8*>(heap_api->heap_malloc(module->tls.image_size));
|
||||
u8* dest = reinterpret_cast<u8*>(
|
||||
Core::ExecuteGuest(heap_api->heap_malloc, module->tls.image_size));
|
||||
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
||||
std::memcpy(dest, src, init_image_size);
|
||||
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/debug.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/kernel/memory.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
#include "core/libraries/kernel/process.h"
|
||||
|
@ -67,7 +68,7 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1
|
|||
}
|
||||
|
||||
u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
|
||||
static constexpr u64 MinSizeToClamp = 512_MB;
|
||||
static constexpr u64 MinSizeToClamp = 2_MB;
|
||||
// Dont bother with clamping if the size is small so we dont pay a map lookup on every buffer.
|
||||
if (size < MinSizeToClamp) {
|
||||
return size;
|
||||
|
@ -109,31 +110,42 @@ bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_byt
|
|||
|
||||
PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) {
|
||||
std::scoped_lock lk{mutex};
|
||||
alignment = alignment > 0 ? alignment : 64_KB;
|
||||
|
||||
auto dmem_area = FindDmemArea(search_start);
|
||||
auto mapping_start = search_start > dmem_area->second.base
|
||||
? Common::AlignUp(search_start, alignment)
|
||||
: Common::AlignUp(dmem_area->second.base, alignment);
|
||||
auto mapping_end = mapping_start + size;
|
||||
|
||||
const auto is_suitable = [&] {
|
||||
const auto aligned_base = alignment > 0 ? Common::AlignUp(dmem_area->second.base, alignment)
|
||||
: dmem_area->second.base;
|
||||
const auto alignment_size = aligned_base - dmem_area->second.base;
|
||||
const auto remaining_size =
|
||||
dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0;
|
||||
return dmem_area->second.is_free && remaining_size >= size;
|
||||
};
|
||||
while (!is_suitable() && dmem_area->second.GetEnd() <= search_end) {
|
||||
// Find the first free, large enough dmem area in the range.
|
||||
while (!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) {
|
||||
// The current dmem_area isn't suitable, move to the next one.
|
||||
dmem_area++;
|
||||
}
|
||||
ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size);
|
||||
if (dmem_area == dmem_map.end()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Align free position
|
||||
PAddr free_addr = dmem_area->second.base;
|
||||
free_addr = alignment > 0 ? Common::AlignUp(free_addr, alignment) : free_addr;
|
||||
// Update local variables based on the new dmem_area
|
||||
mapping_start = Common::AlignUp(dmem_area->second.base, alignment);
|
||||
mapping_end = mapping_start + size;
|
||||
}
|
||||
|
||||
if (dmem_area == dmem_map.end()) {
|
||||
// There are no suitable mappings in this range
|
||||
LOG_ERROR(Kernel_Vmm, "Unable to find free direct memory area: size = {:#x}", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add the allocated region to the list and commit its pages.
|
||||
auto& area = CarveDmemArea(free_addr, size)->second;
|
||||
auto& area = CarveDmemArea(mapping_start, size)->second;
|
||||
area.is_free = false;
|
||||
area.is_pooled = true;
|
||||
return free_addr;
|
||||
|
||||
// Track how much dmem was allocated for pools.
|
||||
pool_budget += size;
|
||||
|
||||
return mapping_start;
|
||||
}
|
||||
|
||||
PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
|
||||
|
@ -170,6 +182,7 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
|
|||
auto& area = CarveDmemArea(mapping_start, size)->second;
|
||||
area.memory_type = memory_type;
|
||||
area.is_free = false;
|
||||
MergeAdjacent(dmem_map, dmem_area);
|
||||
return mapping_start;
|
||||
}
|
||||
|
||||
|
@ -203,123 +216,52 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
|
|||
MergeAdjacent(dmem_map, dmem_area);
|
||||
}
|
||||
|
||||
int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size,
|
||||
MemoryMapFlags flags, u64 alignment) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
alignment = alignment > 0 ? alignment : 2_MB;
|
||||
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
|
||||
|
||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
auto& vma = FindVMA(mapped_addr)->second;
|
||||
// If the VMA is mapped, unmap the region first.
|
||||
if (vma.IsMapped()) {
|
||||
UnmapMemoryImpl(mapped_addr, size);
|
||||
vma = FindVMA(mapped_addr)->second;
|
||||
}
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size,
|
||||
"Memory region {:#x} to {:#x} is not large enough to reserve {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
}
|
||||
|
||||
// Find the first free area starting with provided virtual address.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
mapped_addr = SearchFree(mapped_addr, size, alignment);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// Add virtual memory area
|
||||
const auto new_vma_handle = CarveVMA(mapped_addr, size);
|
||||
auto& new_vma = new_vma_handle->second;
|
||||
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||
new_vma.prot = MemoryProt::NoAccess;
|
||||
new_vma.name = "anon";
|
||||
new_vma.type = VMAType::PoolReserved;
|
||||
MergeAdjacent(vma_map, new_vma_handle);
|
||||
|
||||
*out_addr = std::bit_cast<void*>(mapped_addr);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags,
|
||||
u64 alignment) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
alignment = alignment > 0 ? alignment : 16_KB;
|
||||
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
|
||||
|
||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
auto vma = FindVMA(mapped_addr)->second;
|
||||
// If the VMA is mapped, unmap the region first.
|
||||
if (vma.IsMapped()) {
|
||||
UnmapMemoryImpl(mapped_addr, size);
|
||||
vma = FindVMA(mapped_addr)->second;
|
||||
}
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size,
|
||||
"Memory region {:#x} to {:#x} is not large enough to reserve {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
}
|
||||
|
||||
// Find the first free area starting with provided virtual address.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
mapped_addr = SearchFree(mapped_addr, size, alignment);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// Add virtual memory area
|
||||
const auto new_vma_handle = CarveVMA(mapped_addr, size);
|
||||
auto& new_vma = new_vma_handle->second;
|
||||
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||
new_vma.prot = MemoryProt::NoAccess;
|
||||
new_vma.name = "anon";
|
||||
new_vma.type = VMAType::Reserved;
|
||||
MergeAdjacent(vma_map, new_vma_handle);
|
||||
|
||||
*out_addr = std::bit_cast<void*>(mapped_addr);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
const u64 alignment = 64_KB;
|
||||
|
||||
// When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed
|
||||
// flag so we will take the branch that searches for free (or reserved) mappings.
|
||||
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
// Input addresses to PoolCommit are treated as fixed.
|
||||
VAddr mapped_addr = Common::AlignUp(virtual_addr, alignment);
|
||||
|
||||
// This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen.
|
||||
const auto& vma = FindVMA(mapped_addr)->second;
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size,
|
||||
"Memory region {:#x} to {:#x} isn't free enough to map region {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
auto& vma = FindVMA(mapped_addr)->second;
|
||||
if (vma.type != VMAType::PoolReserved) {
|
||||
// If we're attempting to commit non-pooled memory, return EINVAL
|
||||
LOG_ERROR(Kernel_Vmm, "Attempting to commit non-pooled memory at {:#x}", mapped_addr);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
// Perform the mapping.
|
||||
void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false);
|
||||
TRACK_ALLOC(out_addr, size, "VMEM");
|
||||
if (!vma.Contains(mapped_addr, size)) {
|
||||
// If there's not enough space to commit, return EINVAL
|
||||
LOG_ERROR(Kernel_Vmm,
|
||||
"Pooled region {:#x} to {:#x} is not large enough to commit from {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, mapped_addr, mapped_addr + size);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
auto& new_vma = CarveVMA(mapped_addr, size)->second;
|
||||
if (pool_budget <= size) {
|
||||
// If there isn't enough pooled memory to perform the mapping, return ENOMEM
|
||||
LOG_ERROR(Kernel_Vmm, "Not enough pooled memory to perform mapping");
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
} else {
|
||||
// Track how much pooled memory this commit will take
|
||||
pool_budget -= size;
|
||||
}
|
||||
|
||||
// Carve out the new VMA representing this mapping
|
||||
const auto new_vma_handle = CarveVMA(mapped_addr, size);
|
||||
auto& new_vma = new_vma_handle->second;
|
||||
new_vma.disallow_merge = false;
|
||||
new_vma.prot = prot;
|
||||
new_vma.name = "";
|
||||
new_vma.name = "anon";
|
||||
new_vma.type = Core::VMAType::Pooled;
|
||||
new_vma.is_exec = false;
|
||||
new_vma.phys_base = 0;
|
||||
|
||||
// Perform the mapping
|
||||
void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false);
|
||||
TRACK_ALLOC(out_addr, size, "VMEM");
|
||||
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
|
@ -327,7 +269,7 @@ int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot)
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||
s32 MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, u64 size, MemoryProt prot,
|
||||
MemoryMapFlags flags, VMAType type, std::string_view name,
|
||||
bool is_exec, PAddr phys_addr, u64 alignment) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
@ -338,37 +280,39 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
|
|||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
// When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed
|
||||
// flag so we will take the branch that searches for free (or reserved) mappings.
|
||||
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
alignment = alignment > 0 ? alignment : 16_KB;
|
||||
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
|
||||
// Limit the minumum address to SystemManagedVirtualBase to prevent hardware-specific issues.
|
||||
VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
|
||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
// On a PS4, the Fixed flag is ignored if address 0 is provided.
|
||||
if (True(flags & MemoryMapFlags::Fixed) && virtual_addr != 0) {
|
||||
auto vma = FindVMA(mapped_addr)->second;
|
||||
size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
// There's a possible edge case where we're mapping to a partially reserved range.
|
||||
// To account for this, unmap any reserved areas within this mapping range first.
|
||||
auto unmap_addr = mapped_addr;
|
||||
auto unmap_size = size;
|
||||
while (!vma.IsMapped() && unmap_addr < mapped_addr + size && remaining_size < size) {
|
||||
|
||||
// If flag NoOverwrite is provided, don't overwrite mapped VMAs.
|
||||
// When it isn't provided, VMAs can be overwritten regardless of if they're mapped.
|
||||
while ((False(flags & MemoryMapFlags::NoOverwrite) || !vma.IsMapped()) &&
|
||||
unmap_addr < mapped_addr + size) {
|
||||
auto unmapped = UnmapBytesFromEntry(unmap_addr, vma, unmap_size);
|
||||
unmap_addr += unmapped;
|
||||
unmap_size -= unmapped;
|
||||
vma = FindVMA(unmap_addr)->second;
|
||||
}
|
||||
|
||||
// This should return SCE_KERNEL_ERROR_ENOMEM but rarely happens.
|
||||
vma = FindVMA(mapped_addr)->second;
|
||||
remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size,
|
||||
"Memory region {:#x} to {:#x} isn't free enough to map region {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
}
|
||||
|
||||
// Find the first free area starting with provided virtual address.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
auto remaining_size = vma.base + vma.size - mapped_addr;
|
||||
if (vma.IsMapped() || remaining_size < size) {
|
||||
LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at address {:#x}", size, mapped_addr);
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
} else {
|
||||
// When MemoryMapFlags::Fixed is not specified, and mapped_addr is 0,
|
||||
// search from address 0x200000000 instead.
|
||||
alignment = alignment > 0 ? alignment : 16_KB;
|
||||
mapped_addr = virtual_addr == 0 ? 0x200000000 : mapped_addr;
|
||||
mapped_addr = SearchFree(mapped_addr, size, alignment);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
|
@ -376,33 +320,48 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
|
|||
}
|
||||
}
|
||||
|
||||
// Perform the mapping.
|
||||
*out_addr = impl.Map(mapped_addr, size, alignment, phys_addr, is_exec);
|
||||
TRACK_ALLOC(*out_addr, size, "VMEM");
|
||||
// Create a memory area representing this mapping.
|
||||
const auto new_vma_handle = CarveVMA(mapped_addr, size);
|
||||
auto& new_vma = new_vma_handle->second;
|
||||
|
||||
auto& new_vma = CarveVMA(mapped_addr, size)->second;
|
||||
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||
new_vma.prot = prot;
|
||||
new_vma.name = name;
|
||||
new_vma.type = type;
|
||||
new_vma.is_exec = is_exec;
|
||||
|
||||
if (type == VMAType::Direct) {
|
||||
new_vma.phys_base = phys_addr;
|
||||
}
|
||||
// If type is Flexible, we need to track how much flexible memory is used here.
|
||||
if (type == VMAType::Flexible) {
|
||||
flexible_usage += size;
|
||||
}
|
||||
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||
new_vma.prot = prot;
|
||||
new_vma.name = name;
|
||||
new_vma.type = type;
|
||||
new_vma.phys_base = phys_addr == -1 ? 0 : phys_addr;
|
||||
new_vma.is_exec = is_exec;
|
||||
|
||||
if (type == VMAType::Reserved) {
|
||||
// Technically this should be done for direct and flexible mappings too,
|
||||
// But some Windows-specific limitations make that hard to accomplish.
|
||||
MergeAdjacent(vma_map, new_vma_handle);
|
||||
}
|
||||
|
||||
if (type == VMAType::Reserved || type == VMAType::PoolReserved) {
|
||||
// For Reserved/PoolReserved mappings, we don't perform any address space allocations.
|
||||
// Just set out_addr to mapped_addr instead.
|
||||
*out_addr = std::bit_cast<void*>(mapped_addr);
|
||||
} else {
|
||||
// If this is not a reservation, then map to GPU and address space
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
*out_addr = impl.Map(mapped_addr, size, alignment, phys_addr, is_exec);
|
||||
}
|
||||
|
||||
TRACK_ALLOC(*out_addr, size, "VMEM");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||
MemoryMapFlags flags, uintptr_t fd, size_t offset) {
|
||||
s32 MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, u64 size, MemoryProt prot,
|
||||
MemoryMapFlags flags, s32 fd, s64 phys_addr) {
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
|
||||
VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
const size_t size_aligned = Common::AlignUp(size, 16_KB);
|
||||
|
||||
|
@ -423,8 +382,19 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
}
|
||||
|
||||
// Map the file.
|
||||
impl.MapFile(mapped_addr, size_aligned, offset, std::bit_cast<u32>(prot), fd);
|
||||
// Get the file to map
|
||||
auto file = h->GetFile(fd);
|
||||
if (file == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
const auto handle = file->f.GetFileMapping();
|
||||
|
||||
impl.MapFile(mapped_addr, size_aligned, phys_addr, std::bit_cast<u32>(prot), handle);
|
||||
|
||||
if (prot >= MemoryProt::GpuRead) {
|
||||
ASSERT_MSG(false, "Files cannot be mapped to GPU memory");
|
||||
}
|
||||
|
||||
// Add virtual memory area
|
||||
auto& new_vma = CarveVMA(mapped_addr, size_aligned)->second;
|
||||
|
@ -438,7 +408,7 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
||||
s32 MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
const auto it = FindVMA(virtual_addr);
|
||||
|
@ -453,8 +423,19 @@ void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
|||
const auto start_in_vma = virtual_addr - vma_base_addr;
|
||||
const auto type = vma_base.type;
|
||||
|
||||
if (IsValidGpuMapping(virtual_addr, size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
if (type != VMAType::PoolReserved && type != VMAType::Pooled) {
|
||||
LOG_ERROR(Kernel_Vmm, "Attempting to decommit non-pooled memory!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (type == VMAType::Pooled) {
|
||||
// We always map PoolCommitted memory to GPU, so unmap when decomitting.
|
||||
if (IsValidGpuMapping(virtual_addr, size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
}
|
||||
|
||||
// Track how much pooled memory is decommitted
|
||||
pool_budget += size;
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
|
@ -464,13 +445,17 @@ void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
|||
vma.prot = MemoryProt::NoAccess;
|
||||
vma.phys_base = 0;
|
||||
vma.disallow_merge = false;
|
||||
vma.name = "";
|
||||
vma.name = "anon";
|
||||
MergeAdjacent(vma_map, new_it);
|
||||
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base, is_exec,
|
||||
false, false);
|
||||
TRACK_FREE(virtual_addr, "VMEM");
|
||||
if (type != VMAType::PoolReserved) {
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
|
||||
is_exec, false, false);
|
||||
TRACK_FREE(virtual_addr, "VMEM");
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
||||
|
@ -488,18 +473,16 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma
|
|||
const auto adjusted_size =
|
||||
vma_base_size - start_in_vma < size ? vma_base_size - start_in_vma : size;
|
||||
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
||||
const auto prot = vma_base.prot;
|
||||
|
||||
if (type == VMAType::Free) {
|
||||
return adjusted_size;
|
||||
}
|
||||
|
||||
if (type == VMAType::Flexible) {
|
||||
flexible_usage -= adjusted_size;
|
||||
}
|
||||
|
||||
if (IsValidGpuMapping(virtual_addr, adjusted_size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, adjusted_size);
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
const auto new_it = CarveVMA(virtual_addr, adjusted_size);
|
||||
auto& vma = new_it->second;
|
||||
|
@ -512,6 +495,11 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma
|
|||
auto& post_merge_vma = post_merge_it->second;
|
||||
bool readonly_file = post_merge_vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
||||
if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
|
||||
// If this mapping has GPU access, unmap from GPU.
|
||||
if (IsValidGpuMapping(virtual_addr, size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
}
|
||||
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + adjusted_size,
|
||||
phys_base, is_exec, has_backing, readonly_file);
|
||||
|
@ -565,20 +553,8 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
|
|||
vma_base.size - start_in_vma < size ? vma_base.size - start_in_vma : size;
|
||||
|
||||
if (vma_base.type == VMAType::Free) {
|
||||
LOG_ERROR(Kernel_Vmm, "Cannot change protection on free memory region");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
// Validate protection flags
|
||||
constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead |
|
||||
MemoryProt::CpuReadWrite | MemoryProt::GpuRead |
|
||||
MemoryProt::GpuWrite | MemoryProt::GpuReadWrite;
|
||||
|
||||
MemoryProt invalid_flags = prot & ~valid_flags;
|
||||
if (u32(invalid_flags) != 0 && u32(invalid_flags) != u32(MemoryProt::NoAccess)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Invalid protection flags: prot = {:#x}, invalid flags = {:#x}",
|
||||
u32(prot), u32(invalid_flags));
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
// On PS4, protecting freed memory does nothing.
|
||||
return adjusted_size;
|
||||
}
|
||||
|
||||
// Change protection
|
||||
|
@ -610,20 +586,38 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
|
|||
|
||||
s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
// Validate protection flags
|
||||
constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead |
|
||||
MemoryProt::CpuReadWrite | MemoryProt::GpuRead |
|
||||
MemoryProt::GpuWrite | MemoryProt::GpuReadWrite;
|
||||
|
||||
MemoryProt invalid_flags = prot & ~valid_flags;
|
||||
if (invalid_flags != MemoryProt::NoAccess) {
|
||||
LOG_ERROR(Kernel_Vmm, "Invalid protection flags");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
// Align addr and size to the nearest page boundary.
|
||||
auto aligned_addr = Common::AlignDown(addr, 16_KB);
|
||||
auto aligned_size = Common::AlignUp(size + addr - aligned_addr, 16_KB);
|
||||
|
||||
// Protect all VMAs between aligned_addr and aligned_addr + aligned_size.
|
||||
s64 protected_bytes = 0;
|
||||
do {
|
||||
auto it = FindVMA(addr + protected_bytes);
|
||||
while (protected_bytes < aligned_size) {
|
||||
auto it = FindVMA(aligned_addr + protected_bytes);
|
||||
auto& vma_base = it->second;
|
||||
ASSERT_MSG(vma_base.Contains(addr + protected_bytes, 0), "Address {:#x} is out of bounds",
|
||||
addr + protected_bytes);
|
||||
auto result = 0;
|
||||
result = ProtectBytes(addr + protected_bytes, vma_base, size - protected_bytes, prot);
|
||||
result = ProtectBytes(aligned_addr + protected_bytes, vma_base,
|
||||
aligned_size - protected_bytes, prot);
|
||||
if (result < 0) {
|
||||
// ProtectBytes returned an error, return it
|
||||
return result;
|
||||
}
|
||||
protected_bytes += result;
|
||||
} while (protected_bytes < size);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -741,12 +735,44 @@ int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, si
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) {
|
||||
auto it = FindVMA(virtual_addr);
|
||||
s32 MemoryManager::SetDirectMemoryType(s64 phys_addr, s32 memory_type) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
ASSERT_MSG(it->second.Contains(virtual_addr, size),
|
||||
"Range provided is not fully contained in vma");
|
||||
it->second.name = name;
|
||||
auto& dmem_area = FindDmemArea(phys_addr)->second;
|
||||
|
||||
ASSERT_MSG(phys_addr <= dmem_area.GetEnd() && !dmem_area.is_free,
|
||||
"Direct memory area is not mapped");
|
||||
|
||||
dmem_area.memory_type = memory_type;
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void MemoryManager::NameVirtualRange(VAddr virtual_addr, u64 size, std::string_view name) {
|
||||
// Sizes are aligned up to the nearest 16_KB
|
||||
auto aligned_size = Common::AlignUp(size, 16_KB);
|
||||
// Addresses are aligned down to the nearest 16_KB
|
||||
auto aligned_addr = Common::AlignDown(virtual_addr, 16_KB);
|
||||
|
||||
auto it = FindVMA(aligned_addr);
|
||||
s64 remaining_size = aligned_size;
|
||||
auto current_addr = aligned_addr;
|
||||
while (remaining_size > 0) {
|
||||
// Nothing needs to be done to free VMAs
|
||||
if (!it->second.IsFree()) {
|
||||
if (remaining_size < it->second.size) {
|
||||
// We should split VMAs here, but this could cause trouble for Windows.
|
||||
// Instead log a warning and name the whole VMA.
|
||||
// it = CarveVMA(current_addr, remaining_size);
|
||||
LOG_WARNING(Kernel_Vmm, "Trying to partially name a range");
|
||||
}
|
||||
auto& vma = it->second;
|
||||
vma.name = name;
|
||||
}
|
||||
remaining_size -= it->second.size;
|
||||
current_addr += it->second.size;
|
||||
it = FindVMA(current_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::InvalidateMemory(const VAddr addr, const u64 size) const {
|
||||
|
@ -767,6 +793,8 @@ VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment)
|
|||
ASSERT_MSG(virtual_addr <= max_search_address, "Input address {:#x} is out of bounds",
|
||||
virtual_addr);
|
||||
|
||||
// Align up the virtual_addr first.
|
||||
virtual_addr = Common::AlignUp(virtual_addr, alignment);
|
||||
auto it = FindVMA(virtual_addr);
|
||||
|
||||
// If the VMA is free and contains the requested mapping we are done.
|
||||
|
@ -907,4 +935,33 @@ int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut,
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int MemoryManager::IsStack(VAddr addr, void** start, void** end) {
|
||||
auto vma_handle = FindVMA(addr);
|
||||
if (vma_handle == vma_map.end()) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const VirtualMemoryArea& vma = vma_handle->second;
|
||||
if (!vma.Contains(addr, 0) || vma.IsFree()) {
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
|
||||
auto stack_start = 0ul;
|
||||
auto stack_end = 0ul;
|
||||
if (vma.type == VMAType::Stack) {
|
||||
stack_start = vma.base;
|
||||
stack_end = vma.base + vma.size;
|
||||
}
|
||||
|
||||
if (start != nullptr) {
|
||||
*start = reinterpret_cast<void*>(stack_start);
|
||||
}
|
||||
|
||||
if (end != nullptr) {
|
||||
*end = reinterpret_cast<void*>(stack_end);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -183,22 +183,16 @@ public:
|
|||
|
||||
void Free(PAddr phys_addr, size_t size);
|
||||
|
||||
int PoolReserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags,
|
||||
u64 alignment = 0);
|
||||
|
||||
int Reserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags,
|
||||
u64 alignment = 0);
|
||||
|
||||
int PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot);
|
||||
|
||||
int MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||
s32 MapMemory(void** out_addr, VAddr virtual_addr, u64 size, MemoryProt prot,
|
||||
MemoryMapFlags flags, VMAType type, std::string_view name = "anon",
|
||||
bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0);
|
||||
|
||||
int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||
MemoryMapFlags flags, uintptr_t fd, size_t offset);
|
||||
s32 MapFile(void** out_addr, VAddr virtual_addr, u64 size, MemoryProt prot,
|
||||
MemoryMapFlags flags, s32 fd, s64 phys_addr);
|
||||
|
||||
void PoolDecommit(VAddr virtual_addr, size_t size);
|
||||
s32 PoolDecommit(VAddr virtual_addr, size_t size);
|
||||
|
||||
s32 UnmapMemory(VAddr virtual_addr, size_t size);
|
||||
|
||||
|
@ -219,10 +213,14 @@ public:
|
|||
int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut,
|
||||
void** directMemoryEndOut);
|
||||
|
||||
void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name);
|
||||
s32 SetDirectMemoryType(s64 phys_addr, s32 memory_type);
|
||||
|
||||
void NameVirtualRange(VAddr virtual_addr, u64 size, std::string_view name);
|
||||
|
||||
void InvalidateMemory(VAddr addr, u64 size) const;
|
||||
|
||||
int IsStack(VAddr addr, void** start, void** end);
|
||||
|
||||
private:
|
||||
VMAHandle FindVMA(VAddr target) {
|
||||
return std::prev(vma_map.upper_bound(target));
|
||||
|
@ -274,6 +272,7 @@ private:
|
|||
size_t total_direct_size{};
|
||||
size_t total_flexible_size{};
|
||||
size_t flexible_usage{};
|
||||
size_t pool_budget{};
|
||||
Vulkan::Rasterizer* rasterizer{};
|
||||
|
||||
friend class ::Core::Devtools::Widget::MemoryMapViewer;
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include "common/types.h"
|
||||
|
||||
void* memset(void* ptr, int value, size_t num);
|
||||
|
||||
namespace Xbyak {
|
||||
class CodeGenerator;
|
||||
}
|
||||
|
@ -54,8 +53,20 @@ template <class ReturnType, class... FuncArgs, class... CallArgs>
|
|||
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) {
|
||||
EnsureThreadInitialized();
|
||||
// clear stack to avoid trash from EnsureThreadInitialized
|
||||
ClearStack<13_KB>();
|
||||
ClearStack<12_KB>();
|
||||
return func(std::forward<CallArgs>(args)...);
|
||||
}
|
||||
|
||||
template <class F, F f>
|
||||
struct HostCallWrapperImpl;
|
||||
|
||||
template <class ReturnType, class... Args, PS4_SYSV_ABI ReturnType (*func)(Args...)>
|
||||
struct HostCallWrapperImpl<PS4_SYSV_ABI ReturnType (*)(Args...), func> {
|
||||
static ReturnType PS4_SYSV_ABI wrap(Args... args) {
|
||||
return func(args...);
|
||||
}
|
||||
};
|
||||
|
||||
#define HOST_CALL(func) (Core::HostCallWrapperImpl<decltype(&(func)), func>::wrap)
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
#include <fmt/core.h>
|
||||
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "common/polyfill_thread.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/devtools/widget/module_list.h"
|
||||
#include "core/file_format/psf.h"
|
||||
#include "core/file_format/trp.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
|
@ -61,8 +63,13 @@ Emulator::~Emulator() {
|
|||
Config::saveMainWindow(config_dir / "config.toml");
|
||||
}
|
||||
|
||||
void Emulator::Run(const std::filesystem::path& file, const std::vector<std::string> args) {
|
||||
void Emulator::Run(std::filesystem::path file, const std::vector<std::string> args) {
|
||||
if (std::filesystem::is_directory(file)) {
|
||||
file /= "eboot.bin";
|
||||
}
|
||||
|
||||
const auto eboot_name = file.filename().string();
|
||||
|
||||
auto game_folder = file.parent_path();
|
||||
if (const auto game_folder_name = game_folder.filename().string();
|
||||
game_folder_name.ends_with("-UPDATE") || game_folder_name.ends_with("-patch")) {
|
||||
|
@ -113,6 +120,11 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
Common::Log::Initialize();
|
||||
}
|
||||
Common::Log::Start();
|
||||
if (!std::filesystem::exists(file)) {
|
||||
LOG_CRITICAL(Loader, "eboot.bin does not exist: {}",
|
||||
std::filesystem::absolute(file).string());
|
||||
std::quick_exit(0);
|
||||
}
|
||||
|
||||
LOG_INFO(Loader, "Starting shadps4 emulator v{} ", Common::g_version);
|
||||
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
|
||||
|
@ -188,18 +200,20 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
game_info.splash_path = pic1_path;
|
||||
}
|
||||
|
||||
game_info.game_folder = game_folder;
|
||||
|
||||
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
|
||||
std::string window_title = "";
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host = Common::GetRemoteNameFromLink();
|
||||
if (Common::g_is_release) {
|
||||
window_title = fmt::format("shadPS4 v{} | {}", Common::g_version, game_title);
|
||||
} else {
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host;
|
||||
try {
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} | {}", Common::g_version, game_title);
|
||||
} else {
|
||||
window_title =
|
||||
fmt::format("shadPS4 {}/v{} | {}", remote_host, Common::g_version, game_title);
|
||||
}
|
||||
} else {
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::g_version,
|
||||
Common::g_scm_branch, Common::g_scm_desc, game_title);
|
||||
|
@ -252,7 +266,11 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
|
||||
// Load the module with the linker
|
||||
const auto eboot_path = mnt->GetHostPath("/app0/" + eboot_name);
|
||||
linker->LoadModule(eboot_path);
|
||||
if (linker->LoadModule(eboot_path) == -1) {
|
||||
LOG_CRITICAL(Loader, "Failed to load game's eboot.bin: {}",
|
||||
std::filesystem::absolute(eboot_path).string());
|
||||
std::quick_exit(0);
|
||||
}
|
||||
|
||||
// check if we have system modules to load
|
||||
LoadSystemModules(game_info.game_serial);
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
Emulator();
|
||||
~Emulator();
|
||||
|
||||
void Run(const std::filesystem::path& file, const std::vector<std::string> args = {});
|
||||
void Run(std::filesystem::path file, const std::vector<std::string> args = {});
|
||||
void UpdatePlayTime(const std::string& serial);
|
||||
|
||||
private:
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 133 KiB |
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
@ -165,69 +165,37 @@ void GameController::Acceleration(int id, const float acceleration[3]) {
|
|||
AddState(state);
|
||||
}
|
||||
|
||||
// Stolen from
|
||||
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
|
||||
float eInt[3] = {0.0f, 0.0f, 0.0f}; // Integral error terms
|
||||
const float Kp = 50.0f; // Proportional gain
|
||||
const float Ki = 1.0f; // Integral gain
|
||||
Libraries::Pad::OrbisFQuaternion o = {1, 0, 0, 0};
|
||||
void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||
float deltaTime,
|
||||
Libraries::Pad::OrbisFQuaternion& lastOrientation,
|
||||
Libraries::Pad::OrbisFQuaternion& orientation) {
|
||||
float ax = acceleration.x, ay = acceleration.y, az = acceleration.z;
|
||||
float gx = angularVelocity.x, gy = angularVelocity.y, gz = angularVelocity.z;
|
||||
Libraries::Pad::OrbisFQuaternion q = lastOrientation;
|
||||
Libraries::Pad::OrbisFQuaternion ω = {angularVelocity.x, angularVelocity.y, angularVelocity.z,
|
||||
0.0f};
|
||||
|
||||
float q1 = o.w, q2 = o.x, q3 = o.y, q4 = o.z;
|
||||
Libraries::Pad::OrbisFQuaternion qω = {q.w * ω.x + q.x * ω.w + q.y * ω.z - q.z * ω.y,
|
||||
q.w * ω.y + q.y * ω.w + q.z * ω.x - q.x * ω.z,
|
||||
q.w * ω.z + q.z * ω.w + q.x * ω.y - q.y * ω.x,
|
||||
q.w * ω.w - q.x * ω.x - q.y * ω.y - q.z * ω.z};
|
||||
|
||||
// Normalize accelerometer measurement
|
||||
float norm = std::sqrt(ax * ax + ay * ay + az * az);
|
||||
if (norm == 0.0f || deltaTime == 0.0f)
|
||||
return; // Handle NaN
|
||||
norm = 1.0f / norm;
|
||||
ax *= norm;
|
||||
ay *= norm;
|
||||
az *= norm;
|
||||
Libraries::Pad::OrbisFQuaternion qDot = {0.5f * qω.x, 0.5f * qω.y, 0.5f * qω.z, 0.5f * qω.w};
|
||||
|
||||
// Estimated direction of gravity
|
||||
float vx = 2.0f * (q2 * q4 - q1 * q3);
|
||||
float vy = 2.0f * (q1 * q2 + q3 * q4);
|
||||
float vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
|
||||
q.x += qDot.x * deltaTime;
|
||||
q.y += qDot.y * deltaTime;
|
||||
q.z += qDot.z * deltaTime;
|
||||
q.w += qDot.w * deltaTime;
|
||||
|
||||
// Error is cross product between estimated direction and measured direction of gravity
|
||||
float ex = (ay * vz - az * vy);
|
||||
float ey = (az * vx - ax * vz);
|
||||
float ez = (ax * vy - ay * vx);
|
||||
if (Ki > 0.0f) {
|
||||
eInt[0] += ex * deltaTime; // Accumulate integral error
|
||||
eInt[1] += ey * deltaTime;
|
||||
eInt[2] += ez * deltaTime;
|
||||
} else {
|
||||
eInt[0] = eInt[1] = eInt[2] = 0.0f; // Prevent integral wind-up
|
||||
}
|
||||
float norm = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
|
||||
q.x /= norm;
|
||||
q.y /= norm;
|
||||
q.z /= norm;
|
||||
q.w /= norm;
|
||||
|
||||
// Apply feedback terms
|
||||
gx += Kp * ex + Ki * eInt[0];
|
||||
gy += Kp * ey + Ki * eInt[1];
|
||||
gz += Kp * ez + Ki * eInt[2];
|
||||
|
||||
//// Integrate rate of change of quaternion
|
||||
q1 += (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltaTime);
|
||||
q2 += (q1 * gx + q3 * gz - q4 * gy) * (0.5f * deltaTime);
|
||||
q3 += (q1 * gy - q2 * gz + q4 * gx) * (0.5f * deltaTime);
|
||||
q4 += (q1 * gz + q2 * gy - q3 * gx) * (0.5f * deltaTime);
|
||||
|
||||
// Normalize quaternion
|
||||
norm = std::sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
|
||||
norm = 1.0f / norm;
|
||||
orientation.w = q1 * norm;
|
||||
orientation.x = q2 * norm;
|
||||
orientation.y = q3 * norm;
|
||||
orientation.z = q4 * norm;
|
||||
o.w = q1 * norm;
|
||||
o.x = q2 * norm;
|
||||
o.y = q3 * norm;
|
||||
o.z = q4 * norm;
|
||||
orientation.x = q.x;
|
||||
orientation.y = q.y;
|
||||
orientation.z = q.z;
|
||||
orientation.w = q.w;
|
||||
LOG_DEBUG(Lib_Pad, "Calculated orientation: {:.2f} {:.2f} {:.2f} {:.2f}", orientation.x,
|
||||
orientation.y, orientation.z, orientation.w);
|
||||
}
|
||||
|
@ -260,6 +228,69 @@ void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, f
|
|||
}
|
||||
}
|
||||
|
||||
u8 GameController::GetTouchCount() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_touch_count;
|
||||
}
|
||||
|
||||
void GameController::SetTouchCount(u8 touchCount) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_touch_count = touchCount;
|
||||
}
|
||||
|
||||
u8 GameController::GetSecondaryTouchCount() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_secondary_touch_count;
|
||||
}
|
||||
|
||||
void GameController::SetSecondaryTouchCount(u8 touchCount) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_secondary_touch_count = touchCount;
|
||||
if (touchCount == 0) {
|
||||
m_was_secondary_reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
u8 GameController::GetPreviousTouchNum() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_previous_touchnum;
|
||||
}
|
||||
|
||||
void GameController::SetPreviousTouchNum(u8 touchNum) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_previous_touchnum = touchNum;
|
||||
}
|
||||
|
||||
bool GameController::WasSecondaryTouchReset() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_was_secondary_reset;
|
||||
}
|
||||
|
||||
void GameController::UnsetSecondaryTouchResetBool() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_was_secondary_reset = false;
|
||||
}
|
||||
|
||||
void GameController::SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_orientation = orientation;
|
||||
}
|
||||
|
||||
Libraries::Pad::OrbisFQuaternion GameController::GetLastOrientation() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_orientation;
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point GameController::GetLastUpdate() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_last_update;
|
||||
}
|
||||
|
||||
void GameController::SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_last_update = lastUpdate;
|
||||
}
|
||||
|
||||
void GameController::SetEngine(std::unique_ptr<Engine> engine) {
|
||||
std::scoped_lock _{m_mutex};
|
||||
m_engine = std::move(engine);
|
||||
|
|
|
@ -23,6 +23,7 @@ enum class Axis {
|
|||
};
|
||||
|
||||
struct TouchpadEntry {
|
||||
u8 ID = 0;
|
||||
bool state{};
|
||||
u16 x{};
|
||||
u16 y{};
|
||||
|
@ -82,9 +83,23 @@ public:
|
|||
Engine* GetEngine();
|
||||
u32 Poll();
|
||||
|
||||
u8 GetTouchCount();
|
||||
void SetTouchCount(u8 touchCount);
|
||||
u8 GetSecondaryTouchCount();
|
||||
void SetSecondaryTouchCount(u8 touchCount);
|
||||
u8 GetPreviousTouchNum();
|
||||
void SetPreviousTouchNum(u8 touchNum);
|
||||
bool WasSecondaryTouchReset();
|
||||
void UnsetSecondaryTouchResetBool();
|
||||
|
||||
void SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation);
|
||||
Libraries::Pad::OrbisFQuaternion GetLastOrientation();
|
||||
std::chrono::steady_clock::time_point GetLastUpdate();
|
||||
void SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate);
|
||||
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||
float deltaTime,
|
||||
Libraries::Pad::OrbisFQuaternion& lastOrientation,
|
||||
Libraries::Pad::OrbisFQuaternion& orientation);
|
||||
|
||||
private:
|
||||
|
@ -98,8 +113,15 @@ private:
|
|||
int m_connected_count = 0;
|
||||
u32 m_states_num = 0;
|
||||
u32 m_first_state = 0;
|
||||
u8 m_touch_count = 0;
|
||||
u8 m_secondary_touch_count = 0;
|
||||
u8 m_previous_touch_count = 0;
|
||||
u8 m_previous_touchnum = 0;
|
||||
bool m_was_secondary_reset = false;
|
||||
std::array<State, MAX_STATES> m_states;
|
||||
std::array<StateInternal, MAX_STATES> m_private;
|
||||
std::chrono::steady_clock::time_point m_last_update = {};
|
||||
Libraries::Pad::OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
std::unique_ptr<Engine> m_engine = nullptr;
|
||||
};
|
||||
|
|
|
@ -60,7 +60,7 @@ Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
|||
float angle = atan2(d_y, d_x);
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
if (d_x != 0 || d_y != 0) {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x7f, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x7f, a_y));
|
||||
} else {
|
||||
|
|
|
@ -137,7 +137,7 @@ tr("The Auto Updater allows up to 60 update checks per hour.\\nYou have reached
|
|||
}
|
||||
}
|
||||
|
||||
latestRev = latestVersion.right(7);
|
||||
latestRev = latestVersion.right(40);
|
||||
latestDate = jsonObj["published_at"].toString();
|
||||
|
||||
QJsonArray assets = jsonObj["assets"].toArray();
|
||||
|
@ -167,7 +167,7 @@ tr("The Auto Updater allows up to 60 update checks per hour.\\nYou have reached
|
|||
QDateTime dateTime = QDateTime::fromString(latestDate, Qt::ISODate);
|
||||
latestDate = dateTime.isValid() ? dateTime.toString("yyyy-MM-dd HH:mm:ss") : "Unknown date";
|
||||
|
||||
if (latestRev == currentRev.left(7)) {
|
||||
if (latestRev == currentRev) {
|
||||
if (showMessage) {
|
||||
QMessageBox::information(this, tr("Auto Updater"),
|
||||
tr("Your version is already up to date!"));
|
||||
|
@ -215,7 +215,7 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
|
|||
"<td>%3</td>"
|
||||
"<td>(%4)</td>"
|
||||
"</tr></table></p>")
|
||||
.arg(currentRev.left(7), currentDate, latestRev, latestDate);
|
||||
.arg(currentRev.left(7), currentDate, latestRev.left(7), latestDate);
|
||||
|
||||
QLabel* updateLabel = new QLabel(updateText, this);
|
||||
layout->addWidget(updateLabel);
|
||||
|
|
|
@ -79,6 +79,11 @@ public:
|
|||
if (const auto play_time = psf.GetString("PLAY_TIME"); play_time.has_value()) {
|
||||
game.play_time = *play_time;
|
||||
}
|
||||
if (const auto save_dir = psf.GetString("INSTALL_DIR_SAVEDATA"); save_dir.has_value()) {
|
||||
game.save_dir = *save_dir;
|
||||
} else {
|
||||
game.save_dir = game.serial;
|
||||
}
|
||||
}
|
||||
return game;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ struct GameInfo {
|
|||
std::string version = "Unknown";
|
||||
std::string region = "Unknown";
|
||||
std::string fw = "Unknown";
|
||||
std::string save_dir = "Unknown";
|
||||
|
||||
std::string play_time = "Unknown";
|
||||
CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown};
|
||||
|
|
|
@ -156,11 +156,9 @@ public:
|
|||
}
|
||||
|
||||
if (selected == openSaveDataFolder) {
|
||||
QString userPath;
|
||||
Common::FS::PathToQString(userPath,
|
||||
Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
||||
QString saveDataPath =
|
||||
userPath + "/savedata/1/" + QString::fromStdString(m_games[itemID].serial);
|
||||
QString saveDataPath;
|
||||
Common::FS::PathToQString(saveDataPath,
|
||||
Config::GetSaveDataPath() / "1" / m_games[itemID].save_dir);
|
||||
QDir(saveDataPath).mkpath(saveDataPath);
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(saveDataPath));
|
||||
}
|
||||
|
@ -485,8 +483,7 @@ public:
|
|||
dlc_path, Config::getAddonInstallDir() /
|
||||
Common::FS::PathFromQString(folder_path).parent_path().filename());
|
||||
Common::FS::PathToQString(save_data_path,
|
||||
Common::FS::GetUserPath(Common::FS::PathType::UserDir) /
|
||||
"savedata/1" / m_games[itemID].serial);
|
||||
Config::GetSaveDataPath() / "1" / m_games[itemID].save_dir);
|
||||
|
||||
Common::FS::PathToQString(trophy_data_path,
|
||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
|
|
|
@ -825,6 +825,9 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumHeight">
|
||||
<number>48</number>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::FocusPolicy::NoFocus</enum>
|
||||
</property>
|
||||
|
@ -841,6 +844,9 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumHeight">
|
||||
<number>48</number>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::FocusPolicy::NoFocus</enum>
|
||||
</property>
|
||||
|
@ -983,8 +989,8 @@
|
|||
<widget class="QLabel" name="l_controller">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>200</height>
|
||||
<width>424</width>
|
||||
<height>250</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "main_window.h"
|
||||
#include "settings_dialog.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
#endif
|
||||
|
@ -53,20 +52,18 @@ bool MainWindow::Init() {
|
|||
CreateConnects();
|
||||
SetLastUsedTheme();
|
||||
SetLastIconSizeBullet();
|
||||
GetPhysicalDevices();
|
||||
// show ui
|
||||
setMinimumSize(720, 405);
|
||||
std::string window_title = "";
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host = Common::GetRemoteNameFromLink();
|
||||
if (Common::g_is_release) {
|
||||
window_title = fmt::format("shadPS4 v{}", Common::g_version);
|
||||
} else {
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host;
|
||||
try {
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{}", Common::g_version);
|
||||
} else {
|
||||
window_title = fmt::format("shadPS4 {}/v{}", remote_host, Common::g_version);
|
||||
}
|
||||
} else {
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} {} {}", Common::g_version, Common::g_scm_branch,
|
||||
Common::g_scm_desc);
|
||||
|
@ -368,19 +365,6 @@ void MainWindow::CheckUpdateMain(bool checkSave) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::GetPhysicalDevices() {
|
||||
Vulkan::Instance instance(false, false);
|
||||
auto physical_devices = instance.GetPhysicalDevices();
|
||||
for (const vk::PhysicalDevice physical_device : physical_devices) {
|
||||
auto prop = physical_device.getProperties();
|
||||
QString name = QString::fromUtf8(prop.deviceName, -1);
|
||||
if (prop.apiVersion < Vulkan::TargetVulkanApiVersion) {
|
||||
name += tr(" * Unsupported Vulkan Version");
|
||||
}
|
||||
m_physical_devices.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::CreateConnects() {
|
||||
connect(this, &MainWindow::WindowResized, this, &MainWindow::HandleResize);
|
||||
connect(ui->mw_searchbar, &QLineEdit::textChanged, this, &MainWindow::SearchGameTable);
|
||||
|
@ -388,16 +372,15 @@ void MainWindow::CreateConnects() {
|
|||
connect(ui->refreshGameListAct, &QAction::triggered, this, &MainWindow::RefreshGameTable);
|
||||
connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::RefreshGameTable);
|
||||
connect(ui->showGameListAct, &QAction::triggered, this, &MainWindow::ShowGameList);
|
||||
connect(this, &MainWindow::ExtractionFinished, this, &MainWindow::RefreshGameTable);
|
||||
connect(ui->toggleLabelsAct, &QAction::toggled, this, &MainWindow::toggleLabelsUnderIcons);
|
||||
connect(ui->fullscreenButton, &QPushButton::clicked, this, &MainWindow::toggleFullscreen);
|
||||
|
||||
connect(ui->sizeSlider, &QSlider::valueChanged, this, [this](int value) {
|
||||
if (isTableList) {
|
||||
m_game_list_frame->icon_size =
|
||||
36 + value; // 36 is the minimum icon size to use due to text disappearing.
|
||||
m_game_list_frame->ResizeIcons(36 + value);
|
||||
Config::setIconSize(36 + value);
|
||||
48 + value; // 48 is the minimum icon size to use due to text disappearing.
|
||||
m_game_list_frame->ResizeIcons(48 + value);
|
||||
Config::setIconSize(48 + value);
|
||||
Config::setSliderPosition(value);
|
||||
} else {
|
||||
m_game_grid_frame->icon_size = 69 + value;
|
||||
|
@ -421,7 +404,7 @@ void MainWindow::CreateConnects() {
|
|||
&MainWindow::StartGame);
|
||||
|
||||
connect(ui->configureAct, &QAction::triggered, this, [this]() {
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
||||
auto settingsDialog = new SettingsDialog(m_compat_info, this);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
||||
&MainWindow::OnLanguageChanged);
|
||||
|
@ -454,7 +437,7 @@ void MainWindow::CreateConnects() {
|
|||
});
|
||||
|
||||
connect(ui->settingsButton, &QPushButton::clicked, this, [this]() {
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
||||
auto settingsDialog = new SettingsDialog(m_compat_info, this);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
||||
&MainWindow::OnLanguageChanged);
|
||||
|
|
|
@ -29,7 +29,6 @@ class MainWindow : public QMainWindow {
|
|||
Q_OBJECT
|
||||
signals:
|
||||
void WindowResized(QResizeEvent* event);
|
||||
void ExtractionFinished();
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = nullptr);
|
||||
|
@ -60,7 +59,6 @@ private:
|
|||
void toggleFullscreen();
|
||||
void CreateRecentGameActions();
|
||||
void CreateDockWindows();
|
||||
void GetPhysicalDevices();
|
||||
void LoadGameLists();
|
||||
|
||||
#ifdef ENABLE_UPDATER
|
||||
|
@ -96,8 +94,6 @@ private:
|
|||
QScopedPointer<ElfViewer> m_elf_viewer;
|
||||
// Status Bar.
|
||||
QScopedPointer<QStatusBar> statusBar;
|
||||
// Available GPU devices
|
||||
std::vector<QString> m_physical_devices;
|
||||
|
||||
PSF psf;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <vector>
|
||||
#include <QCompleter>
|
||||
#include <QDirIterator>
|
||||
#include <QFileDialog>
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "common/logging/filter.h"
|
||||
#include "settings_dialog.h"
|
||||
#include "ui_settings_dialog.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
QStringList languageNames = {"Arabic",
|
||||
"Czech",
|
||||
"Danish",
|
||||
|
@ -67,8 +69,9 @@ QMap<QString, QString> chooseHomeTabMap;
|
|||
int backgroundImageOpacitySlider_backup;
|
||||
int bgm_volume_backup;
|
||||
|
||||
SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
static std::vector<QString> m_physical_devices;
|
||||
|
||||
SettingsDialog::SettingsDialog(std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
QWidget* parent)
|
||||
: QDialog(parent), ui(new Ui::SettingsDialog) {
|
||||
ui->setupUi(this);
|
||||
|
@ -89,9 +92,23 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||
{tr("Input"), "Input"}, {tr("Paths"), "Paths"},
|
||||
{tr("Debug"), "Debug"}};
|
||||
|
||||
if (m_physical_devices.empty()) {
|
||||
// Populate cache of physical devices.
|
||||
Vulkan::Instance instance(false, false);
|
||||
auto physical_devices = instance.GetPhysicalDevices();
|
||||
for (const vk::PhysicalDevice physical_device : physical_devices) {
|
||||
auto prop = physical_device.getProperties();
|
||||
QString name = QString::fromUtf8(prop.deviceName, -1);
|
||||
if (prop.apiVersion < Vulkan::TargetVulkanApiVersion) {
|
||||
name += tr(" * Unsupported Vulkan Version");
|
||||
}
|
||||
m_physical_devices.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Add list of available GPUs
|
||||
ui->graphicsAdapterBox->addItem(tr("Auto Select")); // -1, auto selection
|
||||
for (const auto& device : physical_devices) {
|
||||
for (const auto& device : m_physical_devices) {
|
||||
ui->graphicsAdapterBox->addItem(device);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ class SettingsDialog;
|
|||
class SettingsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsDialog(std::span<const QString> physical_devices,
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
explicit SettingsDialog(std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
QWidget* parent = nullptr);
|
||||
~SettingsDialog();
|
||||
|
||||
|
|
|
@ -1347,10 +1347,6 @@
|
|||
<source>Game List</source>
|
||||
<translation>قائمة الألعاب</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> * Unsupported Vulkan Version</source>
|
||||
<translation> * إصدار Vulkan غير مدعوم</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Cheats For All Installed Games</source>
|
||||
<translation>تحميل الشفرات لجميع الألعاب المثبتة</translation>
|
||||
|
@ -2051,6 +2047,10 @@ Nightly: نُسخ تحتوي على أحدث الميزات، لكنها أقل
|
|||
<source>Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</source>
|
||||
<translation>افتح مجلد الصور/الأصوات الخاصة بالجوائز المخصصة:\nيمكنك إضافة صور مخصصة للجوائز وصوت مرفق.\nأضف الملفات إلى مجلد custom_trophy بالأسماء التالية:\ntrophy.wav أو trophy.mp3، bronze.png، gold.png، platinum.png، silver.png\nملاحظة: الصوت سيعمل فقط في الإصدارات التي تستخدم QT.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> * Unsupported Vulkan Version</source>
|
||||
<translation type="unfinished"> * Unsupported Vulkan Version</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TrophyViewer</name>
|
||||
|
|
|
@ -1347,10 +1347,6 @@
|
|||
<source>Game List</source>
|
||||
<translation>Spiloversigt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> * Unsupported Vulkan Version</source>
|
||||
<translation> * Ikke understøttet Vulkan-version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Cheats For All Installed Games</source>
|
||||
<translation>Hent snyd til alle installerede spil</translation>
|
||||
|
@ -2050,6 +2046,10 @@
|
|||
<source>Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</source>
|
||||
<translation type="unfinished">Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> * Unsupported Vulkan Version</source>
|
||||
<translation type="unfinished"> * Unsupported Vulkan Version</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TrophyViewer</name>
|
||||
|
|
|
@ -1347,10 +1347,6 @@
|
|||
<source>Game List</source>
|
||||
<translation>Spieleliste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> * Unsupported Vulkan Version</source>
|
||||
<translation> * Nicht unterstützte Vulkan-Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Cheats For All Installed Games</source>
|
||||
<translation>Cheats für alle installierten Spiele herunterladen</translation>
|
||||
|
@ -2054,6 +2050,10 @@ Fügen Sie die Dateien dem Ordner custom_trophy mit folgenden Namen hinzu:\n
|
|||
trophy.wav ODER trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\n
|
||||
Hinweis: Der Sound funktioniert nur in Qt-Versionen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> * Unsupported Vulkan Version</source>
|
||||
<translation type="unfinished"> * Unsupported Vulkan Version</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TrophyViewer</name>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue