diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ceb915f6a..b098896f5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -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,13 +218,16 @@ 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
archives: qtbase qttools
modules: qtmultimedia
-
+
+ - name: Workaround Qt <=6.9.1 issue
+ run: sed -i '' '/target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE ${__opengl_agl_fw_path})/d' ${{env.QT_ROOT_DIR}}/lib/cmake/Qt6/FindWrapOpenGL.cmake
+
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
@@ -247,7 +240,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 +294,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 +355,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 +402,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 +438,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 +487,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 +523,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,
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 20d33ac95..d8fe5f68b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -653,6 +653,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/arch.h
src/common/assert.cpp
src/common/assert.h
+ src/common/bit_array.h
src/common/bit_field.h
src/common/bounded_threadsafe_queue.h
src/common/concepts.h
@@ -870,6 +871,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp
+ src/shader_recompiler/ir/passes/shared_memory_simplify_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
@@ -912,9 +914,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/buffer_cache/buffer.h
src/video_core/buffer_cache/buffer_cache.cpp
src/video_core/buffer_cache/buffer_cache.h
- src/video_core/buffer_cache/memory_tracker_base.h
+ src/video_core/buffer_cache/memory_tracker.h
src/video_core/buffer_cache/range_set.h
- src/video_core/buffer_cache/word_manager.h
+ src/video_core/buffer_cache/region_definitions.h
+ src/video_core/buffer_cache/region_manager.h
src/video_core/renderer_vulkan/liverpool_to_vk.cpp
src/video_core/renderer_vulkan/liverpool_to_vk.h
src/video_core/renderer_vulkan/vk_common.cpp
@@ -951,6 +954,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/host_passes/fsr_pass.h
src/video_core/renderer_vulkan/host_passes/pp_pass.cpp
src/video_core/renderer_vulkan/host_passes/pp_pass.h
+ src/video_core/texture_cache/blit_helper.cpp
+ src/video_core/texture_cache/blit_helper.h
+ src/video_core/texture_cache/host_compatibility.cpp
+ src/video_core/texture_cache/host_compatibility.h
src/video_core/texture_cache/image.cpp
src/video_core/texture_cache/image.h
src/video_core/texture_cache/image_info.cpp
@@ -964,7 +971,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/texture_cache/tile_manager.cpp
src/video_core/texture_cache/tile_manager.h
src/video_core/texture_cache/types.h
- src/video_core/texture_cache/host_compatibility.h
src/video_core/page_manager.cpp
src/video_core/page_manager.h
src/video_core/multi_level_page_table.h
@@ -1053,6 +1059,10 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/settings_dialog.h
src/qt_gui/settings_dialog.ui
src/qt_gui/main.cpp
+ src/qt_gui/gui_settings.cpp
+ src/qt_gui/gui_settings.h
+ src/qt_gui/settings.cpp
+ src/qt_gui/settings.h
${EMULATOR}
${RESOURCE_FILES}
${TRANSLATIONS}
@@ -1118,6 +1128,10 @@ if (APPLE)
set(MVK_BUNDLE_PATH "Resources/vulkan/icd.d")
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLE_PATH}")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/${MVK_BUNDLE_PATH})
+
+ add_custom_command(
+ OUTPUT ${MVK_DST}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
else()
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
@@ -1128,9 +1142,6 @@ if (APPLE)
set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json)
- add_custom_command(
- OUTPUT ${MVK_DST}
- COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
add_custom_command(
OUTPUT ${MVK_ICD_DST}
DEPENDS ${MVK_ICD_SRC} ${MVK_DST}
@@ -1145,17 +1156,13 @@ if (APPLE)
if (ARCHITECTURE STREQUAL "x86_64")
# Reserve system-managed memory space.
- target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000)
+ target_link_options(shadps4 PRIVATE -Wl,-ld_classic,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000)
endif()
# Replacement for std::chrono::time_zone
target_link_libraries(shadps4 PRIVATE date::date-tz)
endif()
-if (NOT ENABLE_QT_GUI)
- target_link_libraries(shadps4 PRIVATE SDL3::SDL3)
-endif()
-
if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI)
diff --git a/README.md b/README.md
index 985bba586..22fc27a33 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
-If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md).\
+If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D).\
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).\
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\
@@ -124,8 +124,8 @@ Keyboard and mouse inputs can be customized in the settings menu by clicking the
# Firmware files
-shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.\
-The following firmware modules are supported and must be placed in shadPS4's `user/sys_modules` folder.
+shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.
+The following firmware modules are supported and must be placed in shadPS4's `sys_modules` folder.
@@ -138,8 +138,7 @@ The following firmware modules are supported and must be placed in shadPS4's `us
> [!Caution]
-> The above modules are required to run the games properly and must be extracted from your PlayStation 4.\
-> **We do not provide any information or support on how to do this**.
+> The above modules are required to run the games properly and must be extracted from your PlayStation 4.
@@ -148,7 +147,7 @@ The following firmware modules are supported and must be placed in shadPS4's `us
- [**georgemoralis**](https://github.com/georgemoralis)
- [**psucien**](https://github.com/psucien)
- [**viniciuslrangel**](https://github.com/viniciuslrangel)
-- [**roamic**](https://github.com/vladmikhalin)
+- [**roamic**](https://github.com/roamic)
- [**squidbus**](https://github.com/squidbus)
- [**frodo**](https://github.com/baggins183)
- [**Stephen Miller**](https://github.com/StevenMiller123)
@@ -158,7 +157,7 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
# Contributing
-If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
+If you want to contribute, please read the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
Open a PR and we'll check it :)
# Translations
diff --git a/REUSE.toml b/REUSE.toml
index 662987611..7a7e4bb38 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -7,8 +7,8 @@ path = [
"CMakeSettings.json",
".github/FUNDING.yml",
".github/shadps4.png",
- ".github/workflows/scripts/update_translation.sh",
- ".github/workflows/update_translation.yml",
+ ".github/workflows/scripts/update_translation.sh",
+ ".github/workflows/update_translation.yml",
".gitmodules",
"dist/MacOSBundleInfo.plist.in",
"dist/net.shadps4.shadPS4.desktop",
@@ -29,6 +29,7 @@ path = [
"src/images/discord.png",
"src/images/dump_icon.png",
"src/images/exit_icon.png",
+ "src/images/favorite_icon.png",
"src/images/file_icon.png",
"src/images/trophy_icon.png",
"src/images/flag_china.png",
@@ -71,7 +72,7 @@ path = [
"src/images/youtube.svg",
"src/shadps4.qrc",
"src/shadps4.rc",
- "src/qt_gui/translations/update_translation.sh",
+ "src/qt_gui/translations/update_translation.sh",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
diff --git a/documents/building-linux.md b/documents/building-linux.md
index bd07b2eff..00d73280e 100644
--- a/documents/building-linux.md
+++ b/documents/building-linux.md
@@ -25,7 +25,7 @@ sudo apt install build-essential clang git cmake libasound2-dev \
```bash
sudo dnf install clang git cmake libatomic alsa-lib-devel \
- pipewire-jack-audio-connection-kit-devel openal-devel \
+ pipewire-jack-audio-connection-kit-devel openal-soft-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 \
@@ -74,6 +74,7 @@ and install the dependencies on that container as cited above.
This option is **highly recommended** for distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS).
### Cloning
+The project uses submodules to manage dependencies, and they need to be initialized before you can build the project. To achieve this, make sure you've cloned the repository with the --recursive flag
```bash
git clone --recursive https://github.com/shadps4-emu/shadPS4.git
diff --git a/externals/MoltenVK/MoltenVK b/externals/MoltenVK/MoltenVK
index 3a0b07a24..00abd384c 160000
--- a/externals/MoltenVK/MoltenVK
+++ b/externals/MoltenVK/MoltenVK
@@ -1 +1 @@
-Subproject commit 3a0b07a24a4a681ffe70b461b1f4333b2729e2ef
+Subproject commit 00abd384ce01cbd439045905d2fa6cf799dfa2f6
diff --git a/externals/MoltenVK/SPIRV-Cross b/externals/MoltenVK/SPIRV-Cross
index 969e75f7c..1a69a919f 160000
--- a/externals/MoltenVK/SPIRV-Cross
+++ b/externals/MoltenVK/SPIRV-Cross
@@ -1 +1 @@
-Subproject commit 969e75f7cc0718774231d029f9d52fa87d4ae1b2
+Subproject commit 1a69a919fa302e92b337594bd0a8aaea61037d91
diff --git a/src/common/bit_array.h b/src/common/bit_array.h
new file mode 100644
index 000000000..f211bbf95
--- /dev/null
+++ b/src/common/bit_array.h
@@ -0,0 +1,411 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#include
+#include "common/types.h"
+
+#ifdef __AVX2__
+#define BIT_ARRAY_USE_AVX
+#include
+#endif
+
+namespace Common {
+
+template
+class BitArray {
+ static_assert(N % 64 == 0, "BitArray size must be a multiple of 64 bits.");
+
+ static constexpr size_t BITS_PER_WORD = 64;
+ static constexpr size_t WORD_COUNT = N / BITS_PER_WORD;
+ static constexpr size_t WORDS_PER_AVX = 4;
+ static constexpr size_t AVX_WORD_COUNT = WORD_COUNT / WORDS_PER_AVX;
+
+public:
+ using Range = std::pair;
+
+ class Iterator {
+ public:
+ explicit Iterator(const BitArray& bit_array_, u64 start) : bit_array(bit_array_) {
+ range = bit_array.FirstRangeFrom(start);
+ }
+
+ Iterator& operator++() {
+ range = bit_array.FirstRangeFrom(range.second);
+ return *this;
+ }
+
+ bool operator==(const Iterator& other) const {
+ return range == other.range;
+ }
+
+ bool operator!=(const Iterator& other) const {
+ return !(*this == other);
+ }
+
+ const Range& operator*() const {
+ return range;
+ }
+
+ const Range* operator->() const {
+ return ⦥
+ }
+
+ private:
+ const BitArray& bit_array;
+ Range range;
+ };
+
+ using const_iterator = Iterator;
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = Range;
+ using difference_type = std::ptrdiff_t;
+ using pointer = const Range*;
+ using reference = const Range&;
+
+ BitArray() = default;
+ BitArray(const BitArray& other) = default;
+ BitArray& operator=(const BitArray& other) = default;
+ BitArray(BitArray&& other) noexcept = default;
+ BitArray& operator=(BitArray&& other) noexcept = default;
+ ~BitArray() = default;
+
+ BitArray(const BitArray& other, size_t start, size_t end) {
+ if (start >= end || end > N) {
+ return;
+ }
+ const size_t first_word = start / BITS_PER_WORD;
+ const size_t last_word = (end - 1) / BITS_PER_WORD;
+ const size_t start_bit = start % BITS_PER_WORD;
+ const size_t end_bit = (end - 1) % BITS_PER_WORD;
+ const u64 start_mask = ~((1ULL << start_bit) - 1);
+ const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? ~0ULL : (1ULL << (end_bit + 1)) - 1;
+ if (first_word == last_word) {
+ data[first_word] = other.data[first_word] & (start_mask & end_mask);
+ } else {
+ data[first_word] = other.data[first_word] & start_mask;
+ size_t i = first_word + 1;
+#ifdef BIT_ARRAY_USE_AVX
+ for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) {
+ const __m256i current =
+ _mm256_loadu_si256(reinterpret_cast(&other.data[i]));
+ _mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), current);
+ }
+#endif
+ for (; i < last_word; ++i) {
+ data[i] = other.data[i];
+ }
+ data[last_word] = other.data[last_word] & end_mask;
+ }
+ }
+
+ BitArray(const BitArray& other, const Range& range)
+ : BitArray(other, range.first, range.second) {}
+
+ const_iterator begin() const {
+ return Iterator(*this, 0);
+ }
+ const_iterator end() const {
+ return Iterator(*this, N);
+ }
+
+ inline constexpr void Set(size_t idx) {
+ data[idx / BITS_PER_WORD] |= (1ULL << (idx % BITS_PER_WORD));
+ }
+
+ inline constexpr void Unset(size_t idx) {
+ data[idx / BITS_PER_WORD] &= ~(1ULL << (idx % BITS_PER_WORD));
+ }
+
+ inline constexpr bool Get(size_t idx) const {
+ return (data[idx / BITS_PER_WORD] & (1ULL << (idx % BITS_PER_WORD))) != 0;
+ }
+
+ inline void SetRange(size_t start, size_t end) {
+ if (start >= end || end > N) {
+ return;
+ }
+ const size_t first_word = start / BITS_PER_WORD;
+ const size_t last_word = (end - 1) / BITS_PER_WORD;
+ const size_t start_bit = start % BITS_PER_WORD;
+ const size_t end_bit = (end - 1) % BITS_PER_WORD;
+ const u64 start_mask = ~((1ULL << start_bit) - 1);
+ const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? ~0ULL : (1ULL << (end_bit + 1)) - 1;
+ if (first_word == last_word) {
+ data[first_word] |= start_mask & end_mask;
+ } else {
+ data[first_word] |= start_mask;
+ size_t i = first_word + 1;
+#ifdef BIT_ARRAY_USE_AVX
+ const __m256i value = _mm256_set1_epi64x(-1);
+ for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) {
+ _mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), value);
+ }
+#endif
+ for (; i < last_word; ++i) {
+ data[i] = ~0ULL;
+ }
+ data[last_word] |= end_mask;
+ }
+ }
+
+ inline void UnsetRange(size_t start, size_t end) {
+ if (start >= end || end > N) {
+ return;
+ }
+ size_t first_word = start / BITS_PER_WORD;
+ const size_t last_word = (end - 1) / BITS_PER_WORD;
+ const size_t start_bit = start % BITS_PER_WORD;
+ const size_t end_bit = (end - 1) % BITS_PER_WORD;
+ const u64 start_mask = (1ULL << start_bit) - 1;
+ const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? 0ULL : ~((1ULL << (end_bit + 1)) - 1);
+ if (first_word == last_word) {
+ data[first_word] &= start_mask | end_mask;
+ } else {
+ data[first_word] &= start_mask;
+ size_t i = first_word + 1;
+#ifdef BIT_ARRAY_USE_AVX
+ const __m256i value = _mm256_setzero_si256();
+ for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) {
+ _mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), value);
+ }
+#endif
+ for (; i < last_word; ++i) {
+ data[i] = 0ULL;
+ }
+ data[last_word] &= end_mask;
+ }
+ }
+
+ inline constexpr void SetRange(const Range& range) {
+ SetRange(range.first, range.second);
+ }
+
+ inline constexpr void UnsetRange(const Range& range) {
+ UnsetRange(range.first, range.second);
+ }
+
+ inline constexpr void Clear() {
+ data.fill(0);
+ }
+
+ inline constexpr void Fill() {
+ data.fill(~0ULL);
+ }
+
+ inline constexpr bool None() const {
+ u64 result = 0;
+ for (const auto& word : data) {
+ result |= word;
+ }
+ return result == 0;
+ }
+
+ inline constexpr bool Any() const {
+ return !None();
+ }
+
+ Range FirstRangeFrom(size_t start) const {
+ if (start >= N) {
+ return {N, N};
+ }
+ const auto find_end_bit = [&](size_t word) {
+#ifdef BIT_ARRAY_USE_AVX
+ const __m256i all_one = _mm256_set1_epi64x(-1);
+ for (; word + WORDS_PER_AVX <= WORD_COUNT; word += WORDS_PER_AVX) {
+ const __m256i current =
+ _mm256_loadu_si256(reinterpret_cast(&data[word]));
+ const __m256i cmp = _mm256_cmpeq_epi64(current, all_one);
+ if (_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
+ break;
+ }
+ }
+#endif
+ for (; word < WORD_COUNT; ++word) {
+ if (data[word] != ~0ULL) {
+ return (word * BITS_PER_WORD) + std::countr_one(data[word]);
+ }
+ }
+ return N;
+ };
+
+ const auto word_bits = [&](size_t index, u64 word) {
+ const int empty_bits = std::countr_zero(word);
+ const int ones_count = std::countr_one(word >> empty_bits);
+ const size_t start_bit = index * BITS_PER_WORD + empty_bits;
+ if (ones_count + empty_bits < BITS_PER_WORD) {
+ return Range{start_bit, start_bit + ones_count};
+ }
+ return Range{start_bit, find_end_bit(index + 1)};
+ };
+
+ const size_t start_word = start / BITS_PER_WORD;
+ const size_t start_bit = start % BITS_PER_WORD;
+ const u64 masked_first = data[start_word] & (~((1ULL << start_bit) - 1));
+ if (masked_first) {
+ return word_bits(start_word, masked_first);
+ }
+
+ size_t word = start_word + 1;
+#ifdef BIT_ARRAY_USE_AVX
+ for (; word + WORDS_PER_AVX <= WORD_COUNT; word += WORDS_PER_AVX) {
+ const __m256i current =
+ _mm256_loadu_si256(reinterpret_cast(&data[word]));
+ if (!_mm256_testz_si256(current, current)) {
+ break;
+ }
+ }
+#endif
+ for (; word < WORD_COUNT; ++word) {
+ if (data[word] != 0) {
+ return word_bits(word, data[word]);
+ }
+ }
+ return {N, N};
+ }
+
+ inline constexpr Range FirstRange() const {
+ return FirstRangeFrom(0);
+ }
+
+ Range LastRangeFrom(size_t end) const {
+ if (end == 0) {
+ return {0, 0};
+ }
+ if (end > N) {
+ end = N;
+ }
+ const auto find_start_bit = [&](size_t word) {
+#ifdef BIT_ARRAY_USE_AVX
+ const __m256i all_zero = _mm256_setzero_si256();
+ for (; word >= WORDS_PER_AVX; word -= WORDS_PER_AVX) {
+ const __m256i current = _mm256_loadu_si256(
+ reinterpret_cast(&data[word - WORDS_PER_AVX]));
+ const __m256i cmp = _mm256_cmpeq_epi64(current, all_zero);
+ if (_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
+ break;
+ }
+ }
+#endif
+ for (; word > 0; --word) {
+ if (data[word - 1] != ~0ULL) {
+ return word * BITS_PER_WORD - std::countl_one(data[word - 1]);
+ }
+ }
+ return size_t(0);
+ };
+ const auto word_bits = [&](size_t index, u64 word) {
+ const int empty_bits = std::countl_zero(word);
+ const int ones_count = std::countl_one(word << empty_bits);
+ const size_t end_bit = index * BITS_PER_WORD - empty_bits;
+ if (empty_bits + ones_count < BITS_PER_WORD) {
+ return Range{end_bit - ones_count, end_bit};
+ }
+ return Range{find_start_bit(index - 1), end_bit};
+ };
+ const size_t end_word = ((end - 1) / BITS_PER_WORD) + 1;
+ const size_t end_bit = (end - 1) % BITS_PER_WORD;
+ u64 masked_last = data[end_word - 1];
+ if (end_bit < BITS_PER_WORD - 1) {
+ masked_last &= (1ULL << (end_bit + 1)) - 1;
+ }
+ if (masked_last) {
+ return word_bits(end_word, masked_last);
+ }
+ size_t word = end_word - 1;
+#ifdef BIT_ARRAY_USE_AVX
+ for (; word >= WORDS_PER_AVX; word -= WORDS_PER_AVX) {
+ const __m256i current =
+ _mm256_loadu_si256(reinterpret_cast(&data[word - WORDS_PER_AVX]));
+ if (!_mm256_testz_si256(current, current)) {
+ break;
+ }
+ }
+#endif
+ for (; word > 0; --word) {
+ if (data[word - 1] != 0) {
+ return word_bits(word, data[word - 1]);
+ }
+ }
+ return {0, 0};
+ }
+
+ inline constexpr Range LastRange() const {
+ return LastRangeFrom(N);
+ }
+
+ inline constexpr size_t Size() const {
+ return N;
+ }
+
+ inline constexpr BitArray& operator|=(const BitArray& other) {
+ for (size_t i = 0; i < WORD_COUNT; ++i) {
+ data[i] |= other.data[i];
+ }
+ return *this;
+ }
+
+ inline constexpr BitArray& operator&=(const BitArray& other) {
+ for (size_t i = 0; i < WORD_COUNT; ++i) {
+ data[i] &= other.data[i];
+ }
+ return *this;
+ }
+
+ inline constexpr BitArray& operator^=(const BitArray& other) {
+ for (size_t i = 0; i < WORD_COUNT; ++i) {
+ data[i] ^= other.data[i];
+ }
+ return *this;
+ }
+
+ inline constexpr BitArray& operator~() {
+ for (size_t i = 0; i < WORD_COUNT; ++i) {
+ data[i] = ~data[i];
+ }
+ return *this;
+ }
+
+ inline constexpr BitArray operator|(const BitArray& other) const {
+ BitArray result = *this;
+ result |= other;
+ return result;
+ }
+
+ inline constexpr BitArray operator&(const BitArray& other) const {
+ BitArray result = *this;
+ result &= other;
+ return result;
+ }
+
+ inline constexpr BitArray operator^(const BitArray& other) const {
+ BitArray result = *this;
+ result ^= other;
+ return result;
+ }
+
+ inline constexpr BitArray operator~() const {
+ BitArray result = *this;
+ result = ~result;
+ return result;
+ }
+
+ inline constexpr bool operator==(const BitArray& other) const {
+ u64 result = 0;
+ for (size_t i = 0; i < WORD_COUNT; ++i) {
+ result |= data[i] ^ other.data[i];
+ }
+ return result == 0;
+ }
+
+ inline constexpr bool operator!=(const BitArray& other) const {
+ return !(*this == other);
+ }
+
+private:
+ std::array data{};
+};
+
+} // namespace Common
\ No newline at end of file
diff --git a/src/common/config.cpp b/src/common/config.cpp
index 6565ab82a..9c316949a 100644
--- a/src/common/config.cpp
+++ b/src/common/config.cpp
@@ -33,9 +33,7 @@ namespace Config {
static bool isNeo = false;
static bool isDevKit = false;
-static bool playBGM = false;
static bool isTrophyPopupDisabled = false;
-static int BGMvolume = 50;
static bool enableDiscordRPC = false;
static u32 screenWidth = 1280;
static u32 screenHeight = 720;
@@ -43,17 +41,13 @@ static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto
static std::string logFilter;
static std::string logType = "sync";
static std::string userName = "shadPS4";
-static std::string updateChannel;
static std::string chooseHomeTab;
-static std::string backButtonBehavior = "left";
static bool useSpecialPad = false;
static int specialPadClass = 1;
static bool isMotionControlsEnabled = true;
static bool isDebugDump = false;
static bool isShaderDebug = false;
static bool isShowSplash = false;
-static bool isAutoUpdate = false;
-static bool isAlwaysShowChangelog = false;
static std::string isSideTrophy = "right";
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
@@ -86,27 +80,9 @@ static std::vector settings_install_dirs = {};
std::vector install_dirs_enabled = {};
std::filesystem::path settings_addon_install_dir = {};
std::filesystem::path save_data_path = {};
-u32 main_window_geometry_x = 400;
-u32 main_window_geometry_y = 400;
-u32 main_window_geometry_w = 1280;
-u32 main_window_geometry_h = 720;
-u32 mw_themes = 0;
-u32 m_icon_size = 36;
-u32 m_icon_size_grid = 69;
-u32 m_slider_pos = 0;
-u32 m_slider_pos_grid = 0;
-u32 m_table_mode = 0;
-u32 m_window_size_W = 1280;
-u32 m_window_size_H = 720;
-std::vector m_elf_viewer;
-std::vector m_recent_files;
-std::string emulator_language = "en_US";
-static int backgroundImageOpacity = 50;
-static bool showBackgroundImage = true;
static bool isFullscreen = false;
static std::string fullscreenMode = "Windowed";
static bool isHDRAllowed = false;
-static bool showLabelsUnderIcons = true;
// Language
u32 m_language = 1; // english
@@ -176,14 +152,6 @@ bool getIsFullscreen() {
return isFullscreen;
}
-bool getShowLabelsUnderIcons() {
- return showLabelsUnderIcons;
-}
-
-bool setShowLabelsUnderIcons() {
- return false;
-}
-
std::string getFullscreenMode() {
return fullscreenMode;
}
@@ -192,14 +160,6 @@ bool getisTrophyPopupDisabled() {
return isTrophyPopupDisabled;
}
-bool getPlayBGM() {
- return playBGM;
-}
-
-int getBGMvolume() {
- return BGMvolume;
-}
-
bool getEnableDiscordRPC() {
return enableDiscordRPC;
}
@@ -240,18 +200,10 @@ std::string getUserName() {
return userName;
}
-std::string getUpdateChannel() {
- return updateChannel;
-}
-
std::string getChooseHomeTab() {
return chooseHomeTab;
}
-std::string getBackButtonBehavior() {
- return backButtonBehavior;
-}
-
bool getUseSpecialPad() {
return useSpecialPad;
}
@@ -276,14 +228,6 @@ bool showSplash() {
return isShowSplash;
}
-bool autoUpdate() {
- return isAutoUpdate;
-}
-
-bool alwaysShowChangelog() {
- return isAlwaysShowChangelog;
-}
-
std::string sideTrophy() {
return isSideTrophy;
}
@@ -384,14 +328,6 @@ void setShowSplash(bool enable) {
isShowSplash = enable;
}
-void setAutoUpdate(bool enable) {
- isAutoUpdate = enable;
-}
-
-void setAlwaysShowChangelog(bool enable) {
- isAlwaysShowChangelog = enable;
-}
-
void setSideTrophy(std::string side) {
isSideTrophy = side;
}
@@ -431,9 +367,6 @@ void setVblankDiv(u32 value) {
void setIsFullscreen(bool enable) {
isFullscreen = enable;
}
-static void setShowLabelsUnderIcons(bool enable) {
- showLabelsUnderIcons = enable;
-}
void setFullscreenMode(std::string mode) {
fullscreenMode = mode;
@@ -443,14 +376,6 @@ void setisTrophyPopupDisabled(bool disable) {
isTrophyPopupDisabled = disable;
}
-void setPlayBGM(bool enable) {
- playBGM = enable;
-}
-
-void setBGMvolume(int volume) {
- BGMvolume = volume;
-}
-
void setEnableDiscordRPC(bool enable) {
enableDiscordRPC = enable;
}
@@ -490,17 +415,10 @@ void setUserName(const std::string& type) {
userName = type;
}
-void setUpdateChannel(const std::string& type) {
- updateChannel = type;
-}
void setChooseHomeTab(const std::string& type) {
chooseHomeTab = type;
}
-void setBackButtonBehavior(const std::string& type) {
- backButtonBehavior = type;
-}
-
void setUseSpecialPad(bool use) {
useSpecialPad = use;
}
@@ -521,13 +439,6 @@ void setCheckCompatibilityOnStartup(bool use) {
checkCompatibilityOnStartup = use;
}
-void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
- main_window_geometry_x = x;
- main_window_geometry_y = y;
- main_window_geometry_w = w;
- main_window_geometry_h = h;
-}
-
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
for (const auto& install_dir : settings_install_dirs) {
if (install_dir.path == dir) {
@@ -560,52 +471,6 @@ void setAddonInstallDir(const std::filesystem::path& dir) {
settings_addon_install_dir = dir;
}
-void setMainWindowTheme(u32 theme) {
- mw_themes = theme;
-}
-
-void setIconSize(u32 size) {
- m_icon_size = size;
-}
-
-void setIconSizeGrid(u32 size) {
- m_icon_size_grid = size;
-}
-
-void setSliderPosition(u32 pos) {
- m_slider_pos = pos;
-}
-
-void setSliderPositionGrid(u32 pos) {
- m_slider_pos_grid = pos;
-}
-
-void setTableMode(u32 mode) {
- m_table_mode = mode;
-}
-
-void setMainWindowWidth(u32 width) {
- m_window_size_W = width;
-}
-
-void setMainWindowHeight(u32 height) {
- m_window_size_H = height;
-}
-
-void setElfViewer(const std::vector& elfList) {
- m_elf_viewer.resize(elfList.size());
- m_elf_viewer = elfList;
-}
-
-void setRecentFiles(const std::vector& recentFiles) {
- m_recent_files.resize(recentFiles.size());
- m_recent_files = recentFiles;
-}
-
-void setEmulatorLanguage(std::string language) {
- emulator_language = language;
-}
-
void setGameInstallDirs(const std::vector& dirs_config) {
settings_install_dirs.clear();
for (const auto& dir : dirs_config) {
@@ -621,22 +486,6 @@ void setSaveDataPath(const std::filesystem::path& path) {
save_data_path = path;
}
-u32 getMainWindowGeometryX() {
- return main_window_geometry_x;
-}
-
-u32 getMainWindowGeometryY() {
- return main_window_geometry_y;
-}
-
-u32 getMainWindowGeometryW() {
- return main_window_geometry_w;
-}
-
-u32 getMainWindowGeometryH() {
- return main_window_geometry_h;
-}
-
const std::vector getGameInstallDirs() {
std::vector enabled_dirs;
for (const auto& dir : settings_install_dirs) {
@@ -663,50 +512,6 @@ std::filesystem::path getAddonInstallDir() {
return settings_addon_install_dir;
}
-u32 getMainWindowTheme() {
- return mw_themes;
-}
-
-u32 getIconSize() {
- return m_icon_size;
-}
-
-u32 getIconSizeGrid() {
- return m_icon_size_grid;
-}
-
-u32 getSliderPosition() {
- return m_slider_pos;
-}
-
-u32 getSliderPositionGrid() {
- return m_slider_pos_grid;
-}
-
-u32 getTableMode() {
- return m_table_mode;
-}
-
-u32 getMainWindowWidth() {
- return m_window_size_W;
-}
-
-u32 getMainWindowHeight() {
- return m_window_size_H;
-}
-
-std::vector getElfViewer() {
- return m_elf_viewer;
-}
-
-std::vector getRecentFiles() {
- return m_recent_files;
-}
-
-std::string getEmulatorLanguage() {
- return emulator_language;
-}
-
u32 GetLanguage() {
return m_language;
}
@@ -715,22 +520,6 @@ bool getSeparateLogFilesEnabled() {
return isSeparateLogFilesEnabled;
}
-int getBackgroundImageOpacity() {
- return backgroundImageOpacity;
-}
-
-void setBackgroundImageOpacity(int opacity) {
- backgroundImageOpacity = std::clamp(opacity, 0, 100);
-}
-
-bool getShowBackgroundImage() {
- return showBackgroundImage;
-}
-
-void setShowBackgroundImage(bool show) {
- showBackgroundImage = show;
-}
-
bool getPSNSignedIn() {
return isPSNSignedIn;
}
@@ -764,23 +553,14 @@ void load(const std::filesystem::path& path) {
isNeo = toml::find_or(general, "isPS4Pro", false);
isDevKit = toml::find_or(general, "isDevKit", false);
isPSNSignedIn = toml::find_or(general, "isPSNSignedIn", false);
- playBGM = toml::find_or(general, "playBGM", false);
isTrophyPopupDisabled = toml::find_or(general, "isTrophyPopupDisabled", false);
trophyNotificationDuration =
toml::find_or(general, "trophyNotificationDuration", 5.0);
- BGMvolume = toml::find_or(general, "BGMvolume", 50);
enableDiscordRPC = toml::find_or(general, "enableDiscordRPC", true);
logFilter = toml::find_or(general, "logFilter", "");
logType = toml::find_or(general, "logType", "sync");
userName = toml::find_or(general, "userName", "shadPS4");
- if (Common::g_is_release) {
- updateChannel = toml::find_or(general, "updateChannel", "Release");
- } else {
- updateChannel = toml::find_or(general, "updateChannel", "Nightly");
- }
isShowSplash = toml::find_or(general, "showSplash", true);
- isAutoUpdate = toml::find_or(general, "autoUpdate", false);
- isAlwaysShowChangelog = toml::find_or(general, "alwaysShowChangelog", false);
isSideTrophy = toml::find_or(general, "sideTrophy", "right");
compatibilityData = toml::find_or(general, "compatibilityEnabled", false);
checkCompatibilityOnStartup =
@@ -793,7 +573,6 @@ void load(const std::filesystem::path& path) {
cursorState = toml::find_or(input, "cursorState", HideCursorState::Idle);
cursorHideTimeout = toml::find_or(input, "cursorHideTimeout", 5);
- backButtonBehavior = toml::find_or(input, "backButtonBehavior", "left");
useSpecialPad = toml::find_or(input, "useSpecialPad", false);
specialPadClass = toml::find_or(input, "specialPadClass", 1);
isMotionControlsEnabled = toml::find_or(input, "isMotionControlsEnabled", true);
@@ -841,13 +620,6 @@ void load(const std::filesystem::path& path) {
const toml::value& gui = data.at("GUI");
load_game_size = toml::find_or(gui, "loadGameSizeEnabled", true);
- m_icon_size = toml::find_or(gui, "iconSize", 0);
- m_icon_size_grid = toml::find_or(gui, "iconSizeGrid", 0);
- m_slider_pos = toml::find_or(gui, "sliderPos", 0);
- m_slider_pos_grid = toml::find_or(gui, "sliderPosGrid", 0);
- mw_themes = toml::find_or(gui, "theme", 0);
- m_window_size_W = toml::find_or(gui, "mw_width", 0);
- m_window_size_H = toml::find_or(gui, "mw_height", 0);
const auto install_dir_array =
toml::find_or>(gui, "installDirs", {});
@@ -872,16 +644,6 @@ void load(const std::filesystem::path& path) {
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {});
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
- main_window_geometry_x = toml::find_or(gui, "geometry_x", 0);
- main_window_geometry_y = toml::find_or(gui, "geometry_y", 0);
- main_window_geometry_w = toml::find_or(gui, "geometry_w", 0);
- main_window_geometry_h = toml::find_or(gui, "geometry_h", 0);
- m_elf_viewer = toml::find_or>(gui, "elfDirs", {});
- m_recent_files = toml::find_or>(gui, "recentFiles", {});
- m_table_mode = toml::find_or(gui, "gameTableMode", 0);
- emulator_language = toml::find_or(gui, "emulatorLanguage", "en_US");
- backgroundImageOpacity = toml::find_or(gui, "backgroundImageOpacity", 50);
- showBackgroundImage = toml::find_or(gui, "showBackgroundImage", true);
}
if (data.contains("Settings")) {
@@ -894,18 +656,6 @@ void load(const std::filesystem::path& path) {
const toml::value& keys = data.at("Keys");
trophyKey = toml::find_or(keys, "TrophyKey", "");
}
-
- // Check if the loaded language is in the allowed list
- const std::vector allowed_languages = {
- "ar_SA", "da_DK", "de_DE", "el_GR", "en_US", "es_ES", "fa_IR", "fi_FI", "fr_FR", "hu_HU",
- "id_ID", "it_IT", "ja_JP", "ko_KR", "lt_LT", "nb_NO", "nl_NL", "pl_PL", "pt_BR", "pt_PT",
- "ro_RO", "ru_RU", "sq_AL", "sv_SE", "tr_TR", "uk_UA", "vi_VN", "zh_CN", "zh_TW"};
-
- if (std::find(allowed_languages.begin(), allowed_languages.end(), emulator_language) ==
- allowed_languages.end()) {
- emulator_language = "en_US"; // Default to en_US if not in the list
- save(path);
- }
}
void sortTomlSections(toml::ordered_value& data) {
@@ -966,23 +716,17 @@ void save(const std::filesystem::path& path) {
data["General"]["isPSNSignedIn"] = isPSNSignedIn;
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
- data["General"]["playBGM"] = playBGM;
- data["General"]["BGMvolume"] = BGMvolume;
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
data["General"]["logFilter"] = logFilter;
data["General"]["logType"] = logType;
data["General"]["userName"] = userName;
- data["General"]["updateChannel"] = updateChannel;
data["General"]["chooseHomeTab"] = chooseHomeTab;
data["General"]["showSplash"] = isShowSplash;
- data["General"]["autoUpdate"] = isAutoUpdate;
- data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["Input"]["cursorState"] = cursorState;
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
- data["Input"]["backButtonBehavior"] = backButtonBehavior;
data["Input"]["useSpecialPad"] = useSpecialPad;
data["Input"]["specialPadClass"] = specialPadClass;
data["Input"]["isMotionControlsEnabled"] = isMotionControlsEnabled;
@@ -1045,9 +789,6 @@ void save(const std::filesystem::path& path) {
data["GUI"]["addonInstallDir"] =
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
- data["GUI"]["emulatorLanguage"] = emulator_language;
- data["GUI"]["backgroundImageOpacity"] = backgroundImageOpacity;
- data["GUI"]["showBackgroundImage"] = showBackgroundImage;
data["Settings"]["consoleLanguage"] = m_language;
// Sorting of TOML sections
@@ -1056,53 +797,6 @@ void save(const std::filesystem::path& path) {
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
-
- saveMainWindow(path);
-}
-
-void saveMainWindow(const std::filesystem::path& path) {
- toml::ordered_value data;
-
- std::error_code error;
- if (std::filesystem::exists(path, error)) {
- try {
- std::ifstream ifs;
- ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
- ifs.open(path, std::ios_base::binary);
- data = toml::parse(
- ifs, std::string{fmt::UTF(path.filename().u8string()).data});
- } catch (const std::exception& ex) {
- fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what());
- return;
- }
- } else {
- if (error) {
- fmt::print("Filesystem error: {}\n", error.message());
- }
- fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
- }
-
- data["GUI"]["mw_width"] = m_window_size_W;
- data["GUI"]["mw_height"] = m_window_size_H;
- data["GUI"]["theme"] = mw_themes;
- data["GUI"]["iconSize"] = m_icon_size;
- data["GUI"]["sliderPos"] = m_slider_pos;
- data["GUI"]["iconSizeGrid"] = m_icon_size_grid;
- data["GUI"]["sliderPosGrid"] = m_slider_pos_grid;
- data["GUI"]["gameTableMode"] = m_table_mode;
- data["GUI"]["geometry_x"] = main_window_geometry_x;
- data["GUI"]["geometry_y"] = main_window_geometry_y;
- data["GUI"]["geometry_w"] = main_window_geometry_w;
- data["GUI"]["geometry_h"] = main_window_geometry_h;
- data["GUI"]["elfDirs"] = m_elf_viewer;
- data["GUI"]["recentFiles"] = m_recent_files;
-
- // Sorting of TOML sections
- sortTomlSections(data);
-
- std::ofstream file(path, std::ios::binary);
- file << data;
- file.close();
}
void setDefaultValues() {
@@ -1112,31 +806,22 @@ void setDefaultValues() {
isPSNSignedIn = false;
isFullscreen = false;
isTrophyPopupDisabled = false;
- playBGM = false;
- BGMvolume = 50;
enableDiscordRPC = true;
screenWidth = 1280;
screenHeight = 720;
logFilter = "";
logType = "sync";
userName = "shadPS4";
- if (Common::g_is_release) {
- updateChannel = "Release";
- } else {
- updateChannel = "Nightly";
- }
+
chooseHomeTab = "General";
cursorState = HideCursorState::Idle;
cursorHideTimeout = 5;
trophyNotificationDuration = 6.0;
- backButtonBehavior = "left";
useSpecialPad = false;
specialPadClass = 1;
isDebugDump = false;
isShaderDebug = false;
isShowSplash = false;
- isAutoUpdate = false;
- isAlwaysShowChangelog = false;
isSideTrophy = "right";
isNullGpu = false;
shouldDumpShaders = false;
@@ -1148,13 +833,10 @@ void setDefaultValues() {
vkHostMarkers = false;
vkGuestMarkers = false;
rdocEnable = false;
- emulator_language = "en_US";
m_language = 1;
gpuId = -1;
compatibilityData = false;
checkCompatibilityOnStartup = false;
- backgroundImageOpacity = 50;
- showBackgroundImage = true;
}
constexpr std::string_view GetDefaultKeyboardConfig() {
@@ -1180,7 +862,7 @@ l3 = x
r3 = m
options = enter
-touchpad = space
+touchpad_center = space
pad_up = up
pad_down = down
@@ -1212,7 +894,7 @@ r2 = r2
r3 = r3
options = options
-touchpad = back
+touchpad_center = back
pad_up = pad_up
pad_down = pad_down
diff --git a/src/common/config.h b/src/common/config.h
index 404854ae2..38114983f 100644
--- a/src/common/config.h
+++ b/src/common/config.h
@@ -18,170 +18,116 @@ enum HideCursorState : int { Never, Idle, Always };
void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path);
-void saveMainWindow(const std::filesystem::path& path);
std::string getTrophyKey();
void setTrophyKey(std::string key);
+bool getIsFullscreen();
+void setIsFullscreen(bool enable);
+std::string getFullscreenMode();
+void setFullscreenMode(std::string mode);
+u32 getScreenWidth();
+u32 getScreenHeight();
+void setScreenWidth(u32 width);
+void setScreenHeight(u32 height);
+bool debugDump();
+void setDebugDump(bool enable);
+s32 getGpuId();
+void setGpuId(s32 selectedGpuId);
+bool allowHDR();
+void setAllowHDR(bool enable);
+bool collectShadersForDebug();
+void setCollectShaderForDebug(bool enable);
+bool showSplash();
+void setShowSplash(bool enable);
+std::string sideTrophy();
+void setSideTrophy(std::string side);
+bool nullGpu();
+void setNullGpu(bool enable);
+bool copyGPUCmdBuffers();
+void setCopyGPUCmdBuffers(bool enable);
+bool dumpShaders();
+void setDumpShaders(bool enable);
+u32 vblankDiv();
+void setVblankDiv(u32 value);
+bool getisTrophyPopupDisabled();
+void setisTrophyPopupDisabled(bool disable);
+s16 getCursorState();
+void setCursorState(s16 cursorState);
+bool vkValidationEnabled();
+void setVkValidation(bool enable);
+bool vkValidationSyncEnabled();
+void setVkSyncValidation(bool enable);
+bool getVkCrashDiagnosticEnabled();
+void setVkCrashDiagnosticEnabled(bool enable);
+bool getVkHostMarkersEnabled();
+void setVkHostMarkersEnabled(bool enable);
+bool getVkGuestMarkersEnabled();
+void setVkGuestMarkersEnabled(bool enable);
+bool getEnableDiscordRPC();
+void setEnableDiscordRPC(bool enable);
+bool isRdocEnabled();
+void setRdocEnabled(bool enable);
+std::string getLogType();
+void setLogType(const std::string& type);
+std::string getLogFilter();
+void setLogFilter(const std::string& type);
+double getTrophyNotificationDuration();
+void setTrophyNotificationDuration(double newTrophyNotificationDuration);
+int getCursorHideTimeout();
+void setCursorHideTimeout(int newcursorHideTimeout);
+void setSeparateLogFilesEnabled(bool enabled);
+bool getSeparateLogFilesEnabled();
+u32 GetLanguage();
+void setLanguage(u32 language);
+void setUseSpecialPad(bool use);
+bool getUseSpecialPad();
+void setSpecialPadClass(int type);
+int getSpecialPadClass();
+bool getPSNSignedIn();
+void setPSNSignedIn(bool sign); // no ui setting
+bool patchShaders(); // no set
+bool fpsColor(); // no set
+bool isNeoModeConsole();
+void setNeoMode(bool enable); // no ui setting
+bool isDevKitConsole(); // no set
+bool vkValidationGpuEnabled(); // no set
+bool getIsMotionControlsEnabled();
+void setIsMotionControlsEnabled(bool use);
+
+// TODO
bool GetLoadGameSizeEnabled();
std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable);
-bool getIsFullscreen();
-bool getShowLabelsUnderIcons();
-bool setShowLabelsUnderIcons();
-std::string getFullscreenMode();
-bool isNeoModeConsole();
-bool isDevKitConsole();
-bool getPlayBGM();
-int getBGMvolume();
-bool getisTrophyPopupDisabled();
-bool getEnableDiscordRPC();
bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup();
-int getBackgroundImageOpacity();
-bool getShowBackgroundImage();
-bool getPSNSignedIn();
-
-std::string getLogFilter();
-std::string getLogType();
std::string getUserName();
-std::string getUpdateChannel();
std::string getChooseHomeTab();
-
-s16 getCursorState();
-int getCursorHideTimeout();
-double getTrophyNotificationDuration();
-std::string getBackButtonBehavior();
-bool getUseSpecialPad();
-int getSpecialPadClass();
-bool getIsMotionControlsEnabled();
bool GetUseUnifiedInputConfig();
void SetUseUnifiedInputConfig(bool use);
bool GetOverrideControllerColor();
void SetOverrideControllerColor(bool enable);
int* GetControllerCustomColor();
void SetControllerCustomColor(int r, int b, int g);
-
-u32 getScreenWidth();
-u32 getScreenHeight();
-s32 getGpuId();
-bool allowHDR();
-
-bool debugDump();
-bool collectShadersForDebug();
-bool showSplash();
-bool autoUpdate();
-bool alwaysShowChangelog();
-std::string sideTrophy();
-bool nullGpu();
-bool copyGPUCmdBuffers();
-bool dumpShaders();
-bool patchShaders();
-bool isRdocEnabled();
-bool fpsColor();
-u32 vblankDiv();
-
-void setDebugDump(bool enable);
-void setCollectShaderForDebug(bool enable);
-void setShowSplash(bool enable);
-void setAutoUpdate(bool enable);
-void setAlwaysShowChangelog(bool enable);
-void setSideTrophy(std::string side);
-void setNullGpu(bool enable);
-void setAllowHDR(bool enable);
-void setCopyGPUCmdBuffers(bool enable);
-void setDumpShaders(bool enable);
-void setVblankDiv(u32 value);
-void setGpuId(s32 selectedGpuId);
-void setScreenWidth(u32 width);
-void setScreenHeight(u32 height);
-void setIsFullscreen(bool enable);
-void setFullscreenMode(std::string mode);
-void setisTrophyPopupDisabled(bool disable);
-void setPlayBGM(bool enable);
-void setBGMvolume(int volume);
-void setEnableDiscordRPC(bool enable);
-void setLanguage(u32 language);
-void setNeoMode(bool enable);
void setUserName(const std::string& type);
-void setUpdateChannel(const std::string& type);
void setChooseHomeTab(const std::string& type);
void setGameInstallDirs(const std::vector& dirs_config);
void setAllGameInstallDirs(const std::vector& dirs_config);
void setSaveDataPath(const std::filesystem::path& path);
void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use);
-void setBackgroundImageOpacity(int opacity);
-void setShowBackgroundImage(bool show);
-void setPSNSignedIn(bool sign);
-
-void setCursorState(s16 cursorState);
-void setCursorHideTimeout(int newcursorHideTimeout);
-void setTrophyNotificationDuration(double newTrophyNotificationDuration);
-void setBackButtonBehavior(const std::string& type);
-void setUseSpecialPad(bool use);
-void setSpecialPadClass(int type);
-void setIsMotionControlsEnabled(bool use);
-
-void setLogType(const std::string& type);
-void setLogFilter(const std::string& type);
-void setSeparateLogFilesEnabled(bool enabled);
-bool getSeparateLogFilesEnabled();
-void setVkValidation(bool enable);
-void setVkSyncValidation(bool enable);
-void setRdocEnabled(bool enable);
-
-bool vkValidationEnabled();
-bool vkValidationSyncEnabled();
-bool vkValidationGpuEnabled();
-bool getVkCrashDiagnosticEnabled();
-bool getVkHostMarkersEnabled();
-bool getVkGuestMarkersEnabled();
-void setVkCrashDiagnosticEnabled(bool enable);
-void setVkHostMarkersEnabled(bool enable);
-void setVkGuestMarkersEnabled(bool enable);
-
// Gui
-void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
void removeGameInstallDir(const std::filesystem::path& dir);
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
void setAddonInstallDir(const std::filesystem::path& dir);
-void setMainWindowTheme(u32 theme);
-void setIconSize(u32 size);
-void setIconSizeGrid(u32 size);
-void setSliderPosition(u32 pos);
-void setSliderPositionGrid(u32 pos);
-void setTableMode(u32 mode);
-void setMainWindowWidth(u32 width);
-void setMainWindowHeight(u32 height);
-void setElfViewer(const std::vector& elfList);
-void setRecentFiles(const std::vector& recentFiles);
-void setEmulatorLanguage(std::string language);
-u32 getMainWindowGeometryX();
-u32 getMainWindowGeometryY();
-u32 getMainWindowGeometryW();
-u32 getMainWindowGeometryH();
const std::vector getGameInstallDirs();
const std::vector getGameInstallDirsEnabled();
std::filesystem::path getAddonInstallDir();
-u32 getMainWindowTheme();
-u32 getIconSize();
-u32 getIconSizeGrid();
-u32 getSliderPosition();
-u32 getSliderPositionGrid();
-u32 getTableMode();
-u32 getMainWindowWidth();
-u32 getMainWindowHeight();
-std::vector getElfViewer();
-std::vector getRecentFiles();
-std::string getEmulatorLanguage();
void setDefaultValues();
// todo: name and function location pending
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = "");
-// settings
-u32 GetLanguage();
}; // namespace Config
diff --git a/src/common/io_file.h b/src/common/io_file.h
index d7784927c..58eb7d26b 100644
--- a/src/common/io_file.h
+++ b/src/common/io_file.h
@@ -186,7 +186,9 @@ public:
template
size_t WriteRaw(const void* data, size_t size) const {
- return std::fwrite(data, sizeof(T), size, file);
+ auto bytes = std::fwrite(data, sizeof(T), size, file);
+ std::fflush(file);
+ return bytes;
}
template
diff --git a/src/core/cpu_patches.cpp b/src/core/cpu_patches.cpp
index 8937ef04b..8512858e9 100644
--- a/src/core/cpu_patches.cpp
+++ b/src/core/cpu_patches.cpp
@@ -88,7 +88,8 @@ static bool FilterTcbAccess(const ZydisDecodedOperand* operands) {
dst_op.reg.value <= ZYDIS_REGISTER_R15;
}
-static void GenerateTcbAccess(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
+static void GenerateTcbAccess(void* /* address */, const ZydisDecodedOperand* operands,
+ Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
#if defined(_WIN32)
@@ -126,7 +127,8 @@ static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
return !cpu.has(Cpu::tSSE4a);
}
-static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
+static void GenerateEXTRQ(void* /* address */, const ZydisDecodedOperand* operands,
+ Xbyak::CodeGenerator& c) {
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
@@ -245,7 +247,8 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
}
}
-static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
+static void GenerateINSERTQ(void* /* address */, const ZydisDecodedOperand* operands,
+ Xbyak::CodeGenerator& c) {
bool immediateForm = operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operands[3].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
@@ -383,8 +386,44 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
}
}
+static void ReplaceMOVNT(void* address, u8 rep_prefix) {
+ // Find the opcode byte
+ // There can be any amount of prefixes but the instruction can't be more than 15 bytes
+ // And we know for sure this is a MOVNTSS/MOVNTSD
+ bool found = false;
+ bool rep_prefix_found = false;
+ int index = 0;
+ u8* ptr = reinterpret_cast(address);
+ for (int i = 0; i < 15; i++) {
+ if (ptr[i] == rep_prefix) {
+ rep_prefix_found = true;
+ } else if (ptr[i] == 0x2B) {
+ index = i;
+ found = true;
+ break;
+ }
+ }
+
+ // Some sanity checks
+ ASSERT(found);
+ ASSERT(index >= 2);
+ ASSERT(ptr[index - 1] == 0x0F);
+ ASSERT(rep_prefix_found);
+
+ // This turns the MOVNTSS/MOVNTSD to a MOVSS/MOVSD m, xmm
+ ptr[index] = 0x11;
+}
+
+static void ReplaceMOVNTSS(void* address, const ZydisDecodedOperand*, Xbyak::CodeGenerator&) {
+ ReplaceMOVNT(address, 0xF3);
+}
+
+static void ReplaceMOVNTSD(void* address, const ZydisDecodedOperand*, Xbyak::CodeGenerator&) {
+ ReplaceMOVNT(address, 0xF2);
+}
+
using PatchFilter = bool (*)(const ZydisDecodedOperand*);
-using InstructionGenerator = void (*)(const ZydisDecodedOperand*, Xbyak::CodeGenerator&);
+using InstructionGenerator = void (*)(void*, const ZydisDecodedOperand*, Xbyak::CodeGenerator&);
struct PatchInfo {
/// Filter for more granular patch conditions past just the instruction mnemonic.
PatchFilter filter;
@@ -400,6 +439,8 @@ static const std::unordered_map Patches = {
// SSE4a
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
+ {ZYDIS_MNEMONIC_MOVNTSS, {FilterNoSSE4a, ReplaceMOVNTSS, false}},
+ {ZYDIS_MNEMONIC_MOVNTSD, {FilterNoSSE4a, ReplaceMOVNTSD, false}},
#if defined(_WIN32)
// Windows needs a trampoline.
@@ -477,7 +518,7 @@ static std::pair TryPatch(u8* code, PatchModule* module) {
auto& trampoline_gen = module->trampoline_gen;
const auto trampoline_ptr = trampoline_gen.getCurr();
- patch_info.generator(operands, trampoline_gen);
+ patch_info.generator(code, operands, trampoline_gen);
// Return to the following instruction at the end of the trampoline.
trampoline_gen.jmp(code + instruction.length);
@@ -485,7 +526,7 @@ static std::pair TryPatch(u8* code, PatchModule* module) {
// Replace instruction with near jump to the trampoline.
patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR);
} else {
- patch_info.generator(operands, patch_gen);
+ patch_info.generator(code, operands, patch_gen);
}
const auto patch_size = patch_gen.getCurr() - code;
diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp
index 4dad44874..b237ab7d9 100644
--- a/src/core/file_sys/fs.cpp
+++ b/src/core/file_sys/fs.cpp
@@ -10,6 +10,8 @@
namespace Core::FileSys {
+bool MntPoints::ignore_game_patches = false;
+
std::string RemoveTrailingSlashes(const std::string& path) {
// Remove trailing slashes to make comparisons simpler.
std::string path_sanitized = path;
@@ -77,7 +79,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
patch_path /= rel_path;
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&
- !force_base_path && std::filesystem::exists(patch_path)) {
+ !force_base_path && !ignore_game_patches && std::filesystem::exists(patch_path)) {
return patch_path;
}
@@ -137,7 +139,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
return std::optional(current_path);
};
- if (!force_base_path) {
+ if (!force_base_path && !ignore_game_patches) {
if (const auto path = search(patch_path)) {
return *path;
}
diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h
index 6638b48e8..4a2aa56c1 100644
--- a/src/core/file_sys/fs.h
+++ b/src/core/file_sys/fs.h
@@ -21,6 +21,7 @@ class MntPoints {
static constexpr bool NeedsCaseInsensitiveSearch = true;
#endif
public:
+ static bool ignore_game_patches;
struct MntPair {
std::filesystem::path host_path;
std::string mount; // e.g /app0
diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp
index 911ae4cd5..4d1b116c5 100644
--- a/src/core/libraries/kernel/equeue.cpp
+++ b/src/core/libraries/kernel/equeue.cpp
@@ -125,7 +125,6 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
.count();
count = WaitForSmallTimer(ev, num, std::max(0l, long(micros - time_waited)));
}
- small_timer_event.event.data = 0;
}
if (ev->flags & SceKernelEvent::Flags::OneShot) {
@@ -179,39 +178,46 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
}
bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) {
- // We assume that only one timer event (with the same ident across calls)
- // can be posted to the queue, based on observations so far. In the opposite case,
- // the small timer storage and wait logic should be reworked.
- ASSERT(!HasSmallTimer() || small_timer_event.event.ident == ev.event.ident);
- ev.time_added = std::chrono::steady_clock::now();
- small_timer_event = std::move(ev);
+ SmallTimer st;
+ st.event = ev.event;
+ st.added = std::chrono::steady_clock::now();
+ st.interval = std::chrono::microseconds{ev.event.data};
+ {
+ std::scoped_lock lock{m_mutex};
+ m_small_timers[st.event.ident] = std::move(st);
+ }
return true;
}
int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
- int count{};
-
- ASSERT(num == 1);
+ ASSERT(num >= 1);
auto curr_clock = std::chrono::steady_clock::now();
const auto wait_end_us = (micros == 0) ? std::chrono::steady_clock::time_point::max()
: curr_clock + std::chrono::microseconds{micros};
-
+ int count = 0;
do {
curr_clock = std::chrono::steady_clock::now();
{
std::scoped_lock lock{m_mutex};
- if ((curr_clock - small_timer_event.time_added) >
- std::chrono::microseconds{small_timer_event.event.data}) {
- ev[count++] = small_timer_event.event;
- small_timer_event.event.data = 0;
- break;
+ for (auto it = m_small_timers.begin(); it != m_small_timers.end() && count < num;) {
+ const SmallTimer& st = it->second;
+
+ if (curr_clock - st.added >= st.interval) {
+ ev[count++] = st.event;
+ it = m_small_timers.erase(it);
+ } else {
+ ++it;
+ }
}
+
+ if (count > 0)
+ return count;
}
std::this_thread::yield();
} while (curr_clock < wait_end_us);
- return count;
+ return 0;
}
bool EqueueInternal::EventExists(u64 id, s16 filter) {
@@ -326,6 +332,11 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
// `HrTimerSpinlockThresholdUs`) and fall back to boost asio timers if the time to tick is
// large. Even for large delays, we truncate a small portion to complete the wait
// using the spinlock, prioritizing precision.
+
+ if (eq->EventExists(event.event.ident, event.event.filter)) {
+ eq->RemoveEvent(id, SceKernelEvent::Filter::HrTimer);
+ }
+
if (total_us < HrTimerSpinlockThresholdUs) {
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
}
diff --git a/src/core/libraries/kernel/equeue.h b/src/core/libraries/kernel/equeue.h
index e6e3c0c53..fbc209265 100644
--- a/src/core/libraries/kernel/equeue.h
+++ b/src/core/libraries/kernel/equeue.h
@@ -9,6 +9,7 @@
#include
#include
+#include
#include "common/rdtsc.h"
#include "common/types.h"
@@ -135,6 +136,12 @@ private:
};
class EqueueInternal {
+ struct SmallTimer {
+ SceKernelEvent event;
+ std::chrono::steady_clock::time_point added;
+ std::chrono::microseconds interval;
+ };
+
public:
explicit EqueueInternal(std::string_view name) : m_name(name) {}
@@ -151,13 +158,14 @@ public:
int GetTriggeredEvents(SceKernelEvent* ev, int num);
bool AddSmallTimer(EqueueEvent& event);
- bool HasSmallTimer() const {
- return small_timer_event.event.data != 0;
+ bool HasSmallTimer() {
+ std::scoped_lock lock{m_mutex};
+ return !m_small_timers.empty();
}
bool RemoveSmallTimer(u64 id) {
- if (HasSmallTimer() && small_timer_event.event.ident == id) {
- small_timer_event = {};
- return true;
+ if (HasSmallTimer()) {
+ std::scoped_lock lock{m_mutex};
+ return m_small_timers.erase(id) > 0;
}
return false;
}
@@ -170,8 +178,8 @@ private:
std::string m_name;
std::mutex m_mutex;
std::vector m_events;
- EqueueEvent small_timer_event{};
std::condition_variable m_cond;
+ std::unordered_map m_small_timers;
};
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp
index 29b8ea01a..5f7cb9f87 100644
--- a/src/core/libraries/kernel/file_system.cpp
+++ b/src/core/libraries/kernel/file_system.cpp
@@ -293,6 +293,7 @@ s64 PS4_SYSV_ABI write(s32 fd, const void* buf, size_t nbytes) {
}
return result;
}
+
return file->f.WriteRaw(buf, nbytes);
}
@@ -750,7 +751,24 @@ s32 PS4_SYSV_ABI posix_rename(const char* from, const char* to) {
*__Error() = POSIX_ENOTEMPTY;
return -1;
}
+
+ // On Windows, std::filesystem::rename will error if the file has been opened before.
std::filesystem::copy(src_path, dst_path, std::filesystem::copy_options::overwrite_existing);
+ auto* h = Common::Singleton::Instance();
+ auto file = h->GetFile(src_path);
+ if (file) {
+ // We need to force ReadWrite if the file had Write access before
+ // Otherwise f.Open will clear the file contents.
+ auto access_mode = file->f.GetAccessMode() == Common::FS::FileAccessMode::Write
+ ? Common::FS::FileAccessMode::ReadWrite
+ : file->f.GetAccessMode();
+ file->f.Close();
+ std::filesystem::remove(src_path);
+ file->f.Open(dst_path, access_mode);
+ } else {
+ std::filesystem::remove(src_path);
+ }
+
return ORBIS_OK;
}
@@ -1050,6 +1068,7 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("4wSze92BhLI", "libkernel", 1, "libkernel", 1, 1, sceKernelWrite);
LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, readv);
LIB_FUNCTION("YSHRBRLn2pI", "libkernel", 1, "libkernel", 1, 1, writev);
+ LIB_FUNCTION("kAt6VDbHmro", "libkernel", 1, "libkernel", 1, 1, sceKernelWritev);
LIB_FUNCTION("Oy6IpwgtYOk", "libScePosix", 1, "libkernel", 1, 1, posix_lseek);
LIB_FUNCTION("Oy6IpwgtYOk", "libkernel", 1, "libkernel", 1, 1, posix_lseek);
LIB_FUNCTION("oib76F-12fk", "libkernel", 1, "libkernel", 1, 1, sceKernelLseek);
diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp
index 180850217..61d2e2f2b 100644
--- a/src/core/libraries/kernel/kernel.cpp
+++ b/src/core/libraries/kernel/kernel.cpp
@@ -76,21 +76,21 @@ static PS4_SYSV_ABI void stack_chk_fail() {
UNREACHABLE();
}
-static thread_local int g_posix_errno = 0;
+static thread_local s32 g_posix_errno = 0;
-int* PS4_SYSV_ABI __Error() {
+s32* PS4_SYSV_ABI __Error() {
return &g_posix_errno;
}
-void ErrSceToPosix(int error) {
+void ErrSceToPosix(s32 error) {
g_posix_errno = error - ORBIS_KERNEL_ERROR_UNKNOWN;
}
-int ErrnoToSceKernelError(int error) {
+s32 ErrnoToSceKernelError(s32 error) {
return error + ORBIS_KERNEL_ERROR_UNKNOWN;
}
-void SetPosixErrno(int e) {
+void SetPosixErrno(s32 e) {
// Some error numbers are different between supported OSes
switch (e) {
case EPERM:
@@ -132,15 +132,15 @@ void SetPosixErrno(int e) {
}
}
-static uint64_t g_mspace_atomic_id_mask = 0;
-static uint64_t g_mstate_table[64] = {0};
+static u64 g_mspace_atomic_id_mask = 0;
+static u64 g_mstate_table[64] = {0};
struct HeapInfoInfo {
- uint64_t size = sizeof(HeapInfoInfo);
- uint32_t flag;
- uint32_t getSegmentInfo;
- uint64_t* mspace_atomic_id_mask;
- uint64_t* mstate_table;
+ u64 size = sizeof(HeapInfoInfo);
+ u32 flag;
+ u32 getSegmentInfo;
+ u64* mspace_atomic_id_mask;
+ u64* mstate_table;
};
void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) {
@@ -159,7 +159,7 @@ struct OrbisKernelUuid {
};
static_assert(sizeof(OrbisKernelUuid) == 0x10);
-int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
+s32 PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
if (!orbisUuid) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
@@ -176,7 +176,7 @@ int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
return ORBIS_OK;
}
-int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
+s32 PS4_SYSV_ABI kernel_ioctl(s32 fd, u64 cmd, VA_ARGS) {
auto* h = Common::Singleton::Instance();
auto* file = h->GetFile(fd);
if (file == nullptr) {
@@ -190,7 +190,7 @@ int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
return -1;
}
VA_CTX(ctx);
- int result = file->device->ioctl(cmd, &ctx);
+ s32 result = file->device->ioctl(cmd, &ctx);
LOG_TRACE(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} result = {}", fd, cmd, result);
if (result < 0) {
ErrSceToPosix(result);
@@ -204,15 +204,15 @@ const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
return path;
}
-int PS4_SYSV_ABI _sigprocmask() {
+s32 PS4_SYSV_ABI _sigprocmask() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI posix_getpagesize() {
+s32 PS4_SYSV_ABI posix_getpagesize() {
return 16_KB;
}
-int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
+s32 PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton::Instance();
auto sock = netcall->FindSocket(s);
@@ -221,7 +221,7 @@ int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1;
}
- int returncode = sock->GetSocketAddress(addr, paddrlen);
+ s32 returncode = sock->GetSocketAddress(addr, paddrlen);
if (returncode >= 0) {
LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode);
return 0;
@@ -230,6 +230,19 @@ int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
+
+// stubbed on non-devkit consoles
+s32 PS4_SYSV_ABI sceKernelGetGPI() {
+ LOG_DEBUG(Kernel, "called");
+ return ORBIS_OK;
+}
+
+// stubbed on non-devkit consoles
+s32 PS4_SYSV_ABI sceKernelSetGPO() {
+ LOG_DEBUG(Kernel, "called");
+ return ORBIS_OK;
+}
+
void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
service_thread = std::jthread{KernelServiceThread};
@@ -273,6 +286,13 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
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);
+
+ LIB_FUNCTION("4oXYe9Xmk0Q", "libkernel", 1, "libkernel", 1, 1, sceKernelGetGPI);
+ LIB_FUNCTION("ca7v6Cxulzs", "libkernel", 1, "libkernel", 1, 1, sceKernelSetGPO);
}
} // namespace Libraries::Kernel
diff --git a/src/core/libraries/kernel/kernel.h b/src/core/libraries/kernel/kernel.h
index aaa22aec1..0529c06d5 100644
--- a/src/core/libraries/kernel/kernel.h
+++ b/src/core/libraries/kernel/kernel.h
@@ -12,10 +12,10 @@ class SymbolsResolver;
namespace Libraries::Kernel {
-void ErrSceToPosix(int result);
-int ErrnoToSceKernelError(int e);
-void SetPosixErrno(int e);
-int* PS4_SYSV_ABI __Error();
+void ErrSceToPosix(s32 result);
+s32 ErrnoToSceKernelError(s32 e);
+void SetPosixErrno(s32 e);
+s32* PS4_SYSV_ABI __Error();
template
struct OrbisWrapperImpl;
@@ -33,7 +33,7 @@ struct OrbisWrapperImpl {
#define ORBIS(func) (Libraries::Kernel::OrbisWrapperImpl::wrap)
-int* PS4_SYSV_ABI __Error();
+s32* PS4_SYSV_ABI __Error();
void RegisterKernel(Core::Loader::SymbolsResolver* sym);
diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp
index 18676cbdf..114a096ca 100644
--- a/src/core/libraries/kernel/memory.cpp
+++ b/src/core/libraries/kernel/memory.cpp
@@ -23,8 +23,8 @@ u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
return memory->GetTotalDirectSize();
}
-int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
- u64 alignment, int memoryType, s64* physAddrOut) {
+s32 PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
+ u64 alignment, s32 memoryType, s64* physAddrOut) {
if (searchStart < 0 || searchEnd < 0) {
LOG_ERROR(Kernel_Vmm, "Invalid parameters!");
return ORBIS_KERNEL_ERROR_EINVAL;
@@ -71,13 +71,13 @@ int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u
return ORBIS_OK;
}
-s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(size_t len, size_t alignment, int memoryType,
+s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(u64 len, u64 alignment, s32 memoryType,
s64* physAddrOut) {
const auto searchEnd = static_cast(sceKernelGetDirectMemorySize());
return sceKernelAllocateDirectMemory(0, searchEnd, len, alignment, memoryType, physAddrOut);
}
-s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len) {
+s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, u64 len) {
if (len == 0) {
return ORBIS_OK;
}
@@ -87,7 +87,7 @@ s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len) {
return ORBIS_OK;
}
-s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, size_t len) {
+s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, u64 len) {
if (len == 0) {
return ORBIS_OK;
}
@@ -96,11 +96,10 @@ s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, size_t len) {
return ORBIS_OK;
}
-s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchEnd,
- size_t alignment, u64* physAddrOut,
- size_t* sizeOut) {
- LOG_WARNING(Kernel_Vmm, "called searchStart = {:#x}, searchEnd = {:#x}, alignment = {:#x}",
- searchStart, searchEnd, alignment);
+s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchEnd, u64 alignment,
+ u64* physAddrOut, u64* sizeOut) {
+ LOG_INFO(Kernel_Vmm, "called searchStart = {:#x}, searchEnd = {:#x}, alignment = {:#x}",
+ searchStart, searchEnd, alignment);
if (physAddrOut == nullptr || sizeOut == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
@@ -109,7 +108,7 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
auto* memory = Core::Memory::Instance();
PAddr physAddr{};
- size_t size{};
+ u64 size{};
s32 result = memory->DirectQueryAvailable(searchStart, searchEnd, alignment, &physAddr, &size);
if (size == 0) {
@@ -122,14 +121,14 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
return result;
}
-s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
- size_t infoSize) {
+s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, s32 flags, OrbisVirtualQueryInfo* info,
+ u64 infoSize) {
LOG_INFO(Kernel_Vmm, "called addr = {}, flags = {:#x}", fmt::ptr(addr), flags);
auto* memory = Core::Memory::Instance();
return memory->VirtualQuery(std::bit_cast(addr), flags, info);
}
-s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment) {
+s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, s32 flags, u64 alignment) {
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}, alignment = {:#x}",
fmt::ptr(*addr), len, flags, alignment);
if (addr == nullptr) {
@@ -159,7 +158,7 @@ s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u
return result;
}
-int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
+s32 PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, s32 prot, s32 flags,
s64 directMemoryStart, u64 alignment,
const char* name) {
LOG_INFO(Kernel_Vmm,
@@ -202,7 +201,7 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
return ret;
}
-int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
+s32 PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, s32 prot, s32 flags,
s64 directMemoryStart, u64 alignment) {
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment,
@@ -222,9 +221,10 @@ s32 PS4_SYSV_ABI sceKernelMapDirectMemory2(void** addr, u64 len, s32 type, s32 p
return ret;
}
-s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
- int flags, const char* name) {
-
+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;
@@ -243,22 +243,18 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t
const VAddr in_addr = reinterpret_cast(*addr_in_out);
const auto mem_prot = static_cast(prot);
const auto map_flags = static_cast(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");
}
-int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot) {
+s32 PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot) {
auto* memory = Core::Memory::Instance();
return memory->QueryProtection(std::bit_cast(addr), start, end, prot);
}
@@ -288,14 +284,14 @@ s32 PS4_SYSV_ABI sceKernelMtypeprotect(const void* addr, u64 size, s32 mtype, s3
return memory_manager->Protect(std::bit_cast(addr), size, protection_flags);
}
-int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
- size_t infoSize) {
- LOG_WARNING(Kernel_Vmm, "called offset = {:#x}, flags = {:#x}", offset, flags);
+s32 PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, s32 flags, OrbisQueryInfo* query_info,
+ u64 infoSize) {
+ LOG_INFO(Kernel_Vmm, "called offset = {:#x}, flags = {:#x}", offset, flags);
auto* memory = Core::Memory::Instance();
return memory->DirectMemoryQuery(offset, flags == 1, query_info);
}
-s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* out_size) {
+s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(u64* out_size) {
auto* memory = Core::Memory::Instance();
*out_size = memory->GetAvailableFlexibleSize();
LOG_INFO(Kernel_Vmm, "called size = {:#x}", *out_size);
@@ -307,7 +303,7 @@ void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]) {
linker->SetHeapAPI(func);
}
-int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
+s32 PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, s32* directMemoryTypeOut,
void** directMemoryStartOut,
void** directMemoryEndOut) {
LOG_WARNING(Kernel_Vmm, "called, direct memory addr = {:#x}", addr);
@@ -316,23 +312,23 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
directMemoryEndOut);
}
-int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
+s32 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(addr), start, end);
}
-s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
- int* numEntriesOut) {
+s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, s32 numEntries,
+ s32* numEntriesOut) {
return sceKernelBatchMap2(entries, numEntries, numEntriesOut,
MemoryFlags::SCE_KERNEL_MAP_FIXED); // 0x10, 0x410?
}
-s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEntries,
- int* numEntriesOut, int flags) {
- int result = ORBIS_OK;
- int processed = 0;
- for (int i = 0; i < numEntries; i++, processed++) {
+s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, s32 numEntries,
+ s32* numEntriesOut, s32 flags) {
+ s32 result = ORBIS_OK;
+ s32 processed = 0;
+ for (s32 i = 0; i < numEntries; i++, processed++) {
if (entries == nullptr || entries[i].length == 0 || entries[i].operation > 4) {
result = ORBIS_KERNEL_ERROR_EINVAL;
break; // break and assign a value to numEntriesOut.
@@ -622,7 +618,7 @@ s32 PS4_SYSV_ABI sceKernelConfiguredFlexibleMemorySize(u64* sizeOut) {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
+s32 PS4_SYSV_ABI sceKernelMunmap(void* addr, u64 len) {
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}", fmt::ptr(addr), len);
if (len == 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
@@ -631,8 +627,8 @@ int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
return memory->UnmapMemory(std::bit_cast(addr), len);
}
-int PS4_SYSV_ABI posix_munmap(void* addr, size_t len) {
- int result = sceKernelMunmap(addr, len);
+s32 PS4_SYSV_ABI posix_munmap(void* addr, u64 len) {
+ s32 result = sceKernelMunmap(addr, len);
if (result < 0) {
LOG_ERROR(Kernel_Pthread, "posix_munmap: error = {}", result);
ErrSceToPosix(result);
@@ -641,12 +637,12 @@ int PS4_SYSV_ABI posix_munmap(void* addr, size_t len) {
return result;
}
-static constexpr int MAX_PRT_APERTURES = 3;
+static constexpr s32 MAX_PRT_APERTURES = 3;
static constexpr VAddr PRT_AREA_START_ADDR = 0x1000000000;
-static constexpr size_t PRT_AREA_SIZE = 0xec00000000;
-static std::array, MAX_PRT_APERTURES> PrtApertures{};
+static constexpr u64 PRT_AREA_SIZE = 0xec00000000;
+static std::array, MAX_PRT_APERTURES> PrtApertures{};
-int PS4_SYSV_ABI sceKernelSetPrtAperture(int id, VAddr address, size_t size) {
+s32 PS4_SYSV_ABI sceKernelSetPrtAperture(s32 id, VAddr address, u64 size) {
if (id < 0 || id >= MAX_PRT_APERTURES) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
@@ -663,11 +659,14 @@ int PS4_SYSV_ABI sceKernelSetPrtAperture(int id, VAddr address, size_t size) {
"PRT aperture id = {}, address = {:#x}, size = {:#x} is set but not used", id,
address, size);
+ auto* memory = Core::Memory::Instance();
+ memory->SetPrtArea(id, address, size);
+
PrtApertures[id] = {address, size};
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceKernelGetPrtAperture(int id, VAddr* address, size_t* size) {
+s32 PS4_SYSV_ABI sceKernelGetPrtAperture(s32 id, VAddr* address, u64* size) {
if (id < 0 || id >= MAX_PRT_APERTURES) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
diff --git a/src/core/libraries/kernel/memory.h b/src/core/libraries/kernel/memory.h
index 6cefe0d07..ce4ec64fe 100644
--- a/src/core/libraries/kernel/memory.h
+++ b/src/core/libraries/kernel/memory.h
@@ -52,13 +52,13 @@ constexpr u32 ORBIS_KERNEL_MAXIMUM_NAME_LENGTH = 32;
struct OrbisQueryInfo {
uintptr_t start;
uintptr_t end;
- int memoryType;
+ s32 memoryType;
};
struct OrbisVirtualQueryInfo {
uintptr_t start;
uintptr_t end;
- size_t offset;
+ u64 offset;
s32 protection;
s32 memory_type;
u8 is_flexible : 1;
@@ -73,12 +73,12 @@ static_assert(sizeof(OrbisVirtualQueryInfo) == 72,
struct OrbisKernelBatchMapEntry {
void* start;
- size_t offset;
- size_t length;
+ u64 offset;
+ u64 length;
char protection;
char type;
- short reserved;
- int operation;
+ s16 reserved;
+ s32 operation;
};
enum class OrbisKernelMemoryPoolOpcode : u32 {
@@ -124,46 +124,44 @@ struct OrbisKernelMemoryPoolBatchEntry {
};
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
-int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
- u64 alignment, int memoryType, s64* physAddrOut);
-int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
+s32 PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
+ u64 alignment, s32 memoryType, s64* physAddrOut);
+s32 PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, s32 prot, s32 flags,
s64 directMemoryStart, u64 alignment,
const char* name);
-int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
+s32 PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, s32 prot, s32 flags,
s64 directMemoryStart, u64 alignment);
-s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(size_t len, size_t alignment, int memoryType,
+s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(u64 len, u64 alignment, s32 memoryType,
s64* physAddrOut);
-s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, size_t len);
-s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len);
-s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchEnd,
- size_t alignment, u64* physAddrOut,
- size_t* sizeOut);
-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);
-int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot);
+s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, u64 len);
+s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, u64 len);
+s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchEnd, u64 alignment,
+ u64* physAddrOut, u64* sizeOut);
+s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, s32 flags, OrbisVirtualQueryInfo* info,
+ u64 infoSize);
+s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, s32 flags, u64 alignment);
+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);
+s32 PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot);
s32 PS4_SYSV_ABI sceKernelMprotect(const void* addr, u64 size, s32 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);
-s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut);
+s32 PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, s32 flags, OrbisQueryInfo* query_info,
+ u64 infoSize);
+s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(u64* sizeOut);
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
-int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
+s32 PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, s32* directMemoryTypeOut,
void** directMemoryStartOut,
void** directMemoryEndOut);
-int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
+s32 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 sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, s32 numEntries,
+ s32* numEntriesOut);
+s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, s32 numEntries,
+ s32* numEntriesOut, s32 flags);
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, u64 len, const char* name);
@@ -176,7 +174,7 @@ 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);
+s32 PS4_SYSV_ABI sceKernelMunmap(void* addr, u64 len);
void RegisterMemory(Core::Loader::SymbolsResolver* sym);
diff --git a/src/core/libraries/kernel/threads/mutex.cpp b/src/core/libraries/kernel/threads/mutex.cpp
index 956e5ef65..3dbade96a 100644
--- a/src/core/libraries/kernel/threads/mutex.cpp
+++ b/src/core/libraries/kernel/threads/mutex.cpp
@@ -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);
diff --git a/src/core/libraries/ngs2/ngs2_impl.cpp b/src/core/libraries/ngs2/ngs2_impl.cpp
index 1248f76d7..141ac41ba 100644
--- a/src/core/libraries/ngs2/ngs2_impl.cpp
+++ b/src/core/libraries/ngs2/ngs2_impl.cpp
@@ -100,6 +100,11 @@ s32 SystemSetupCore(StackBuffer* stackBuffer, const OrbisNgs2SystemOption* optio
return ORBIS_NGS2_ERROR_INVALID_SAMPLE_RATE;
}
+ if (outSystem) {
+ // dummy handle
+ outSystem->systemHandle = 1;
+ }
+
return ORBIS_OK;
}
diff --git a/src/core/libraries/np_trophy/np_trophy.cpp b/src/core/libraries/np_trophy/np_trophy.cpp
index 6de84bd93..c0642f81c 100644
--- a/src/core/libraries/np_trophy/np_trophy.cpp
+++ b/src/core/libraries/np_trophy/np_trophy.cpp
@@ -164,10 +164,12 @@ s32 PS4_SYSV_ABI sceNpTrophyCreateContext(OrbisNpTrophyContext* context, int32_t
}
const auto ctx_id = trophy_contexts.insert(user_id, service_label);
- contexts_internal[key].context_id = ctx_id.index;
- LOG_INFO(Lib_NpTrophy, "New context = {}, user_id = {} service label = {}", ctx_id.index,
- user_id, service_label);
- *context = ctx_id.index;
+
+ *context = ctx_id.index + 1;
+ contexts_internal[key].context_id = *context;
+ LOG_INFO(Lib_NpTrophy, "New context = {}, user_id = {} service label = {}", *context, user_id,
+ service_label);
+
return ORBIS_OK;
}
@@ -179,21 +181,27 @@ s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(OrbisNpTrophyHandle* handle) {
if (trophy_handles.size() >= MaxTrophyHandles) {
return ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX;
}
- const auto handle_id = trophy_handles.insert();
- LOG_INFO(Lib_NpTrophy, "New handle = {}", handle_id.index);
- *handle = handle_id.index;
+ const auto handle_id = trophy_handles.insert();
+
+ *handle = handle_id.index + 1;
+ LOG_INFO(Lib_NpTrophy, "New handle = {}", *handle);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNpTrophyDestroyContext(OrbisNpTrophyContext context) {
LOG_INFO(Lib_NpTrophy, "Destroyed Context {}", context);
- if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
+ if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT) {
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
+ }
Common::SlotId contextId;
- contextId.index = context;
+ contextId.index = context - 1;
+
+ if (contextId.index >= trophy_contexts.size()) {
+ return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
+ }
ContextKey contextkey = trophy_contexts[contextId];
trophy_contexts.erase(contextId);
@@ -206,15 +214,17 @@ 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()) {
+ s32 handle_index = handle - 1;
+ if (handle_index >= trophy_handles.size()) {
LOG_ERROR(Lib_NpTrophy, "Invalid handle {}", handle);
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
}
- if (!trophy_handles.is_allocated({static_cast(handle)})) {
+
+ if (!trophy_handles.is_allocated({static_cast(handle_index)})) {
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
}
- trophy_handles.erase({static_cast(handle)});
+ trophy_handles.erase({static_cast(handle_index)});
LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle);
return ORBIS_OK;
}
diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp
index 42582783b..59964fa58 100644
--- a/src/core/libraries/pad/pad.cpp
+++ b/src/core/libraries/pad/pad.cpp
@@ -447,21 +447,18 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
// 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(
- 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->orientation = outputOrientation;
- controller->SetLastOrientation(outputOrientation);
- }
+ auto now = std::chrono::steady_clock::now();
+ float deltaTime =
+ std::chrono::duration_cast(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->orientation = outputOrientation;
+ controller->SetLastOrientation(outputOrientation);
}
pData->touchData.touchNum =
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
diff --git a/src/core/libraries/save_data/save_instance.cpp b/src/core/libraries/save_data/save_instance.cpp
index a7ce3d35f..05253eb23 100644
--- a/src/core/libraries/save_data/save_instance.cpp
+++ b/src/core/libraries/save_data/save_instance.cpp
@@ -22,25 +22,25 @@ static Core::FileSys::MntPoints* g_mnt = Common::Singleton default_title = {
- {"ja_JP", "セーブデータ"},
- {"en_US", "Saved Data"},
- {"fr_FR", "Données sauvegardées"},
- {"es_ES", "Datos guardados"},
- {"de_DE", "Gespeicherte Daten"},
- {"it_IT", "Dati salvati"},
- {"nl_NL", "Opgeslagen data"},
- {"pt_PT", "Dados guardados"},
- {"ru_RU", "Сохраненные данные"},
- {"ko_KR", "저장 데이터"},
- {"zh_CN", "保存数据"},
- {"fi_FI", "Tallennetut tiedot"},
- {"sv_SE", "Sparade data"},
- {"da_DK", "Gemte data"},
- {"no_NO", "Lagrede data"},
- {"pl_PL", "Zapisane dane"},
- {"pt_BR", "Dados salvos"},
- {"tr_TR", "Kayıtlı Veriler"},
+static const std::unordered_map default_title = {
+ {0/*"ja_JP"*/, "セーブデータ"},
+ {1/*"en_US"*/, "Saved Data"},
+ {2/*"fr_FR"*/, "Données sauvegardées"},
+ {3/*"es_ES"*/, "Datos guardados"},
+ {4/*"de_DE"*/, "Gespeicherte Daten"},
+ {5/*"it_IT"*/, "Dati salvati"},
+ {6/*"nl_NL"*/, "Opgeslagen data"},
+ {7/*"pt_PT"*/, "Dados guardados"},
+ {8/*"ru_RU"*/, "Сохраненные данные"},
+ {9/*"ko_KR"*/, "저장 데이터"},
+ {10/*"zh_CN"*/, "保存数据"},
+ {12/*"fi_FI"*/, "Tallennetut tiedot"},
+ {13/*"sv_SE"*/, "Sparade data"},
+ {14/*"da_DK"*/, "Gemte data"},
+ {15/*"no_NO"*/, "Lagrede data"},
+ {16/*"pl_PL"*/, "Zapisane dane"},
+ {17/*"pt_BR"*/, "Dados salvos"},
+ {19/*"tr_TR"*/, "Kayıtlı Veriler"},
};
// clang-format on
@@ -71,9 +71,9 @@ fs::path SaveInstance::GetParamSFOPath(const fs::path& dir_path) {
void SaveInstance::SetupDefaultParamSFO(PSF& param_sfo, std::string dir_name,
std::string game_serial) {
- std::string locale = Config::getEmulatorLanguage();
+ int locale = Config::GetLanguage();
if (!default_title.contains(locale)) {
- locale = "en_US";
+ locale = 1; // default to en_US if not found
}
#define P(type, key, ...) param_sfo.Add##type(std::string{key}, __VA_ARGS__)
diff --git a/src/core/libraries/videodec/videodec2.cpp b/src/core/libraries/videodec/videodec2.cpp
index 4f9379151..1c6044fe2 100644
--- a/src/core/libraries/videodec/videodec2.cpp
+++ b/src/core/libraries/videodec/videodec2.cpp
@@ -140,7 +140,7 @@ s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
- outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
+ (outputInfo->thisSize | 8) != sizeof(OrbisVideodec2OutputInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
@@ -167,7 +167,7 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
}
- if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
+ if ((outputInfo->thisSize | 8) != sizeof(OrbisVideodec2OutputInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
@@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
if (p1stPictureInfoOut) {
OrbisVideodec2AvcPictureInfo* picInfo =
static_cast(p1stPictureInfoOut);
- if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
+ if ((picInfo->thisSize | 16) != sizeof(OrbisVideodec2AvcPictureInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
}
diff --git a/src/core/libraries/videodec/videodec2.h b/src/core/libraries/videodec/videodec2.h
index abc8f8ab5..410ee8ea6 100644
--- a/src/core/libraries/videodec/videodec2.h
+++ b/src/core/libraries/videodec/videodec2.h
@@ -73,8 +73,10 @@ struct OrbisVideodec2OutputInfo {
u32 frameHeight;
void* frameBuffer;
u64 frameBufferSize;
+ u32 frameFormat;
+ u32 framePitchInBytes;
};
-static_assert(sizeof(OrbisVideodec2OutputInfo) == 0x30);
+static_assert(sizeof(OrbisVideodec2OutputInfo) == 0x38);
struct OrbisVideodec2FrameBuffer {
u64 thisSize;
diff --git a/src/core/libraries/videodec/videodec2_avc.h b/src/core/libraries/videodec/videodec2_avc.h
index 22293ee93..1975209cb 100644
--- a/src/core/libraries/videodec/videodec2_avc.h
+++ b/src/core/libraries/videodec/videodec2_avc.h
@@ -55,6 +55,23 @@ struct OrbisVideodec2AvcPictureInfo {
u8 pic_struct;
u8 field_pic_flag;
u8 bottom_field_flag;
+
+ u8 sequenceParameterSetPresentFlag;
+ u8 pictureParameterSetPresentFlag;
+ u8 auDelimiterPresentFlag;
+ u8 endOfSequencePresentFlag;
+ u8 endOfStreamPresentFlag;
+ u8 fillerDataPresentFlag;
+ u8 pictureTimingSeiPresentFlag;
+ u8 bufferingPeriodSeiPresentFlag;
+
+ u8 constraint_set0_flag;
+ u8 constraint_set1_flag;
+ u8 constraint_set2_flag;
+ u8 constraint_set3_flag;
+ u8 constraint_set4_flag;
+ u8 constraint_set5_flag;
};
+static_assert(sizeof(OrbisVideodec2AvcPictureInfo) == 0x78);
} // namespace Libraries::Vdec2
\ No newline at end of file
diff --git a/src/core/libraries/videodec/videodec2_impl.cpp b/src/core/libraries/videodec/videodec2_impl.cpp
index 22b17c86c..373809c14 100644
--- a/src/core/libraries/videodec/videodec2_impl.cpp
+++ b/src/core/libraries/videodec/videodec2_impl.cpp
@@ -44,11 +44,15 @@ s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData,
OrbisVideodec2FrameBuffer& frameBuffer,
OrbisVideodec2OutputInfo& outputInfo) {
frameBuffer.isAccepted = false;
- outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo);
outputInfo.isValid = false;
outputInfo.isErrorFrame = true;
outputInfo.pictureCount = 0;
+ // Only set frameFormat if the game uses the newer struct version.
+ if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) {
+ outputInfo.frameFormat = 0;
+ }
+
if (!inputData.auData) {
return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_POINTER;
}
@@ -113,6 +117,11 @@ s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData,
outputInfo.isErrorFrame = false;
outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video
+ // Only set framePitchInBytes if the game uses the newer struct version.
+ if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) {
+ outputInfo.framePitchInBytes = frame->linesize[0];
+ }
+
if (outputInfo.isValid) {
OrbisVideodec2AvcPictureInfo pictureInfo = {};
@@ -140,11 +149,15 @@ s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData,
s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer,
OrbisVideodec2OutputInfo& outputInfo) {
frameBuffer.isAccepted = false;
- outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo);
outputInfo.isValid = false;
outputInfo.isErrorFrame = true;
outputInfo.pictureCount = 0;
+ // Only set frameFormat if the game uses the newer struct version.
+ if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) {
+ outputInfo.frameFormat = 0;
+ }
+
AVFrame* frame = av_frame_alloc();
if (!frame) {
LOG_ERROR(Lib_Vdec2, "Failed to allocate frame");
@@ -182,6 +195,11 @@ s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer,
outputInfo.isErrorFrame = false;
outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video
+ // Only set framePitchInBytes if the game uses the newer struct version.
+ if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) {
+ outputInfo.framePitchInBytes = frame->linesize[0];
+ }
+
// FIXME: Should we add picture info here too?
}
diff --git a/src/core/libraries/videoout/video_out.cpp b/src/core/libraries/videoout/video_out.cpp
index c5208b6dd..da715b3bf 100644
--- a/src/core/libraries/videoout/video_out.cpp
+++ b/src/core/libraries/videoout/video_out.cpp
@@ -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;
}
diff --git a/src/core/libraries/zlib/zlib.cpp b/src/core/libraries/zlib/zlib.cpp
index 899cb5bf6..b304992ad 100644
--- a/src/core/libraries/zlib/zlib.cpp
+++ b/src/core/libraries/zlib/zlib.cpp
@@ -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;
diff --git a/src/core/linker.cpp b/src/core/linker.cpp
index c50b03a8f..1f45caf12 100644
--- a/src/core/linker.cpp
+++ b/src/core/linker.cpp
@@ -332,21 +332,22 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
sr.type = sym_type;
const auto* record = m_hle_symbols.FindSymbol(sr);
- if (!record) {
- // Check if it an export function
- const auto* p = FindExportedModule(*module, *library);
- if (p && p->export_sym.GetSize() > 0) {
- record = p->export_sym.FindSymbol(sr);
- }
- }
if (record) {
*return_info = *record;
-
Core::Devtools::Widget::ModuleList::AddModule(sr.library);
-
return true;
}
+ // Check if it an export function
+ const auto* p = FindExportedModule(*module, *library);
+ if (p && p->export_sym.GetSize() > 0) {
+ record = p->export_sym.FindSymbol(sr);
+ if (record) {
+ *return_info = *record;
+ return true;
+ }
+ }
+
const auto aeronid = AeroLib::FindByNid(sr.name.c_str());
if (aeronid) {
return_info->name = aeronid->name;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index ba3640877..f70751f3a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -17,11 +17,11 @@ namespace Core {
MemoryManager::MemoryManager() {
// Insert a virtual memory area that covers the entire area we manage.
const VAddr system_managed_base = impl.SystemManagedVirtualBase();
- const size_t system_managed_size = impl.SystemManagedVirtualSize();
+ const u64 system_managed_size = impl.SystemManagedVirtualSize();
const VAddr system_reserved_base = impl.SystemReservedVirtualBase();
- const size_t system_reserved_size = impl.SystemReservedVirtualSize();
+ const u64 system_reserved_size = impl.SystemReservedVirtualSize();
const VAddr user_base = impl.UserVirtualBase();
- const size_t user_size = impl.UserVirtualSize();
+ const u64 user_size = impl.UserVirtualSize();
vma_map.emplace(system_managed_base,
VirtualMemoryArea{system_managed_base, system_managed_size});
vma_map.emplace(system_reserved_base,
@@ -95,6 +95,46 @@ u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
return clamped_size;
}
+void MemoryManager::SetPrtArea(u32 id, VAddr address, u64 size) {
+ PrtArea& area = prt_areas[id];
+ if (area.mapped) {
+ rasterizer->UnmapMemory(area.start, area.end - area.start);
+ }
+
+ area.start = address;
+ area.end = address + size;
+ area.mapped = true;
+
+ // Pretend the entire PRT area is mapped to avoid GPU tracking errors.
+ // The caches will use CopySparseMemory to fetch data which avoids unmapped areas.
+ rasterizer->MapMemory(address, size);
+}
+
+void MemoryManager::CopySparseMemory(VAddr virtual_addr, u8* dest, u64 size) {
+ const bool is_sparse = std::ranges::any_of(
+ prt_areas, [&](const PrtArea& area) { return area.Overlaps(virtual_addr, size); });
+ if (!is_sparse) {
+ std::memcpy(dest, std::bit_cast(virtual_addr), size);
+ return;
+ }
+
+ auto vma = FindVMA(virtual_addr);
+ ASSERT_MSG(vma->second.Contains(virtual_addr, 0),
+ "Attempted to access invalid GPU address {:#x}", virtual_addr);
+ while (size) {
+ u64 copy_size = std::min(vma->second.size - (virtual_addr - vma->first), size);
+ if (vma->second.IsFree()) {
+ std::memset(dest, 0, copy_size);
+ } else {
+ std::memcpy(dest, std::bit_cast(virtual_addr), copy_size);
+ }
+ size -= copy_size;
+ virtual_addr += copy_size;
+ dest += copy_size;
+ ++vma;
+ }
+}
+
bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_bytes) {
const VAddr virtual_addr = std::bit_cast(address);
const auto& vma = FindVMA(virtual_addr)->second;
@@ -108,7 +148,7 @@ bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_byt
return true;
}
-PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) {
+PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, u64 size, u64 alignment) {
std::scoped_lock lk{mutex};
alignment = alignment > 0 ? alignment : 64_KB;
@@ -148,8 +188,8 @@ PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t siz
return mapping_start;
}
-PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
- int memory_type) {
+PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, u64 size, u64 alignment,
+ s32 memory_type) {
std::scoped_lock lk{mutex};
alignment = alignment > 0 ? alignment : 16_KB;
@@ -186,7 +226,7 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
return mapping_start;
}
-void MemoryManager::Free(PAddr phys_addr, size_t size) {
+void MemoryManager::Free(PAddr phys_addr, u64 size) {
std::scoped_lock lk{mutex};
auto dmem_area = CarveDmemArea(phys_addr, size);
@@ -216,7 +256,7 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
MergeAdjacent(dmem_map, dmem_area);
}
-int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot) {
+s32 MemoryManager::PoolCommit(VAddr virtual_addr, u64 size, MemoryProt prot) {
std::scoped_lock lk{mutex};
const u64 alignment = 64_KB;
@@ -280,6 +320,28 @@ s32 MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, u64 size, Memo
return ORBIS_KERNEL_ERROR_ENOMEM;
}
+ // Validate the requested physical address range
+ if (phys_addr != -1) {
+ u64 validated_size = 0;
+ do {
+ auto dmem_area = FindDmemArea(phys_addr + validated_size)->second;
+ // If any requested dmem area is not allocated, return an error.
+ if (dmem_area.is_free) {
+ LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at physical address {:#x}", size,
+ phys_addr);
+ return ORBIS_KERNEL_ERROR_ENOMEM;
+ }
+ // Track how much we've validated.
+ validated_size += dmem_area.size - (phys_addr + validated_size - dmem_area.base);
+ } while (validated_size < size && phys_addr + validated_size < GetTotalDirectSize());
+ // If the requested range goes outside the dmem map, return an error.
+ if (validated_size < size) {
+ LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at physical address {:#x}", size,
+ phys_addr);
+ return ORBIS_KERNEL_ERROR_ENOMEM;
+ }
+ }
+
// Limit the minumum address to SystemManagedVirtualBase to prevent hardware-specific issues.
VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
@@ -363,7 +425,7 @@ s32 MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, u64 size, Memory
auto* h = Common::Singleton::Instance();
VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
- const size_t size_aligned = Common::AlignUp(size, 16_KB);
+ const u64 size_aligned = Common::AlignUp(size, 16_KB);
// Find first free area to map the file.
if (False(flags & MemoryMapFlags::Fixed)) {
@@ -376,7 +438,7 @@ s32 MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, u64 size, Memory
if (True(flags & MemoryMapFlags::Fixed)) {
const auto& vma = FindVMA(virtual_addr)->second;
- const size_t remaining_size = vma.base + vma.size - virtual_addr;
+ const u64 remaining_size = vma.base + vma.size - virtual_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);
@@ -408,7 +470,7 @@ s32 MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, u64 size, Memory
return ORBIS_OK;
}
-s32 MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
+s32 MemoryManager::PoolDecommit(VAddr virtual_addr, u64 size) {
std::scoped_lock lk{mutex};
const auto it = FindVMA(virtual_addr);
@@ -458,7 +520,7 @@ s32 MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
return ORBIS_OK;
}
-s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
+s32 MemoryManager::UnmapMemory(VAddr virtual_addr, u64 size) {
std::scoped_lock lk{mutex};
return UnmapMemoryImpl(virtual_addr, size);
}
@@ -524,7 +586,7 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, u64 size) {
return ORBIS_OK;
}
-int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* prot) {
+s32 MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* prot) {
std::scoped_lock lk{mutex};
const auto it = FindVMA(addr);
@@ -546,8 +608,7 @@ int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr
return ORBIS_OK;
}
-s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t size,
- MemoryProt prot) {
+s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, u64 size, MemoryProt prot) {
const auto start_in_vma = addr - vma_base.base;
const auto adjusted_size =
vma_base.size - start_in_vma < size ? vma_base.size - start_in_vma : size;
@@ -584,7 +645,7 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
return adjusted_size;
}
-s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
+s32 MemoryManager::Protect(VAddr addr, u64 size, MemoryProt prot) {
std::scoped_lock lk{mutex};
// Validate protection flags
@@ -609,9 +670,8 @@ s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
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(aligned_addr + protected_bytes, vma_base,
- aligned_size - protected_bytes, prot);
+ auto result = ProtectBytes(aligned_addr + protected_bytes, vma_base,
+ aligned_size - protected_bytes, prot);
if (result < 0) {
// ProtectBytes returned an error, return it
return result;
@@ -622,7 +682,7 @@ s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
return ORBIS_OK;
}
-int MemoryManager::VirtualQuery(VAddr addr, int flags,
+s32 MemoryManager::VirtualQuery(VAddr addr, s32 flags,
::Libraries::Kernel::OrbisVirtualQueryInfo* info) {
std::scoped_lock lk{mutex};
@@ -667,7 +727,7 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
return ORBIS_OK;
}
-int MemoryManager::DirectMemoryQuery(PAddr addr, bool find_next,
+s32 MemoryManager::DirectMemoryQuery(PAddr addr, bool find_next,
::Libraries::Kernel::OrbisQueryInfo* out_info) {
std::scoped_lock lk{mutex};
@@ -688,13 +748,13 @@ int MemoryManager::DirectMemoryQuery(PAddr addr, bool find_next,
return ORBIS_OK;
}
-int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, size_t alignment,
- PAddr* phys_addr_out, size_t* size_out) {
+s32 MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, u64 alignment,
+ PAddr* phys_addr_out, u64* size_out) {
std::scoped_lock lk{mutex};
auto dmem_area = FindDmemArea(search_start);
PAddr paddr{};
- size_t max_size{};
+ u64 max_size{};
while (dmem_area != dmem_map.end()) {
if (!dmem_area->second.is_free) {
@@ -775,13 +835,60 @@ void MemoryManager::NameVirtualRange(VAddr virtual_addr, u64 size, std::string_v
}
}
+s32 MemoryManager::GetDirectMemoryType(PAddr addr, s32* directMemoryTypeOut,
+ void** directMemoryStartOut, void** directMemoryEndOut) {
+ std::scoped_lock lk{mutex};
+
+ auto dmem_area = FindDmemArea(addr);
+
+ if (addr > dmem_area->second.GetEnd() || dmem_area->second.is_free) {
+ LOG_ERROR(Core, "Unable to find allocated direct memory region to check type!");
+ return ORBIS_KERNEL_ERROR_ENOENT;
+ }
+
+ const auto& area = dmem_area->second;
+ *directMemoryStartOut = reinterpret_cast(area.base);
+ *directMemoryEndOut = reinterpret_cast(area.GetEnd());
+ *directMemoryTypeOut = area.memory_type;
+ return ORBIS_OK;
+}
+
+s32 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;
+ }
+
+ u64 stack_start = 0;
+ u64 stack_end = 0;
+ if (vma.type == VMAType::Stack) {
+ stack_start = vma.base;
+ stack_end = vma.base + vma.size;
+ }
+
+ if (start != nullptr) {
+ *start = reinterpret_cast(stack_start);
+ }
+
+ if (end != nullptr) {
+ *end = reinterpret_cast(stack_end);
+ }
+
+ return ORBIS_OK;
+}
+
void MemoryManager::InvalidateMemory(const VAddr addr, const u64 size) const {
if (rasterizer) {
rasterizer->InvalidateMemory(addr, size);
}
}
-VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment) {
+VAddr MemoryManager::SearchFree(VAddr virtual_addr, u64 size, u32 alignment) {
// If the requested address is below the mapped range, start search from the lowest address
auto min_search_address = impl.SystemManagedVirtualBase();
if (virtual_addr < min_search_address) {
@@ -824,7 +931,7 @@ VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment)
}
// If there's enough space in the VMA, return the address.
- const size_t remaining_size = vma.base + vma.size - virtual_addr;
+ const u64 remaining_size = vma.base + vma.size - virtual_addr;
if (remaining_size >= size) {
return virtual_addr;
}
@@ -837,7 +944,7 @@ VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment)
return -1;
}
-MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size) {
+MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, u64 size) {
auto vma_handle = FindVMA(virtual_addr);
ASSERT_MSG(vma_handle->second.Contains(virtual_addr, 0), "Virtual address not in vm_map");
@@ -866,7 +973,7 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
return vma_handle;
}
-MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, size_t size) {
+MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, u64 size) {
auto dmem_handle = FindDmemArea(addr);
ASSERT_MSG(addr <= dmem_handle->second.GetEnd(), "Physical address not in dmem_map");
@@ -890,7 +997,7 @@ MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, size_t size)
return dmem_handle;
}
-MemoryManager::VMAHandle MemoryManager::Split(VMAHandle vma_handle, size_t offset_in_vma) {
+MemoryManager::VMAHandle MemoryManager::Split(VMAHandle vma_handle, u64 offset_in_vma) {
auto& old_vma = vma_handle->second;
ASSERT(offset_in_vma < old_vma.size && offset_in_vma > 0);
@@ -905,7 +1012,7 @@ MemoryManager::VMAHandle MemoryManager::Split(VMAHandle vma_handle, size_t offse
return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
}
-MemoryManager::DMemHandle MemoryManager::Split(DMemHandle dmem_handle, size_t offset_in_area) {
+MemoryManager::DMemHandle MemoryManager::Split(DMemHandle dmem_handle, u64 offset_in_area) {
auto& old_area = dmem_handle->second;
ASSERT(offset_in_area < old_area.size && offset_in_area > 0);
@@ -917,51 +1024,4 @@ MemoryManager::DMemHandle MemoryManager::Split(DMemHandle dmem_handle, size_t of
return dmem_map.emplace_hint(std::next(dmem_handle), new_area.base, new_area);
}
-int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut,
- void** directMemoryStartOut, void** directMemoryEndOut) {
- std::scoped_lock lk{mutex};
-
- auto dmem_area = FindDmemArea(addr);
-
- if (addr > dmem_area->second.GetEnd() || dmem_area->second.is_free) {
- LOG_ERROR(Core, "Unable to find allocated direct memory region to check type!");
- return ORBIS_KERNEL_ERROR_ENOENT;
- }
-
- const auto& area = dmem_area->second;
- *directMemoryStartOut = reinterpret_cast(area.base);
- *directMemoryEndOut = reinterpret_cast(area.GetEnd());
- *directMemoryTypeOut = area.memory_type;
- 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(stack_start);
- }
-
- if (end != nullptr) {
- *end = reinterpret_cast(stack_end);
- }
-
- return ORBIS_OK;
-}
-
} // namespace Core
diff --git a/src/core/memory.h b/src/core/memory.h
index b3ebe3c27..c800ef763 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -5,6 +5,7 @@
#include