diff --git a/.ci/clang-format.sh b/.ci/clang-format.sh
index 0ccd4062d..c0d8c2c2d 100755
--- a/.ci/clang-format.sh
+++ b/.ci/clang-format.sh
@@ -10,7 +10,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
fi
# Default clang-format points to default 3.5 version one
-CLANG_FORMAT=clang-format-17
+CLANG_FORMAT=clang-format-18
$CLANG_FORMAT --version
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a3b3ee8ec..878c10868 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -18,7 +18,7 @@ jobs:
continue-on-error: true
steps:
- uses: actions/checkout@v4
- - uses: fsfe/reuse-action@v4
+ - uses: fsfe/reuse-action@v5
clang-format:
runs-on: ubuntu-latest
@@ -30,9 +30,9 @@ jobs:
- name: Install
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
- sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main'
+ sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main'
sudo apt update
- sudo apt install clang-format-17
+ sudo apt install clang-format-18
- name: Build
env:
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
@@ -92,7 +92,7 @@ jobs:
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
- run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
+ run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $env:NUMBER_OF_PROCESSORS
- name: Upload Windows SDL artifact
uses: actions/upload-artifact@v4
@@ -146,7 +146,7 @@ jobs:
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
- run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
+ run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $env:NUMBER_OF_PROCESSORS
- name: Deploy and Package
run: |
@@ -315,7 +315,7 @@ jobs:
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
- run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
+ run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
- name: Package and Upload Linux(ubuntu64) SDL artifact
run: |
@@ -371,7 +371,7 @@ jobs:
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
- run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel3
+ run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
- name: Run AppImage packaging script
run: ./.github/linux-appimage-qt.sh
diff --git a/.gitignore b/.gitignore
index 61d9e32e1..683f6f0a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -414,3 +414,7 @@ FodyWeavers.xsd
# for macOS
**/.DS_Store
+
+# JetBrains
+.idea
+cmake-build-*
diff --git a/.gitmodules b/.gitmodules
index 07d1d4ef7..8010250a9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -102,3 +102,8 @@
[submodule "externals/LibAtrac9"]
path = externals/LibAtrac9
url = https://github.com/shadps4-emu/ext-LibAtrac9.git
+ shallow = true
+[submodule "externals/libpng"]
+ path = externals/libpng
+ url = https://github.com/pnggroup/libpng
+ shallow = true
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8c69eef27..b1b49946d 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,8 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
-cmake_minimum_required(VERSION 3.16.3)
+# Version 3.24 needed for FetchContent OVERRIDE_FIND_PACKAGE
+cmake_minimum_required(VERSION 3.24)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)
@@ -110,18 +111,20 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_
find_package(Boost 1.84.0 CONFIG)
find_package(FFmpeg 5.1.2 MODULE)
find_package(fmt 10.2.0 CONFIG)
-find_package(glslang 14.2.0 CONFIG)
+find_package(glslang 15 CONFIG)
find_package(half 1.12.0 MODULE)
-find_package(magic_enum 0.9.6 CONFIG)
+find_package(magic_enum 0.9.7 CONFIG)
+find_package(PNG 1.6 MODULE)
find_package(RenderDoc 1.6.0 MODULE)
find_package(SDL3 3.1.2 CONFIG)
+find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)
-find_package(VulkanHeaders 1.3.289 CONFIG)
+find_package(VulkanHeaders 1.4.303 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE)
-find_package(zlib-ng 2.1.7 MODULE)
+find_package(ZLIB 1.3 MODULE)
find_package(Zydis 5.0.0 CONFIG)
find_package(pugixml 1.14 CONFIG)
@@ -176,10 +179,6 @@ if(ENABLE_QT_GUI)
qt_add_resources(TRANSLATIONS ${TRANSLATIONS_QRC})
endif()
-set(AUDIO_CORE src/audio_core/sdl_audio.cpp
- src/audio_core/sdl_audio.h
-)
-
set(AJM_LIB src/core/libraries/ajm/ajm.cpp
src/core/libraries/ajm/ajm.h
src/core/libraries/ajm/ajm_at9.cpp
@@ -199,6 +198,9 @@ set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
src/core/libraries/audio/audioin.h
src/core/libraries/audio/audioout.cpp
src/core/libraries/audio/audioout.h
+ src/core/libraries/audio/sdl_audio.cpp
+ src/core/libraries/audio/sdl_audio.h
+ src/core/libraries/audio/audioout_error.h
src/core/libraries/ngs2/ngs2.cpp
src/core/libraries/ngs2/ngs2.h
)
@@ -208,30 +210,43 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
src/core/libraries/gnmdriver/gnm_error.h
)
-set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
- src/core/libraries/kernel/event_flag/event_flag.h
- src/core/libraries/kernel/event_flag/event_flag_obj.cpp
- src/core/libraries/kernel/event_flag/event_flag_obj.h
+set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
+ src/core/libraries/kernel/sync/mutex.h
+ src/core/libraries/kernel/sync/semaphore.h
+ src/core/libraries/kernel/threads/condvar.cpp
+ src/core/libraries/kernel/threads/event_flag.cpp
+ src/core/libraries/kernel/threads/exception.cpp
+ src/core/libraries/kernel/threads/exception.h
+ src/core/libraries/kernel/threads/mutex.cpp
+ src/core/libraries/kernel/threads/pthread_attr.cpp
+ src/core/libraries/kernel/threads/pthread_clean.cpp
+ src/core/libraries/kernel/threads/pthread.cpp
+ src/core/libraries/kernel/threads/pthread_spec.cpp
src/core/libraries/kernel/threads/rwlock.cpp
src/core/libraries/kernel/threads/semaphore.cpp
- src/core/libraries/kernel/threads/keys.cpp
- src/core/libraries/kernel/threads/threads.h
- src/core/libraries/kernel/cpu_management.cpp
- src/core/libraries/kernel/cpu_management.h
- src/core/libraries/kernel/event_queue.cpp
- src/core/libraries/kernel/event_queue.h
- src/core/libraries/kernel/event_queues.cpp
- src/core/libraries/kernel/event_queues.h
+ src/core/libraries/kernel/threads/sleepq.cpp
+ src/core/libraries/kernel/threads/sleepq.h
+ src/core/libraries/kernel/threads/stack.cpp
+ src/core/libraries/kernel/threads/tcb.cpp
+ src/core/libraries/kernel/threads/pthread.h
+ src/core/libraries/kernel/threads/thread_state.cpp
+ src/core/libraries/kernel/threads/thread_state.h
+ src/core/libraries/kernel/process.cpp
+ src/core/libraries/kernel/process.h
+ src/core/libraries/kernel/equeue.cpp
+ src/core/libraries/kernel/equeue.h
src/core/libraries/kernel/file_system.cpp
src/core/libraries/kernel/file_system.h
- src/core/libraries/kernel/libkernel.cpp
- src/core/libraries/kernel/libkernel.h
- src/core/libraries/kernel/memory_management.cpp
- src/core/libraries/kernel/memory_management.h
- src/core/libraries/kernel/thread_management.cpp
- src/core/libraries/kernel/thread_management.h
- src/core/libraries/kernel/time_management.cpp
- src/core/libraries/kernel/time_management.h
+ src/core/libraries/kernel/kernel.cpp
+ src/core/libraries/kernel/kernel.h
+ src/core/libraries/kernel/memory.cpp
+ src/core/libraries/kernel/memory.h
+ src/core/libraries/kernel/threads.cpp
+ src/core/libraries/kernel/threads.h
+ src/core/libraries/kernel/time.cpp
+ src/core/libraries/kernel/time.h
+ src/core/libraries/kernel/orbis_error.h
+ src/core/libraries/kernel/posix_error.h
)
set(NETWORK_LIBS src/core/libraries/network/http.cpp
@@ -247,6 +262,21 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
src/core/libraries/network/ssl.h
)
+set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp
+ src/core/libraries/avplayer/avplayer_common.h
+ src/core/libraries/avplayer/avplayer_file_streamer.cpp
+ src/core/libraries/avplayer/avplayer_file_streamer.h
+ src/core/libraries/avplayer/avplayer_impl.cpp
+ src/core/libraries/avplayer/avplayer_impl.h
+ src/core/libraries/avplayer/avplayer_source.cpp
+ src/core/libraries/avplayer/avplayer_source.h
+ src/core/libraries/avplayer/avplayer_state.cpp
+ src/core/libraries/avplayer/avplayer_state.h
+ src/core/libraries/avplayer/avplayer.cpp
+ src/core/libraries/avplayer/avplayer.h
+ src/core/libraries/avplayer/avplayer_error.h
+)
+
set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/system/commondialog.h
src/core/libraries/system/msgdialog.cpp
@@ -268,30 +298,22 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/save_data/dialog/savedatadialog_ui.h
src/core/libraries/system/sysmodule.cpp
src/core/libraries/system/sysmodule.h
+ src/core/libraries/system/system_error.h
src/core/libraries/system/systemservice.cpp
src/core/libraries/system/systemservice.h
+ src/core/libraries/system/systemservice_error.h
src/core/libraries/system/userservice.cpp
src/core/libraries/system/userservice.h
+ src/core/libraries/system/userservice_error.h
src/core/libraries/app_content/app_content.cpp
src/core/libraries/app_content/app_content.h
+ src/core/libraries/app_content/app_content_error.h
src/core/libraries/rtc/rtc.cpp
src/core/libraries/rtc/rtc.h
src/core/libraries/rtc/rtc_error.h
src/core/libraries/disc_map/disc_map.cpp
src/core/libraries/disc_map/disc_map.h
src/core/libraries/disc_map/disc_map_codes.h
- src/core/libraries/avplayer/avplayer_common.cpp
- src/core/libraries/avplayer/avplayer_common.h
- src/core/libraries/avplayer/avplayer_file_streamer.cpp
- src/core/libraries/avplayer/avplayer_file_streamer.h
- src/core/libraries/avplayer/avplayer_impl.cpp
- src/core/libraries/avplayer/avplayer_impl.h
- src/core/libraries/avplayer/avplayer_source.cpp
- src/core/libraries/avplayer/avplayer_source.h
- src/core/libraries/avplayer/avplayer_state.cpp
- src/core/libraries/avplayer/avplayer_state.h
- src/core/libraries/avplayer/avplayer.cpp
- src/core/libraries/avplayer/avplayer.h
src/core/libraries/ngs2/ngs2.cpp
src/core/libraries/ngs2/ngs2.h
src/core/libraries/ngs2/ngs2_error.h
@@ -309,6 +331,8 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/remote_play/remoteplay.h
src/core/libraries/share_play/shareplay.cpp
src/core/libraries/share_play/shareplay.h
+ src/core/libraries/razor_cpu/razor_cpu.cpp
+ src/core/libraries/razor_cpu/razor_cpu.h
)
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
@@ -316,6 +340,7 @@ set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
src/core/libraries/videoout/driver.h
src/core/libraries/videoout/video_out.cpp
src/core/libraries/videoout/video_out.h
+ src/core/libraries/videoout/videoout_error.h
)
set(LIBC_SOURCES src/core/libraries/libc_internal/libc_internal.cpp
@@ -333,18 +358,28 @@ set(IME_LIB src/core/libraries/ime/error_dialog.cpp
src/core/libraries/ime/ime_ui.h
src/core/libraries/ime/ime.cpp
src/core/libraries/ime/ime.h
+ src/core/libraries/ime/ime_error.h
)
set(PAD_LIB src/core/libraries/pad/pad.cpp
src/core/libraries/pad/pad.h
+ src/core/libraries/pad/pad_errors.h
)
set(PNG_LIB src/core/libraries/libpng/pngdec.cpp
src/core/libraries/libpng/pngdec.h
+ src/core/libraries/libpng/pngdec_error.h
+)
+
+set(JPEG_LIB src/core/libraries/jpeg/jpeg_error.h
+ src/core/libraries/jpeg/jpegenc.cpp
+ src/core/libraries/jpeg/jpegenc.h
)
set(PLAYGO_LIB src/core/libraries/playgo/playgo.cpp
src/core/libraries/playgo/playgo.h
+ src/core/libraries/playgo/playgo_dialog.cpp
+ src/core/libraries/playgo/playgo_dialog.h
src/core/libraries/playgo/playgo_types.h
)
@@ -359,6 +394,7 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp
set(FIBER_LIB src/core/libraries/fiber/fiber.cpp
src/core/libraries/fiber/fiber.h
+ src/core/libraries/fiber/fiber_error.h
)
set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp
@@ -368,6 +404,7 @@ set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp
src/core/libraries/videodec/videodec2_avc.h
src/core/libraries/videodec/videodec.cpp
src/core/libraries/videodec/videodec.h
+ src/core/libraries/videodec/videodec_error.h
src/core/libraries/videodec/videodec_impl.cpp
src/core/libraries/videodec/videodec_impl.h
)
@@ -380,6 +417,7 @@ set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
src/core/libraries/np_trophy/np_trophy.h
src/core/libraries/np_trophy/trophy_ui.cpp
src/core/libraries/np_trophy/trophy_ui.h
+ src/core/libraries/np_trophy/np_trophy_error.h
)
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
@@ -401,10 +439,14 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/widget/frame_graph.cpp
src/core/devtools/widget/frame_graph.h
src/core/devtools/widget/imgui_memory_editor.h
+ src/core/devtools/widget/memory_map.cpp
+ src/core/devtools/widget/memory_map.h
src/core/devtools/widget/reg_popup.cpp
src/core/devtools/widget/reg_popup.h
src/core/devtools/widget/reg_view.cpp
src/core/devtools/widget/reg_view.h
+ src/core/devtools/widget/shader_list.cpp
+ src/core/devtools/widget/shader_list.h
src/core/devtools/widget/text_editor.cpp
src/core/devtools/widget/text_editor.h
)
@@ -453,7 +495,12 @@ set(COMMON src/common/logging/backend.cpp
src/common/signal_context.h
src/common/signal_context.cpp
src/common/singleton.h
+ src/common/slab_heap.h
src/common/slot_vector.h
+ src/common/spin_lock.cpp
+ src/common/spin_lock.h
+ src/common/stb.cpp
+ src/common/stb.h
src/common/string_util.cpp
src/common/string_util.h
src/common/thread.cpp
@@ -461,6 +508,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/types.h
src/common/uint128.h
src/common/unique_function.h
+ src/common/va_ctx.h
src/common/version.h
src/common/ntapi.h
src/common/ntapi.cpp
@@ -485,6 +533,12 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/crypto/crypto.cpp
src/core/crypto/crypto.h
src/core/crypto/keys.h
+ src/core/devices/base_device.cpp
+ src/core/devices/base_device.h
+ src/core/devices/ioccom.h
+ src/core/devices/logger.cpp
+ src/core/devices/logger.h
+ src/core/devices/nop_device.h
src/core/file_format/pfs.h
src/core/file_format/pkg.cpp
src/core/file_format/pkg.h
@@ -508,10 +562,10 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/loader/elf.h
src/core/loader/symbols_resolver.h
src/core/loader/symbols_resolver.cpp
- src/core/libraries/error_codes.h
src/core/libraries/libs.h
src/core/libraries/libs.cpp
${AJM_LIB}
+ ${AVPLAYER_LIB}
${AUDIO_LIB}
${GNM_LIB}
${KERNEL_LIB}
@@ -522,6 +576,7 @@ set(CORE src/core/aerolib/stubs.cpp
${VIDEOOUT_LIB}
${NP_LIBS}
${PNG_LIB}
+ ${JPEG_LIB}
${PLAYGO_LIB}
${RANDOM_LIB}
${USBD_LIB}
@@ -541,10 +596,10 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/platform.h
src/core/signals.cpp
src/core/signals.h
+ src/core/thread.cpp
+ src/core/thread.h
src/core/tls.cpp
src/core/tls.h
- src/core/virtual_memory.cpp
- src/core/virtual_memory.h
)
if (ARCHITECTURE STREQUAL "x86_64")
@@ -657,8 +712,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/buffer_cache/word_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/renderer_vulkan.cpp
- src/video_core/renderer_vulkan/renderer_vulkan.h
src/video_core/renderer_vulkan/vk_common.cpp
src/video_core/renderer_vulkan/vk_common.h
src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -677,6 +730,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/vk_pipeline_common.h
src/video_core/renderer_vulkan/vk_platform.cpp
src/video_core/renderer_vulkan/vk_platform.h
+ src/video_core/renderer_vulkan/vk_presenter.cpp
+ src/video_core/renderer_vulkan/vk_presenter.h
src/video_core/renderer_vulkan/vk_rasterizer.cpp
src/video_core/renderer_vulkan/vk_rasterizer.h
src/video_core/renderer_vulkan/vk_resource_pool.cpp
@@ -820,12 +875,20 @@ endif()
create_target_directory_groups(shadps4)
-target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half)
-target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
+target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
+target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
+if (ENABLE_DISCORD_RPC)
+ target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
+endif()
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
+endif()
+
if (APPLE)
option(USE_SYSTEM_VULKAN_LOADER "Enables using the system Vulkan loader instead of directly linking with MoltenVK. Useful for loading validation layers." OFF)
if (USE_SYSTEM_VULKAN_LOADER)
@@ -850,9 +913,9 @@ if (NOT ENABLE_QT_GUI)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
- target_link_libraries(shadps4 PRIVATE cryptoppwin zlib-ng::zlib)
+ target_link_libraries(shadps4 PRIVATE cryptoppwin)
else()
- target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp zlib-ng::zlib)
+ target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp)
endif()
if (ENABLE_QT_GUI)
@@ -924,7 +987,10 @@ if (ENABLE_QT_GUI)
set_target_properties(shadps4 PROPERTIES
# WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
- MACOSX_BUNDLE_ICON_FILE shadPS4.icns)
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/dist/MacOSBundleInfo.plist.in"
+ MACOSX_BUNDLE_ICON_FILE "shadPS4.icns"
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "0.4.1"
+ )
set_source_files_properties(src/images/shadPS4.icns PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
diff --git a/REUSE.toml b/REUSE.toml
index b0e482ef3..47e8ee4d7 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -7,6 +7,7 @@ path = [
".github/FUNDING.yml",
".github/shadps4.png",
".gitmodules",
+ "dist/MacOSBundleInfo.plist.in",
"dist/net.shadps4.shadPS4.desktop",
"dist/net.shadps4.shadPS4_metadata.pot",
"dist/net.shadps4.shadPS4.metainfo.xml",
@@ -41,6 +42,7 @@ path = [
"src/images/refresh_icon.png",
"src/images/settings_icon.png",
"src/images/stop_icon.png",
+ "src/images/utils_icon.png",
"src/images/shadPS4.icns",
"src/images/shadps4.ico",
"src/images/net.shadps4.shadPS4.svg",
@@ -68,7 +70,7 @@ SPDX-FileCopyrightText = "2019-2024 Baldur Karlsson"
SPDX-License-Identifier = "MIT"
[[annotations]]
-path = "externals/stb_image.h"
+path = "externals/stb/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2017 Sean Barrett"
SPDX-License-Identifier = "MIT"
diff --git a/cmake/Findstb.cmake b/cmake/Findstb.cmake
new file mode 100644
index 000000000..667911e1d
--- /dev/null
+++ b/cmake/Findstb.cmake
@@ -0,0 +1,19 @@
+# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+find_path(stb_image_INCLUDE_DIR stb_image.h PATH_SUFFIXES stb)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(stb
+ REQUIRED_VARS stb_image_INCLUDE_DIR
+)
+
+if (stb_FOUND AND NOT TARGET stb::headers)
+ add_library(stb::headers INTERFACE IMPORTED)
+ set_property(TARGET stb::headers PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${stb_image_INCLUDE_DIR}"
+ )
+endif()
+
+mark_as_advanced(stb_image_INCLUDE_DIR)
diff --git a/cmake/Findzlib-ng.cmake b/cmake/Findzlib-ng.cmake
deleted file mode 100644
index ec6f14b4a..000000000
--- a/cmake/Findzlib-ng.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-find_package(PkgConfig QUIET)
-pkg_search_module(ZLIB_NG QUIET IMPORTED_TARGET zlib-ng)
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(zlib-ng
- REQUIRED_VARS ZLIB_NG_LINK_LIBRARIES
- VERSION_VAR ZLIB_NG_VERSION
-)
-
-if (zlib-ng_FOUND AND NOT TARGET zlib-ng::zlib)
- add_library(zlib-ng::zlib ALIAS PkgConfig::ZLIB_NG)
-endif()
diff --git a/dist/MacOSBundleInfo.plist.in b/dist/MacOSBundleInfo.plist.in
new file mode 100644
index 000000000..70cbfb4ab
--- /dev/null
+++ b/dist/MacOSBundleInfo.plist.in
@@ -0,0 +1,46 @@
+
+
+
+
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+
+ CFBundleName
+ shadps4
+ CFBundleIdentifier
+ com.shadps4-emu.shadps4
+ CFBundleExecutable
+ shadps4
+
+ CFBundleVersion
+ 1.0.0
+ CFBundleShortVersionString
+ ${MACOSX_BUNDLE_SHORT_VERSION_STRING}
+
+ LSMinimumSystemVersion
+ ${CMAKE_OSX_DEPLOYMENT_TARGET}
+ LSApplicationCategoryType
+ public.app-category.games
+ GCSupportsGameMode
+
+
+ NSHumanReadableCopyright
+
+
+ CFBundleIconFile
+ ${MACOSX_BUNDLE_ICON_FILE}
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleAllowMixedLocalizations
+
+
+ NSPrincipalClass
+ NSApplication
+
+ NSSupportsAutomaticGraphicsSwitching
+
+
+
diff --git a/documents/building-windows.md b/documents/building-windows.md
index 48fd09c41..d01e7b81e 100644
--- a/documents/building-windows.md
+++ b/documents/building-windows.md
@@ -25,8 +25,8 @@ Once you are within the installer:
Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead.
-1. Under the current, non beta version of Qt (at the time of writing 6.7.2), select the option `MSVC 2019 64-bit` or similar.
- If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2019 ARM64` instead.
+1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar.
+ If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead.
Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space.
@@ -35,7 +35,7 @@ Beware, this requires you to create a Qt account. If you do not want to do this,
Once you are finished, you will have to configure Qt within Visual Studio:
1. Tools -> Options -> Qt -> Versions
-2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.7.2\msvc2019_64`
+2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.7.3\msvc2022_64`
3. Enable the default checkmark on the new version you just created.
### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win)
@@ -55,16 +55,16 @@ Go through the Git for Windows installation as normal
3. If you want to build shadPS4 with the Qt Gui:
1. Click x64-Clang-Release and select "Manage Configurations"
2. Look for "CMake command arguments" and add to the text field
- `-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.7.2\msvc2019_64`
+ `-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.7.3\msvc2022_64`
(Change Qt path if you've installed it to non-default path)
3. Press CTRL+S to save and wait a moment for CMake generation
4. Change the project to build to shadps4.exe
5. Build -> Build All
-Your shadps4.exe will be in `c:\path\to\source\Build\x64-Clang-Release\`
+Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
-`C:\Qt\6.7.2\msvc2019_64\bin\windeployqt.exe "c:\path\to\shadps4.exe"`
+`C:\Qt\6.7.3\msvc2022_64\bin\windeployqt.exe "C:\path\to\shadps4.exe"`
(Change Qt path if you've installed it to non-default path)
## Option 2: MSYS2/MinGW
@@ -79,7 +79,7 @@ Normal x86-based computers, follow:
1. Open "MSYS2 MINGW64" from your new applications
2. Run `pacman -Syu`, let it complete;
-3. Run `pacman -S --needed git mingw-w64-x86_64-binutils mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-ffmpeg`
+3. Run `pacman -S --needed git mingw-w64-x86_64-binutils mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-rapidjson mingw-w64-x86_64-ninja mingw-w64-x86_64-ffmpeg`
1. Optional (Qt only): run `pacman -S --needed mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4`
@@ -93,7 +93,7 @@ ARM64-based computers, follow:
1. Open "MSYS2 CLANGARM64" from your new applications
2. Run `pacman -Syu`, let it complete;
-3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-ffmpeg`
+3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-rapidjson mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-ffmpeg`
1. Optional (Qt only): run `pacman -S --needed mingw-w64-clang-aarch64-qt6-base mingw-w64-clang-aarch64-qt6-tools mingw-w64-clang-aarch64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4`
diff --git a/documents/patching-shader.md b/documents/patching-shader.md
new file mode 100644
index 000000000..613e89bf9
--- /dev/null
+++ b/documents/patching-shader.md
@@ -0,0 +1,19 @@
+
+
+### Install Vulkan SDK and \*ensure `spirv-cross` and `glslc` are in PATH\*.
+
+1. Enable `dumpShaders` in config.toml
+
+2. Run `spirv-cross -V fs_0x000000.spv --output fs_0x000000.glsl` to decompile the SPIR-V IR to GLSL.
+
+3. Edit the GLSL file as you wish
+
+4. To compile back to SPIR-V, run (change the _**-fshader-stage**_ to correct stage):
+ `glslc --target-env=vulkan1.3 --target-spv=spv1.6 -fshader-stage=frag fs_0x000000.glsl -o fs_0x000000.spv`
+
+5. Put the updated .spv file to `shader/patch` folder with the same name as the original shader
+
+6. Enable `patchShaders` in config.toml
\ No newline at end of file
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 17d710878..082be211a 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -35,10 +35,11 @@ else()
if (NOT TARGET cryptopp::cryptopp)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
- set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp/)
+ set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
add_subdirectory(cryptopp-cmake)
file(COPY cryptopp DESTINATION cryptopp FILES_MATCHING PATTERN "*.h")
- target_include_directories(cryptopp INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
+ # remove externals/cryptopp from include directories because it contains a conflicting zlib.h file
+ set_target_properties(cryptopp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
endif()
endif()
@@ -52,14 +53,23 @@ file(GLOB LIBATRAC9_SOURCES LibAtrac9/C/src/*.c)
add_library(LibAtrac9 STATIC ${LIBATRAC9_SOURCES})
target_include_directories(LibAtrac9 INTERFACE LibAtrac9/C/src)
-# Zlib-Ng
-if (NOT TARGET zlib-ng::zlib)
+# zlib
+if (NOT TARGET ZLIB::ZLIB)
set(ZLIB_ENABLE_TESTS OFF)
set(WITH_GTEST OFF)
set(WITH_NEW_STRATEGIES ON)
set(WITH_NATIVE_INSTRUCTIONS ON)
- add_subdirectory(zlib-ng)
- add_library(zlib-ng::zlib ALIAS zlib)
+ set(ZLIB_COMPAT ON CACHE BOOL "" FORCE)
+ include(FetchContent)
+ FetchContent_Declare(
+ ZLIB
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zlib-ng"
+ OVERRIDE_FIND_PACKAGE
+ )
+ FetchContent_MakeAvailable(ZLIB)
+ add_library(ZLIB::ZLIB ALIAS zlib)
+ # libpng expects this variable to exist after its find_package(ZLIB)
+ set(ZLIB_INCLUDE_DIRS "${FETCHCONTENT_BASE_DIR}/zlib-build")
endif()
# SDL3
@@ -153,6 +163,17 @@ if (NOT TARGET half::half)
add_library(half::half ALIAS half)
endif()
+# libpng
+if (NOT TARGET PNG::PNG)
+ set(PNG_SHARED OFF CACHE BOOL "" FORCE)
+ set(PNG_STATIC ON CACHE BOOL "" FORCE)
+ set(PNG_TESTS OFF CACHE BOOL "" FORCE)
+ set(PNG_TOOLS OFF CACHE BOOL "" FORCE)
+ set(SKIP_INSTALL_ALL OFF CACHE BOOL "" FORCE)
+ add_subdirectory(libpng)
+ add_library(PNG::PNG ALIAS png_static)
+endif()
+
if (APPLE)
# date
if (NOT TARGET date::date-tz)
@@ -195,9 +216,16 @@ endif()
# Discord RPC
if (ENABLE_DISCORD_RPC)
set(BUILD_EXAMPLES OFF)
- add_subdirectory(discord-rpc/)
+ add_subdirectory(discord-rpc)
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
endif()
# GCN Headers
add_subdirectory(gcn)
+
+# stb
+if (NOT TARGET stb::headers)
+ add_library(stb INTERFACE)
+ target_include_directories(stb INTERFACE stb)
+ add_library(stb::headers ALIAS stb)
+endif()
diff --git a/externals/LibAtrac9 b/externals/LibAtrac9
index 3acdcdc78..9640129dc 160000
--- a/externals/LibAtrac9
+++ b/externals/LibAtrac9
@@ -1 +1 @@
-Subproject commit 3acdcdc78f129c2e6145331ff650fa76dd88d62c
+Subproject commit 9640129dc6f2afbca6ceeca3019856e8653a5fb2
diff --git a/externals/date b/externals/date
index dd8affc6d..28b7b2325 160000
--- a/externals/date
+++ b/externals/date
@@ -1 +1 @@
-Subproject commit dd8affc6de5755e07638bf0a14382d29549d6ee9
+Subproject commit 28b7b232521ace2c8ef3f2ad4126daec3569c14f
diff --git a/externals/ext-boost b/externals/ext-boost
index f2474e1b5..ca6f230e6 160000
--- a/externals/ext-boost
+++ b/externals/ext-boost
@@ -1 +1 @@
-Subproject commit f2474e1b584fb7a3ed6f85ba875e6eacd742ec8a
+Subproject commit ca6f230e67be7cc45fc919057f07b2aee64dadc1
diff --git a/externals/ffmpeg-core b/externals/ffmpeg-core
index e30b7d7fe..27de97c82 160000
--- a/externals/ffmpeg-core
+++ b/externals/ffmpeg-core
@@ -1 +1 @@
-Subproject commit e30b7d7fe228bfb3f6e41ce1040b44a15eb7d5e0
+Subproject commit 27de97c826b6b40c255891c37ac046a25836a575
diff --git a/externals/glslang b/externals/glslang
index e61d7bb30..a0995c49e 160000
--- a/externals/glslang
+++ b/externals/glslang
@@ -1 +1 @@
-Subproject commit e61d7bb3006f451968714e2f653412081871e1ee
+Subproject commit a0995c49ebcaca2c6d3b03efbabf74f3843decdb
diff --git a/externals/libpng b/externals/libpng
new file mode 160000
index 000000000..c1cc0f3f4
--- /dev/null
+++ b/externals/libpng
@@ -0,0 +1 @@
+Subproject commit c1cc0f3f4c3d4abd11ca68c59446a29ff6f95003
diff --git a/externals/magic_enum b/externals/magic_enum
index 126539e13..1a1824df7 160000
--- a/externals/magic_enum
+++ b/externals/magic_enum
@@ -1 +1 @@
-Subproject commit 126539e13cccdc2e75ce770e94f3c26403099fa5
+Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
diff --git a/externals/pugixml b/externals/pugixml
index 3b1718437..4bc14418d 160000
--- a/externals/pugixml
+++ b/externals/pugixml
@@ -1 +1 @@
-Subproject commit 3b17184379fcaaeb7f1fbe08018b7fedf2640b3b
+Subproject commit 4bc14418d12d289dd9978fdce9490a45deeb653e
diff --git a/externals/sdl3 b/externals/sdl3
index 54e622c2e..3a1d76d29 160000
--- a/externals/sdl3
+++ b/externals/sdl3
@@ -1 +1 @@
-Subproject commit 54e622c2e6af456bfef382fae44c17682d5ac88a
+Subproject commit 3a1d76d298db023f6cf37fb08ee766f20a4e12ab
diff --git a/externals/stb_image.h b/externals/stb/stb_image.h
similarity index 100%
rename from externals/stb_image.h
rename to externals/stb/stb_image.h
diff --git a/externals/toml11 b/externals/toml11
index f925e7f28..7f6c574ff 160000
--- a/externals/toml11
+++ b/externals/toml11
@@ -1 +1 @@
-Subproject commit f925e7f287c0008813c2294798cf9ca167fd9ffd
+Subproject commit 7f6c574ff5aa1053534e7e19c0a4f22bf4c6aaca
diff --git a/externals/tracy b/externals/tracy
index b8061982c..143a53d19 160000
--- a/externals/tracy
+++ b/externals/tracy
@@ -1 +1 @@
-Subproject commit b8061982cad0210b649541016c88ff5faa90733c
+Subproject commit 143a53d1985b8e52a7590a0daca30a0a7c653b42
diff --git a/externals/vma b/externals/vma
index 1c35ba99c..5a53a1989 160000
--- a/externals/vma
+++ b/externals/vma
@@ -1 +1 @@
-Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39
+Subproject commit 5a53a198945ba8260fbc58fadb788745ce6aa263
diff --git a/externals/vulkan-headers b/externals/vulkan-headers
index d91597a82..6a74a7d65 160000
--- a/externals/vulkan-headers
+++ b/externals/vulkan-headers
@@ -1 +1 @@
-Subproject commit d91597a82f881d473887b560a03a7edf2720b72c
+Subproject commit 6a74a7d65cafa19e38ec116651436cce6efd5b2e
diff --git a/externals/xbyak b/externals/xbyak
index d067f0d3f..4e44f4614 160000
--- a/externals/xbyak
+++ b/externals/xbyak
@@ -1 +1 @@
-Subproject commit d067f0d3f55696ae8bc9a25ad7012ee80f221d54
+Subproject commit 4e44f4614ddbf038f2a6296f5b906d5c72691e0f
diff --git a/externals/xxhash b/externals/xxhash
index d4ad85e4a..2bf8313b9 160000
--- a/externals/xxhash
+++ b/externals/xxhash
@@ -1 +1 @@
-Subproject commit d4ad85e4afaad5c780f54db1dc967fff5a869ffd
+Subproject commit 2bf8313b934633b2a5b7e8fd239645b85e10c852
diff --git a/externals/zydis b/externals/zydis
index 9d298eb80..bffbb610c 160000
--- a/externals/zydis
+++ b/externals/zydis
@@ -1 +1 @@
-Subproject commit 9d298eb8067ff62a237203d1e1470785033e185c
+Subproject commit bffbb610cfea643b98e87658b9058382f7522807
diff --git a/src/audio_core/sdl_audio.cpp b/src/audio_core/sdl_audio.cpp
deleted file mode 100644
index 7fed42a44..000000000
--- a/src/audio_core/sdl_audio.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "sdl_audio.h"
-
-#include "common/assert.h"
-#include "core/libraries/error_codes.h"
-
-#include
-#include
-#include
-
-#include // std::unique_lock
-
-namespace Audio {
-
-constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
-
-s32 SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
- Libraries::AudioOut::OrbisAudioOutParamFormat format) {
- using Libraries::AudioOut::OrbisAudioOutParamFormat;
- std::unique_lock lock{m_mutex};
- for (int id = 0; id < portsOut.size(); id++) {
- auto& port = portsOut[id];
- if (!port.isOpen) {
- port.isOpen = true;
- port.type = type;
- port.samples_num = samples_num;
- port.freq = freq;
- port.format = format;
- SDL_AudioFormat sampleFormat;
- switch (format) {
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
- sampleFormat = SDL_AUDIO_S16;
- port.channels_num = 1;
- port.sample_size = 2;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
- sampleFormat = SDL_AUDIO_F32;
- port.channels_num = 1;
- port.sample_size = 4;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
- sampleFormat = SDL_AUDIO_S16;
- port.channels_num = 2;
- port.sample_size = 2;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
- sampleFormat = SDL_AUDIO_F32;
- port.channels_num = 2;
- port.sample_size = 4;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
- sampleFormat = SDL_AUDIO_S16;
- port.channels_num = 8;
- port.sample_size = 2;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
- sampleFormat = SDL_AUDIO_F32;
- port.channels_num = 8;
- port.sample_size = 4;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
- sampleFormat = SDL_AUDIO_S16;
- port.channels_num = 8;
- port.sample_size = 2;
- break;
- case OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
- sampleFormat = SDL_AUDIO_F32;
- port.channels_num = 8;
- port.sample_size = 4;
- break;
- default:
- UNREACHABLE_MSG("Unknown format");
- }
-
- for (int i = 0; i < port.channels_num; i++) {
- port.volume[i] = Libraries::AudioOut::SCE_AUDIO_OUT_VOLUME_0DB;
- }
-
- SDL_AudioSpec fmt;
- SDL_zero(fmt);
- fmt.format = sampleFormat;
- fmt.channels = port.channels_num;
- fmt.freq = freq; // Set frequency from the argument
- port.stream =
- SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
- SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port.stream));
- return id + 1;
- }
- }
-
- LOG_ERROR(Lib_AudioOut, "Audio ports are full");
- return ORBIS_AUDIO_OUT_ERROR_PORT_FULL; // all ports are used
-}
-
-s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
- std::shared_lock lock{m_mutex};
- auto& port = portsOut[handle - 1];
- if (!port.isOpen) {
- return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
- }
-
- const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
-
- bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
-
- lock.unlock(); // Unlock only after necessary operations
-
- while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
- SDL_Delay(0);
- }
-
- return result ? ORBIS_OK : -1;
-}
-
-s32 SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
- using Libraries::AudioOut::OrbisAudioOutParamFormat;
- std::shared_lock lock{m_mutex};
- auto& port = portsOut[handle - 1];
- if (!port.isOpen) {
- return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
- }
-
- for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) {
- auto bit = bitflag & 0x1u;
-
- if (bit == 1) {
- int src_index = i;
- if (port.format ==
- OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD ||
- port.format == OrbisAudioOutParamFormat::ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD) {
- switch (i) {
- case 4:
- src_index = 6;
- break;
- case 5:
- src_index = 7;
- break;
- case 6:
- src_index = 4;
- break;
- case 7:
- src_index = 5;
- break;
- default:
- break;
- }
- }
- port.volume[i] = volume[src_index];
- }
- }
-
- return ORBIS_OK;
-}
-
-s32 SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) {
- std::shared_lock lock{m_mutex};
- auto& port = portsOut[handle - 1];
- *type = port.type;
- *channels_num = port.channels_num;
-
- return ORBIS_OK;
-}
-
-} // namespace Audio
diff --git a/src/audio_core/sdl_audio.h b/src/audio_core/sdl_audio.h
deleted file mode 100644
index 0d4783f19..000000000
--- a/src/audio_core/sdl_audio.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include
-#include
-#include "core/libraries/audio/audioout.h"
-
-namespace Audio {
-
-class SDLAudio {
-public:
- SDLAudio() = default;
- virtual ~SDLAudio() = default;
-
- s32 AudioOutOpen(int type, u32 samples_num, u32 freq,
- Libraries::AudioOut::OrbisAudioOutParamFormat format);
- s32 AudioOutOutput(s32 handle, const void* ptr);
- s32 AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume);
- s32 AudioOutGetStatus(s32 handle, int* type, int* channels_num);
-
-private:
- struct PortOut {
- SDL_AudioStream* stream = nullptr;
- u32 samples_num = 0;
- u32 freq = 0;
- u32 format = -1;
- int type = 0;
- int channels_num = 0;
- int volume[8] = {};
- u8 sample_size = 0;
- bool isOpen = false;
- };
- std::shared_mutex m_mutex;
- std::array portsOut;
-};
-
-} // namespace Audio
diff --git a/src/common/alignment.h b/src/common/alignment.h
index 8480fae26..3fb961c63 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -22,6 +22,12 @@ template
return static_cast(value - value % size);
}
+template
+ requires std::is_integral_v
+[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
+ return (value & (alignment - 1)) == 0;
+}
+
template
requires std::is_integral_v
[[nodiscard]] constexpr bool Is16KBAligned(T value) {
diff --git a/src/common/config.cpp b/src/common/config.cpp
index e97a46005..eae8897c8 100644
--- a/src/common/config.cpp
+++ b/src/common/config.cpp
@@ -3,13 +3,14 @@
#include
#include
-#include
#include
#include // for wstring support
#include
-#include "common/logging/formatter.h"
+
#include "common/path_util.h"
#include "config.h"
+#include "logging/formatter.h"
+#include "version.h"
namespace toml {
template
@@ -46,11 +47,13 @@ static std::string backButtonBehavior = "left";
static bool useSpecialPad = false;
static int specialPadClass = 1;
static bool isDebugDump = false;
+static bool isShaderDebug = false;
static bool isShowSplash = false;
static bool isAutoUpdate = false;
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false;
+static bool shouldPatchShaders = true;
static u32 vblankDivider = 1;
static bool vkValidation = false;
static bool vkValidationSync = false;
@@ -81,7 +84,8 @@ std::vector m_pkg_viewer;
std::vector m_elf_viewer;
std::vector m_recent_files;
std::string emulator_language = "en";
-// Settings
+
+// Language
u32 m_language = 1; // english
bool isNeoMode() {
@@ -156,6 +160,10 @@ bool debugDump() {
return isDebugDump;
}
+bool collectShadersForDebug() {
+ return isShaderDebug;
+}
+
bool showSplash() {
return isShowSplash;
}
@@ -176,6 +184,10 @@ bool dumpShaders() {
return shouldDumpShaders;
}
+bool patchShaders() {
+ return shouldPatchShaders;
+}
+
bool isRdocEnabled() {
return rdocEnable;
}
@@ -228,6 +240,10 @@ void setDebugDump(bool enable) {
isDebugDump = enable;
}
+void setCollectShaderForDebug(bool enable) {
+ isShaderDebug = enable;
+}
+
void setShowSplash(bool enable) {
isShowSplash = enable;
}
@@ -334,6 +350,7 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_w = w;
main_window_geometry_h = h;
}
+
bool addGameInstallDir(const std::filesystem::path& dir) {
if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
settings_install_dirs.end()) {
@@ -342,47 +359,60 @@ bool addGameInstallDir(const std::filesystem::path& dir) {
}
return false;
}
+
void removeGameInstallDir(const std::filesystem::path& dir) {
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir);
if (iterator != settings_install_dirs.end()) {
settings_install_dirs.erase(iterator);
}
}
+
void setAddonInstallDir(const std::filesystem::path& dir) {
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 setPkgViewer(const std::vector& pkgList) {
m_pkg_viewer.resize(pkgList.size());
m_pkg_viewer = pkgList;
}
+
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;
@@ -395,18 +425,23 @@ void setEmulatorLanguage(std::string language) {
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() {
return settings_install_dirs;
}
+
std::filesystem::path getAddonInstallDir() {
if (settings_addon_install_dir.empty()) {
// Default for users without a config file or a config file from before this option existed
@@ -414,36 +449,47 @@ 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 getPkgViewer() {
return m_pkg_viewer;
}
+
std::vector getElfViewer() {
return m_elf_viewer;
}
+
std::vector getRecentFiles() {
return m_recent_files;
}
@@ -455,6 +501,7 @@ std::string getEmulatorLanguage() {
u32 GetLanguage() {
return m_language;
}
+
void load(const std::filesystem::path& path) {
// If the configuration file does not exist, create it and return
std::error_code error;
@@ -513,6 +560,7 @@ void load(const std::filesystem::path& path) {
isNullGpu = toml::find_or(gpu, "nullGpu", false);
shouldCopyGPUBuffers = toml::find_or(gpu, "copyGPUBuffers", false);
shouldDumpShaders = toml::find_or(gpu, "dumpShaders", false);
+ shouldPatchShaders = toml::find_or(gpu, "patchShaders", true);
vblankDivider = toml::find_or(gpu, "vblankDivider", 1);
}
@@ -532,6 +580,7 @@ void load(const std::filesystem::path& path) {
const toml::value& debug = data.at("Debug");
isDebugDump = toml::find_or(debug, "DebugDump", false);
+ isShaderDebug = toml::find_or(debug, "CollectShader", false);
}
if (data.contains("GUI")) {
@@ -545,16 +594,10 @@ void load(const std::filesystem::path& path) {
m_window_size_W = toml::find_or(gui, "mw_width", 0);
m_window_size_H = toml::find_or(gui, "mw_height", 0);
- // TODO Migration code, after a major release this should be removed.
- auto old_game_install_dir = toml::find_fs_path_or(gui, "installDir", {});
- if (!old_game_install_dir.empty()) {
- addGameInstallDir(std::filesystem::path{old_game_install_dir});
- } else {
- const auto install_dir_array =
- toml::find_or>(gui, "installDirs", {});
- for (const auto& dir : install_dir_array) {
- addGameInstallDir(std::filesystem::path{dir});
- }
+ const auto install_dir_array =
+ toml::find_or>(gui, "installDirs", {});
+ for (const auto& dir : install_dir_array) {
+ addGameInstallDir(std::filesystem::path{dir});
}
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
@@ -575,6 +618,7 @@ void load(const std::filesystem::path& path) {
m_language = toml::find_or(settings, "consoleLanguage", 1);
}
}
+
void save(const std::filesystem::path& path) {
toml::value data;
@@ -618,6 +662,7 @@ void save(const std::filesystem::path& path) {
data["GPU"]["nullGpu"] = isNullGpu;
data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers;
data["GPU"]["dumpShaders"] = shouldDumpShaders;
+ data["GPU"]["patchShaders"] = shouldPatchShaders;
data["GPU"]["vblankDivider"] = vblankDivider;
data["Vulkan"]["gpuId"] = gpuId;
data["Vulkan"]["validation"] = vkValidation;
@@ -627,6 +672,7 @@ void save(const std::filesystem::path& path) {
data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
data["Debug"]["DebugDump"] = isDebugDump;
+ data["Debug"]["CollectShader"] = isShaderDebug;
data["GUI"]["theme"] = mw_themes;
data["GUI"]["iconSize"] = m_icon_size;
data["GUI"]["sliderPos"] = m_slider_pos;
@@ -655,9 +701,6 @@ void save(const std::filesystem::path& path) {
data["Settings"]["consoleLanguage"] = m_language;
- // TODO Migration code, after a major release this should be removed.
- data.at("GUI").as_table().erase("installDir");
-
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
@@ -685,6 +728,7 @@ void setDefaultValues() {
useSpecialPad = false;
specialPadClass = 1;
isDebugDump = false;
+ isShaderDebug = false;
isShowSplash = false;
isAutoUpdate = false;
isNullGpu = false;
diff --git a/src/common/config.h b/src/common/config.h
index 9c71c96a8..d98c94480 100644
--- a/src/common/config.h
+++ b/src/common/config.h
@@ -37,15 +37,18 @@ u32 getScreenHeight();
s32 getGpuId();
bool debugDump();
+bool collectShadersForDebug();
bool showSplash();
bool autoUpdate();
bool nullGpu();
bool copyGPUCmdBuffers();
bool dumpShaders();
+bool patchShaders();
bool isRdocEnabled();
u32 vblankDiv();
void setDebugDump(bool enable);
+void setCollectShaderForDebug(bool enable);
void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setNullGpu(bool enable);
diff --git a/src/common/debug.h b/src/common/debug.h
index 596ad7b84..091c6191d 100644
--- a/src/common/debug.h
+++ b/src/common/debug.h
@@ -41,7 +41,7 @@ enum MarkersPalette : int {
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
#define HLE_TRACE ZoneScopedC(HleMarkerColor)
-#define TRACE_HINT(str) ZoneText(str.c_str(), str.size())
+#define TRACE_HINT(str) ZoneText(str.data(), str.size())
#define TRACE_WARN(msg) \
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
diff --git a/src/common/discord_rpc_handler.cpp b/src/common/discord_rpc_handler.cpp
index 91b278a15..448cb4a7f 100644
--- a/src/common/discord_rpc_handler.cpp
+++ b/src/common/discord_rpc_handler.cpp
@@ -3,7 +3,7 @@
#include
#include
-#include "src/common/discord_rpc_handler.h"
+#include "discord_rpc_handler.h"
namespace DiscordRPCHandler {
@@ -17,7 +17,7 @@ void RPC::init() {
void RPC::setStatusIdling() {
DiscordRichPresence rpc{};
- rpc.largeImageKey = "https://github.com/shadps4-emu/shadPS4/raw/main/.github/shadps4.png";
+ rpc.largeImageKey = "https://cdn.jsdelivr.net/gh/shadps4-emu/shadPS4@main/.github/shadps4.png";
rpc.largeImageText = "shadPS4 is a PS4 emulator";
rpc.startTimestamp = startTimestamp;
rpc.details = "Idle";
diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp
index dd3a40cae..067010a26 100644
--- a/src/common/io_file.cpp
+++ b/src/common/io_file.cpp
@@ -377,16 +377,18 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false;
}
- u64 size = GetSize();
- if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
- LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
- return false;
- } else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
- LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
- return false;
- } else if (origin == SeekOrigin::End && offset > 0) {
- LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
- return false;
+ if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
+ u64 size = GetSize();
+ if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
+ LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
+ return false;
+ } else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
+ LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
+ return false;
+ } else if (origin == SeekOrigin::End && offset > 0) {
+ LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
+ return false;
+ }
}
errno = 0;
diff --git a/src/common/io_file.h b/src/common/io_file.h
index 8fed4981f..feb2110ac 100644
--- a/src/common/io_file.h
+++ b/src/common/io_file.h
@@ -10,6 +10,7 @@
#include "common/concepts.h"
#include "common/types.h"
+#include "enum.h"
namespace Common::FS {
@@ -42,6 +43,7 @@ enum class FileAccessMode {
*/
ReadAppend = Read | Append,
};
+DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);
enum class FileType {
BinaryFile,
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 5ca594bf7..75c61a188 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -69,6 +69,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Common, Memory) \
CLS(Core) \
SUB(Core, Linker) \
+ SUB(Core, Devices) \
CLS(Config) \
CLS(Debug) \
CLS(Kernel) \
@@ -105,7 +106,9 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Rtc) \
SUB(Lib, DiscMap) \
SUB(Lib, Png) \
+ SUB(Lib, Jpeg) \
SUB(Lib, PlayGo) \
+ SUB(Lib, PlayGoDialog) \
SUB(Lib, Random) \
SUB(Lib, Usbd) \
SUB(Lib, Ajm) \
@@ -121,6 +124,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Fiber) \
SUB(Lib, Vdec2) \
SUB(Lib, Videodec) \
+ SUB(Lib, RazorCpu) \
CLS(Frontend) \
CLS(Render) \
SUB(Render, Vulkan) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 2821729d4..a0e7d021f 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -35,6 +35,7 @@ enum class Class : u8 {
Common_Memory, ///< Memory mapping and management functions
Core, ///< LLE emulation core
Core_Linker, ///< The module linker
+ Core_Devices, ///< Devices emulation
Config, ///< Emulator configuration (including commandline)
Debug, ///< Debugging tools
Kernel, ///< The HLE implementation of the PS4 kernel.
@@ -72,7 +73,9 @@ enum class Class : u8 {
Lib_Rtc, ///< The LibSceRtc implementation.
Lib_DiscMap, ///< The LibSceDiscMap implementation.
Lib_Png, ///< The LibScePng implementation.
+ Lib_Jpeg, ///< The LibSceJpeg implementation.
Lib_PlayGo, ///< The LibScePlayGo implementation.
+ Lib_PlayGoDialog, ///< The LibScePlayGoDialog implementation.
Lib_Random, ///< The libSceRandom implementation.
Lib_Usbd, ///< The LibSceUsbd implementation.
Lib_Ajm, ///< The LibSceAjm implementation.
@@ -88,6 +91,7 @@ enum class Class : u8 {
Lib_Fiber, ///< The LibSceFiber implementation.
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
Lib_Videodec, ///< The LibSceVideodec implementation.
+ Lib_RazorCpu, ///< The LibRazorCpu implementation.
Frontend, ///< Emulator UI
Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend
diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp
index d2930cf5e..6b79edb9f 100644
--- a/src/common/memory_patcher.cpp
+++ b/src/common/memory_patcher.cpp
@@ -28,7 +28,7 @@ std::string g_game_serial;
std::string patchFile;
std::vector pending_patches;
-std::string toHex(unsigned long long value, size_t byteSize) {
+std::string toHex(u64 value, size_t byteSize) {
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(byteSize * 2) << value;
return ss.str();
@@ -38,16 +38,16 @@ std::string convertValueToHex(const std::string type, const std::string valueStr
std::string result;
if (type == "byte") {
- unsigned int value = std::stoul(valueStr, nullptr, 16);
+ const u32 value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 1);
} else if (type == "bytes16") {
- unsigned int value = std::stoul(valueStr, nullptr, 16);
+ const u32 value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 2);
} else if (type == "bytes32") {
- unsigned long value = std::stoul(valueStr, nullptr, 16);
+ const u32 value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 4);
} else if (type == "bytes64") {
- unsigned long long value = std::stoull(valueStr, nullptr, 16);
+ const u64 value = std::stoull(valueStr, nullptr, 16);
result = toHex(value, 8);
} else if (type == "float32") {
union {
diff --git a/src/common/ntapi.cpp b/src/common/ntapi.cpp
index 0fe797e09..c76c4657e 100644
--- a/src/common/ntapi.cpp
+++ b/src/common/ntapi.cpp
@@ -5,8 +5,11 @@
#include "ntapi.h"
-NtDelayExecution_t NtDelayExecution = nullptr;
+NtClose_t NtClose = nullptr;
NtSetInformationFile_t NtSetInformationFile = nullptr;
+NtCreateThread_t NtCreateThread = nullptr;
+NtTerminateThread_t NtTerminateThread = nullptr;
+NtQueueApcThreadEx_t NtQueueApcThreadEx = nullptr;
namespace Common::NtApi {
@@ -14,9 +17,12 @@ void Initialize() {
HMODULE nt_handle = GetModuleHandleA("ntdll.dll");
// http://stackoverflow.com/a/31411628/4725495
- NtDelayExecution = (NtDelayExecution_t)GetProcAddress(nt_handle, "NtDelayExecution");
+ NtClose = (NtClose_t)GetProcAddress(nt_handle, "NtClose");
NtSetInformationFile =
(NtSetInformationFile_t)GetProcAddress(nt_handle, "NtSetInformationFile");
+ NtCreateThread = (NtCreateThread_t)GetProcAddress(nt_handle, "NtCreateThread");
+ NtTerminateThread = (NtTerminateThread_t)GetProcAddress(nt_handle, "NtTerminateThread");
+ NtQueueApcThreadEx = (NtQueueApcThreadEx_t)GetProcAddress(nt_handle, "NtQueueApcThreadEx");
}
} // namespace Common::NtApi
diff --git a/src/common/ntapi.h b/src/common/ntapi.h
index 17d353403..daab8440d 100644
--- a/src/common/ntapi.h
+++ b/src/common/ntapi.h
@@ -108,14 +108,444 @@ typedef struct _FILE_DISPOSITION_INFORMATION {
BOOLEAN DeleteFile;
} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
-typedef u32(__stdcall* NtDelayExecution_t)(BOOL Alertable, PLARGE_INTEGER DelayInterval);
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWCH Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
-typedef u32(__stdcall* NtSetInformationFile_t)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
+typedef const UNICODE_STRING* PCUNICODE_STRING;
+
+typedef struct _OBJECT_ATTRIBUTES {
+ ULONG Length;
+ HANDLE RootDirectory;
+ PCUNICODE_STRING ObjectName;
+ ULONG Attributes;
+ PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR;
+ PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE
+} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+
+typedef const OBJECT_ATTRIBUTES* PCOBJECT_ATTRIBUTES;
+
+typedef struct _CLIENT_ID {
+ HANDLE UniqueProcess;
+ HANDLE UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+
+typedef struct _INITIAL_TEB {
+ struct {
+ PVOID OldStackBase;
+ PVOID OldStackLimit;
+ } OldInitialTeb;
+ PVOID StackBase;
+ PVOID StackLimit;
+ PVOID StackAllocationBase;
+} INITIAL_TEB, *PINITIAL_TEB;
+
+typedef struct _PEB_LDR_DATA {
+ ULONG Length;
+ BOOLEAN Initialized;
+ PVOID SsHandle;
+ LIST_ENTRY InLoadOrderModuleList;
+ LIST_ENTRY InMemoryOrderModuleList;
+ LIST_ENTRY InInitializationOrderModuleList;
+ PVOID EntryInProgress;
+ BOOLEAN ShutdownInProgress;
+ HANDLE ShutdownThreadId;
+} PEB_LDR_DATA, *PPEB_LDR_DATA;
+
+typedef struct _CURDIR {
+ UNICODE_STRING DosPath;
+ PVOID Handle;
+} CURDIR, *PCURDIR;
+
+typedef struct RTL_DRIVE_LETTER_CURDIR {
+ USHORT Flags;
+ USHORT Length;
+ ULONG TimeStamp;
+ UNICODE_STRING DosPath;
+} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
+
+typedef struct _RTL_USER_PROCESS_PARAMETERS {
+ ULONG AllocationSize;
+ ULONG Size;
+ ULONG Flags;
+ ULONG DebugFlags;
+ HANDLE ConsoleHandle;
+ ULONG ConsoleFlags;
+ HANDLE hStdInput;
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+ CURDIR CurrentDirectory;
+ UNICODE_STRING DllPath;
+ UNICODE_STRING ImagePathName;
+ UNICODE_STRING CommandLine;
+ PWSTR Environment;
+ ULONG dwX;
+ ULONG dwY;
+ ULONG dwXSize;
+ ULONG dwYSize;
+ ULONG dwXCountChars;
+ ULONG dwYCountChars;
+ ULONG dwFillAttribute;
+ ULONG dwFlags;
+ ULONG wShowWindow;
+ UNICODE_STRING WindowTitle;
+ UNICODE_STRING Desktop;
+ UNICODE_STRING ShellInfo;
+ UNICODE_STRING RuntimeInfo;
+ RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
+ ULONG_PTR EnvironmentSize;
+ ULONG_PTR EnvironmentVersion;
+ PVOID PackageDependencyData;
+ ULONG ProcessGroupId;
+ ULONG LoaderThreads;
+} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+
+typedef struct tagRTL_BITMAP {
+ ULONG SizeOfBitMap;
+ PULONG Buffer;
+} RTL_BITMAP, *PRTL_BITMAP;
+
+typedef struct {
+ UINT next;
+ UINT id;
+ ULONGLONG addr;
+ ULONGLONG size;
+ UINT args[4];
+} CROSS_PROCESS_WORK_ENTRY;
+
+typedef union {
+ struct {
+ UINT first;
+ UINT counter;
+ };
+ volatile LONGLONG hdr;
+} CROSS_PROCESS_WORK_HDR;
+
+typedef struct {
+ CROSS_PROCESS_WORK_HDR free_list;
+ CROSS_PROCESS_WORK_HDR work_list;
+ ULONGLONG unknown[4];
+ CROSS_PROCESS_WORK_ENTRY entries[1];
+} CROSS_PROCESS_WORK_LIST;
+
+typedef struct _CHPEV2_PROCESS_INFO {
+ ULONG Wow64ExecuteFlags; /* 000 */
+ USHORT NativeMachineType; /* 004 */
+ USHORT EmulatedMachineType; /* 006 */
+ HANDLE SectionHandle; /* 008 */
+ CROSS_PROCESS_WORK_LIST* CrossProcessWorkList; /* 010 */
+ void* unknown; /* 018 */
+} CHPEV2_PROCESS_INFO, *PCHPEV2_PROCESS_INFO;
+
+typedef u64(__stdcall* KERNEL_CALLBACK_PROC)(void*, ULONG);
+
+typedef struct _PEB { /* win32/win64 */
+ BOOLEAN InheritedAddressSpace; /* 000/000 */
+ BOOLEAN ReadImageFileExecOptions; /* 001/001 */
+ BOOLEAN BeingDebugged; /* 002/002 */
+ UCHAR ImageUsedLargePages : 1; /* 003/003 */
+ UCHAR IsProtectedProcess : 1;
+ UCHAR IsImageDynamicallyRelocated : 1;
+ UCHAR SkipPatchingUser32Forwarders : 1;
+ UCHAR IsPackagedProcess : 1;
+ UCHAR IsAppContainer : 1;
+ UCHAR IsProtectedProcessLight : 1;
+ UCHAR IsLongPathAwareProcess : 1;
+ HANDLE Mutant; /* 004/008 */
+ HMODULE ImageBaseAddress; /* 008/010 */
+ PPEB_LDR_DATA LdrData; /* 00c/018 */
+ RTL_USER_PROCESS_PARAMETERS* ProcessParameters; /* 010/020 */
+ PVOID SubSystemData; /* 014/028 */
+ HANDLE ProcessHeap; /* 018/030 */
+ PRTL_CRITICAL_SECTION FastPebLock; /* 01c/038 */
+ PVOID AtlThunkSListPtr; /* 020/040 */
+ PVOID IFEOKey; /* 024/048 */
+ ULONG ProcessInJob : 1; /* 028/050 */
+ ULONG ProcessInitializing : 1;
+ ULONG ProcessUsingVEH : 1;
+ ULONG ProcessUsingVCH : 1;
+ ULONG ProcessUsingFTH : 1;
+ ULONG ProcessPreviouslyThrottled : 1;
+ ULONG ProcessCurrentlyThrottled : 1;
+ ULONG ProcessImagesHotPatched : 1;
+ ULONG ReservedBits0 : 24;
+ KERNEL_CALLBACK_PROC* KernelCallbackTable; /* 02c/058 */
+ ULONG Reserved; /* 030/060 */
+ ULONG AtlThunkSListPtr32; /* 034/064 */
+ PVOID ApiSetMap; /* 038/068 */
+ ULONG TlsExpansionCounter; /* 03c/070 */
+ PRTL_BITMAP TlsBitmap; /* 040/078 */
+ ULONG TlsBitmapBits[2]; /* 044/080 */
+ PVOID ReadOnlySharedMemoryBase; /* 04c/088 */
+ PVOID SharedData; /* 050/090 */
+ PVOID* ReadOnlyStaticServerData; /* 054/098 */
+ PVOID AnsiCodePageData; /* 058/0a0 */
+ PVOID OemCodePageData; /* 05c/0a8 */
+ PVOID UnicodeCaseTableData; /* 060/0b0 */
+ ULONG NumberOfProcessors; /* 064/0b8 */
+ ULONG NtGlobalFlag; /* 068/0bc */
+ LARGE_INTEGER CriticalSectionTimeout; /* 070/0c0 */
+ SIZE_T HeapSegmentReserve; /* 078/0c8 */
+ SIZE_T HeapSegmentCommit; /* 07c/0d0 */
+ SIZE_T HeapDeCommitTotalFreeThreshold; /* 080/0d8 */
+ SIZE_T HeapDeCommitFreeBlockThreshold; /* 084/0e0 */
+ ULONG NumberOfHeaps; /* 088/0e8 */
+ ULONG MaximumNumberOfHeaps; /* 08c/0ec */
+ PVOID* ProcessHeaps; /* 090/0f0 */
+ PVOID GdiSharedHandleTable; /* 094/0f8 */
+ PVOID ProcessStarterHelper; /* 098/100 */
+ PVOID GdiDCAttributeList; /* 09c/108 */
+ PVOID LoaderLock; /* 0a0/110 */
+ ULONG OSMajorVersion; /* 0a4/118 */
+ ULONG OSMinorVersion; /* 0a8/11c */
+ ULONG OSBuildNumber; /* 0ac/120 */
+ ULONG OSPlatformId; /* 0b0/124 */
+ ULONG ImageSubSystem; /* 0b4/128 */
+ ULONG ImageSubSystemMajorVersion; /* 0b8/12c */
+ ULONG ImageSubSystemMinorVersion; /* 0bc/130 */
+ KAFFINITY ActiveProcessAffinityMask; /* 0c0/138 */
+#ifdef _WIN64
+ ULONG GdiHandleBuffer[60]; /* /140 */
+#else
+ ULONG GdiHandleBuffer[34]; /* 0c4/ */
+#endif
+ PVOID PostProcessInitRoutine; /* 14c/230 */
+ PRTL_BITMAP TlsExpansionBitmap; /* 150/238 */
+ ULONG TlsExpansionBitmapBits[32]; /* 154/240 */
+ ULONG SessionId; /* 1d4/2c0 */
+ ULARGE_INTEGER AppCompatFlags; /* 1d8/2c8 */
+ ULARGE_INTEGER AppCompatFlagsUser; /* 1e0/2d0 */
+ PVOID ShimData; /* 1e8/2d8 */
+ PVOID AppCompatInfo; /* 1ec/2e0 */
+ UNICODE_STRING CSDVersion; /* 1f0/2e8 */
+ PVOID ActivationContextData; /* 1f8/2f8 */
+ PVOID ProcessAssemblyStorageMap; /* 1fc/300 */
+ PVOID SystemDefaultActivationData; /* 200/308 */
+ PVOID SystemAssemblyStorageMap; /* 204/310 */
+ SIZE_T MinimumStackCommit; /* 208/318 */
+ PVOID* FlsCallback; /* 20c/320 */
+ LIST_ENTRY FlsListHead; /* 210/328 */
+ union {
+ PRTL_BITMAP FlsBitmap; /* 218/338 */
+#ifdef _WIN64
+ CHPEV2_PROCESS_INFO* ChpeV2ProcessInfo; /* /338 */
+#endif
+ };
+ ULONG FlsBitmapBits[4]; /* 21c/340 */
+ ULONG FlsHighIndex; /* 22c/350 */
+ PVOID WerRegistrationData; /* 230/358 */
+ PVOID WerShipAssertPtr; /* 234/360 */
+ PVOID EcCodeBitMap; /* 238/368 */
+ PVOID pImageHeaderHash; /* 23c/370 */
+ ULONG HeapTracingEnabled : 1; /* 240/378 */
+ ULONG CritSecTracingEnabled : 1;
+ ULONG LibLoaderTracingEnabled : 1;
+ ULONG SpareTracingBits : 29;
+ ULONGLONG CsrServerReadOnlySharedMemoryBase; /* 248/380 */
+ ULONG TppWorkerpListLock; /* 250/388 */
+ LIST_ENTRY TppWorkerpList; /* 254/390 */
+ PVOID WaitOnAddressHashTable[0x80]; /* 25c/3a0 */
+ PVOID TelemetryCoverageHeader; /* 45c/7a0 */
+ ULONG CloudFileFlags; /* 460/7a8 */
+ ULONG CloudFileDiagFlags; /* 464/7ac */
+ CHAR PlaceholderCompatibilityMode; /* 468/7b0 */
+ CHAR PlaceholderCompatibilityModeReserved[7]; /* 469/7b1 */
+ PVOID LeapSecondData; /* 470/7b8 */
+ ULONG LeapSecondFlags; /* 474/7c0 */
+ ULONG NtGlobalFlag2; /* 478/7c4 */
+} PEB, *PPEB;
+
+typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME {
+ struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous;
+ struct _ACTIVATION_CONTEXT* ActivationContext;
+ ULONG Flags;
+} RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME;
+
+typedef struct _ACTIVATION_CONTEXT_STACK {
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame;
+ LIST_ENTRY FrameListCache;
+ ULONG Flags;
+ ULONG NextCookieSequenceNumber;
+ ULONG_PTR StackId;
+} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;
+
+typedef struct _GDI_TEB_BATCH {
+ ULONG Offset;
+ HANDLE HDC;
+ ULONG Buffer[0x136];
+} GDI_TEB_BATCH;
+
+typedef struct _TEB_ACTIVE_FRAME_CONTEXT {
+ ULONG Flags;
+ const char* FrameName;
+} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT;
+
+typedef struct _TEB_ACTIVE_FRAME {
+ ULONG Flags;
+ struct _TEB_ACTIVE_FRAME* Previous;
+ TEB_ACTIVE_FRAME_CONTEXT* Context;
+} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME;
+
+typedef struct _TEB { /* win32/win64 */
+ NT_TIB Tib; /* 000/0000 */
+ PVOID EnvironmentPointer; /* 01c/0038 */
+ CLIENT_ID ClientId; /* 020/0040 */
+ PVOID ActiveRpcHandle; /* 028/0050 */
+ PVOID ThreadLocalStoragePointer; /* 02c/0058 */
+ PPEB Peb; /* 030/0060 */
+ ULONG LastErrorValue; /* 034/0068 */
+ ULONG CountOfOwnedCriticalSections; /* 038/006c */
+ PVOID CsrClientThread; /* 03c/0070 */
+ PVOID Win32ThreadInfo; /* 040/0078 */
+ ULONG User32Reserved[26]; /* 044/0080 */
+ ULONG UserReserved[5]; /* 0ac/00e8 */
+ PVOID WOW32Reserved; /* 0c0/0100 */
+ ULONG CurrentLocale; /* 0c4/0108 */
+ ULONG FpSoftwareStatusRegister; /* 0c8/010c */
+ PVOID ReservedForDebuggerInstrumentation[16]; /* 0cc/0110 */
+#ifdef _WIN64
+ PVOID SystemReserved1[30]; /* /0190 */
+#else
+ PVOID SystemReserved1[26]; /* 10c/ */
+#endif
+ char PlaceholderCompatibilityMode; /* 174/0280 */
+ BOOLEAN PlaceholderHydrationAlwaysExplicit; /* 175/0281 */
+ char PlaceholderReserved[10]; /* 176/0282 */
+ DWORD ProxiedProcessId; /* 180/028c */
+ ACTIVATION_CONTEXT_STACK ActivationContextStack; /* 184/0290 */
+ UCHAR WorkingOnBehalfOfTicket[8]; /* 19c/02b8 */
+ LONG ExceptionCode; /* 1a4/02c0 */
+ ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; /* 1a8/02c8 */
+ ULONG_PTR InstrumentationCallbackSp; /* 1ac/02d0 */
+ ULONG_PTR InstrumentationCallbackPreviousPc; /* 1b0/02d8 */
+ ULONG_PTR InstrumentationCallbackPreviousSp; /* 1b4/02e0 */
+#ifdef _WIN64
+ ULONG TxFsContext; /* /02e8 */
+ BOOLEAN InstrumentationCallbackDisabled; /* /02ec */
+ BOOLEAN UnalignedLoadStoreExceptions; /* /02ed */
+#else
+ BOOLEAN InstrumentationCallbackDisabled; /* 1b8/ */
+ BYTE SpareBytes1[23]; /* 1b9/ */
+ ULONG TxFsContext; /* 1d0/ */
+#endif
+ GDI_TEB_BATCH GdiTebBatch; /* 1d4/02f0 */
+ CLIENT_ID RealClientId; /* 6b4/07d8 */
+ HANDLE GdiCachedProcessHandle; /* 6bc/07e8 */
+ ULONG GdiClientPID; /* 6c0/07f0 */
+ ULONG GdiClientTID; /* 6c4/07f4 */
+ PVOID GdiThreadLocaleInfo; /* 6c8/07f8 */
+ ULONG_PTR Win32ClientInfo[62]; /* 6cc/0800 */
+ PVOID glDispatchTable[233]; /* 7c4/09f0 */
+ PVOID glReserved1[29]; /* b68/1138 */
+ PVOID glReserved2; /* bdc/1220 */
+ PVOID glSectionInfo; /* be0/1228 */
+ PVOID glSection; /* be4/1230 */
+ PVOID glTable; /* be8/1238 */
+ PVOID glCurrentRC; /* bec/1240 */
+ PVOID glContext; /* bf0/1248 */
+ ULONG LastStatusValue; /* bf4/1250 */
+ UNICODE_STRING StaticUnicodeString; /* bf8/1258 */
+ WCHAR StaticUnicodeBuffer[261]; /* c00/1268 */
+ PVOID DeallocationStack; /* e0c/1478 */
+ PVOID TlsSlots[64]; /* e10/1480 */
+ LIST_ENTRY TlsLinks; /* f10/1680 */
+ PVOID Vdm; /* f18/1690 */
+ PVOID ReservedForNtRpc; /* f1c/1698 */
+ PVOID DbgSsReserved[2]; /* f20/16a0 */
+ ULONG HardErrorMode; /* f28/16b0 */
+#ifdef _WIN64
+ PVOID Instrumentation[11]; /* /16b8 */
+#else
+ PVOID Instrumentation[9]; /* f2c/ */
+#endif
+ GUID ActivityId; /* f50/1710 */
+ PVOID SubProcessTag; /* f60/1720 */
+ PVOID PerflibData; /* f64/1728 */
+ PVOID EtwTraceData; /* f68/1730 */
+ PVOID WinSockData; /* f6c/1738 */
+ ULONG GdiBatchCount; /* f70/1740 */
+ ULONG IdealProcessorValue; /* f74/1744 */
+ ULONG GuaranteedStackBytes; /* f78/1748 */
+ PVOID ReservedForPerf; /* f7c/1750 */
+ PVOID ReservedForOle; /* f80/1758 */
+ ULONG WaitingOnLoaderLock; /* f84/1760 */
+ PVOID SavedPriorityState; /* f88/1768 */
+ ULONG_PTR ReservedForCodeCoverage; /* f8c/1770 */
+ PVOID ThreadPoolData; /* f90/1778 */
+ PVOID* TlsExpansionSlots; /* f94/1780 */
+#ifdef _WIN64
+ union {
+ PVOID DeallocationBStore; /* /1788 */
+ PVOID* ChpeV2CpuAreaInfo; /* /1788 */
+ } DUMMYUNIONNAME;
+ PVOID BStoreLimit; /* /1790 */
+#endif
+ ULONG MuiGeneration; /* f98/1798 */
+ ULONG IsImpersonating; /* f9c/179c */
+ PVOID NlsCache; /* fa0/17a0 */
+ PVOID ShimData; /* fa4/17a8 */
+ ULONG HeapVirtualAffinity; /* fa8/17b0 */
+ PVOID CurrentTransactionHandle; /* fac/17b8 */
+ TEB_ACTIVE_FRAME* ActiveFrame; /* fb0/17c0 */
+ PVOID* FlsSlots; /* fb4/17c8 */
+ PVOID PreferredLanguages; /* fb8/17d0 */
+ PVOID UserPrefLanguages; /* fbc/17d8 */
+ PVOID MergedPrefLanguages; /* fc0/17e0 */
+ ULONG MuiImpersonation; /* fc4/17e8 */
+ USHORT CrossTebFlags; /* fc8/17ec */
+ USHORT SameTebFlags; /* fca/17ee */
+ PVOID TxnScopeEnterCallback; /* fcc/17f0 */
+ PVOID TxnScopeExitCallback; /* fd0/17f8 */
+ PVOID TxnScopeContext; /* fd4/1800 */
+ ULONG LockCount; /* fd8/1808 */
+ LONG WowTebOffset; /* fdc/180c */
+ PVOID ResourceRetValue; /* fe0/1810 */
+ PVOID ReservedForWdf; /* fe4/1818 */
+ ULONGLONG ReservedForCrt; /* fe8/1820 */
+ GUID EffectiveContainerId; /* ff0/1828 */
+} TEB, *PTEB;
+static_assert(offsetof(TEB, DeallocationStack) ==
+ 0x1478); /* The only member we care about at the moment */
+
+typedef enum _QUEUE_USER_APC_FLAGS {
+ QueueUserApcFlagsNone,
+ QueueUserApcFlagsSpecialUserApc,
+ QueueUserApcFlagsMaxValue
+} QUEUE_USER_APC_FLAGS;
+
+typedef union _USER_APC_OPTION {
+ ULONG_PTR UserApcFlags;
+ HANDLE MemoryReserveHandle;
+} USER_APC_OPTION, *PUSER_APC_OPTION;
+
+using PPS_APC_ROUTINE = void (*)(PVOID ApcArgument1, PVOID ApcArgument2, PVOID ApcArgument3,
+ PCONTEXT Context);
+
+typedef u64(__stdcall* NtClose_t)(HANDLE Handle);
+
+typedef u64(__stdcall* NtSetInformationFile_t)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation, ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass);
-extern NtDelayExecution_t NtDelayExecution;
+typedef u64(__stdcall* NtCreateThread_t)(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess,
+ PCOBJECT_ATTRIBUTES ObjectAttributes, HANDLE ProcessHandle,
+ PCLIENT_ID ClientId, PCONTEXT ThreadContext,
+ PINITIAL_TEB InitialTeb, BOOLEAN CreateSuspended);
+
+typedef u64(__stdcall* NtTerminateThread_t)(HANDLE ThreadHandle, u64 ExitStatus);
+
+typedef u64(__stdcall* NtQueueApcThreadEx_t)(HANDLE ThreadHandle,
+ USER_APC_OPTION UserApcReserveHandle,
+ PPS_APC_ROUTINE ApcRoutine, PVOID ApcArgument1,
+ PVOID ApcArgument2, PVOID ApcArgument3);
+
+extern NtClose_t NtClose;
extern NtSetInformationFile_t NtSetInformationFile;
+extern NtCreateThread_t NtCreateThread;
+extern NtTerminateThread_t NtTerminateThread;
+extern NtQueueApcThreadEx_t NtQueueApcThreadEx;
namespace Common::NtApi {
void Initialize();
diff --git a/src/common/slab_heap.h b/src/common/slab_heap.h
new file mode 100644
index 000000000..7648ebea3
--- /dev/null
+++ b/src/common/slab_heap.h
@@ -0,0 +1,163 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#include "common/assert.h"
+#include "common/spin_lock.h"
+
+namespace Common {
+
+class SlabHeapImpl {
+public:
+ struct Node {
+ Node* next{};
+ };
+
+public:
+ constexpr SlabHeapImpl() = default;
+
+ void Initialize() {
+ ASSERT(m_head == nullptr);
+ }
+
+ Node* GetHead() const {
+ return m_head;
+ }
+
+ void* Allocate() {
+ m_lock.lock();
+
+ Node* ret = m_head;
+ if (ret != nullptr) {
+ m_head = ret->next;
+ }
+
+ m_lock.unlock();
+ return ret;
+ }
+
+ void Free(void* obj) {
+ m_lock.lock();
+
+ Node* node = static_cast(obj);
+ node->next = m_head;
+ m_head = node;
+
+ m_lock.unlock();
+ }
+
+private:
+ std::atomic m_head{};
+ Common::SpinLock m_lock;
+};
+
+class SlabHeapBase : protected SlabHeapImpl {
+private:
+ size_t m_obj_size{};
+ uintptr_t m_peak{};
+ uintptr_t m_start{};
+ uintptr_t m_end{};
+
+public:
+ constexpr SlabHeapBase() = default;
+
+ bool Contains(uintptr_t address) const {
+ return m_start <= address && address < m_end;
+ }
+
+ void Initialize(size_t obj_size, void* memory, size_t memory_size) {
+ // Ensure we don't initialize a slab using null memory.
+ ASSERT(memory != nullptr);
+
+ // Set our object size.
+ m_obj_size = obj_size;
+
+ // Initialize the base allocator.
+ SlabHeapImpl::Initialize();
+
+ // Set our tracking variables.
+ const size_t num_obj = (memory_size / obj_size);
+ m_start = reinterpret_cast(memory);
+ m_end = m_start + num_obj * obj_size;
+ m_peak = m_start;
+
+ // Free the objects.
+ u8* cur = reinterpret_cast(m_end);
+
+ for (size_t i = 0; i < num_obj; i++) {
+ cur -= obj_size;
+ SlabHeapImpl::Free(cur);
+ }
+ }
+
+ size_t GetSlabHeapSize() const {
+ return (m_end - m_start) / this->GetObjectSize();
+ }
+
+ size_t GetObjectSize() const {
+ return m_obj_size;
+ }
+
+ void* Allocate() {
+ void* obj = SlabHeapImpl::Allocate();
+ return obj;
+ }
+
+ void Free(void* obj) {
+ // Don't allow freeing an object that wasn't allocated from this heap.
+ const bool contained = this->Contains(reinterpret_cast(obj));
+ ASSERT(contained);
+ SlabHeapImpl::Free(obj);
+ }
+
+ size_t GetObjectIndex(const void* obj) const {
+ return (reinterpret_cast(obj) - m_start) / this->GetObjectSize();
+ }
+
+ size_t GetPeakIndex() const {
+ return this->GetObjectIndex(reinterpret_cast(m_peak));
+ }
+
+ uintptr_t GetSlabHeapAddress() const {
+ return m_start;
+ }
+
+ size_t GetNumRemaining() const {
+ // Only calculate the number of remaining objects under debug configuration.
+ return 0;
+ }
+};
+
+template
+class SlabHeap final : public SlabHeapBase {
+private:
+ using BaseHeap = SlabHeapBase;
+
+public:
+ constexpr SlabHeap() = default;
+
+ void Initialize(void* memory, size_t memory_size) {
+ BaseHeap::Initialize(sizeof(T), memory, memory_size);
+ }
+
+ T* Allocate() {
+ T* obj = static_cast(BaseHeap::Allocate());
+
+ if (obj != nullptr) [[likely]] {
+ std::construct_at(obj);
+ }
+ return obj;
+ }
+
+ void Free(T* obj) {
+ BaseHeap::Free(obj);
+ }
+
+ size_t GetObjectIndex(const T* obj) const {
+ return BaseHeap::GetObjectIndex(obj);
+ }
+};
+
+} // namespace Common
diff --git a/src/common/slot_vector.h b/src/common/slot_vector.h
index 36e647971..d4ac51361 100644
--- a/src/common/slot_vector.h
+++ b/src/common/slot_vector.h
@@ -3,10 +3,7 @@
#pragma once
-#include
-#include
#include
-#include
#include
#include
#include "common/assert.h"
diff --git a/src/common/spin_lock.cpp b/src/common/spin_lock.cpp
new file mode 100755
index 000000000..9d4cfe36b
--- /dev/null
+++ b/src/common/spin_lock.cpp
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/spin_lock.h"
+
+#if _MSC_VER
+#include
+#if _M_AMD64
+#define __x86_64__ 1
+#endif
+#if _M_ARM64
+#define __aarch64__ 1
+#endif
+#else
+#if __x86_64__
+#include
+#endif
+#endif
+
+namespace {
+
+void ThreadPause() {
+#if __x86_64__
+ _mm_pause();
+#elif __aarch64__ && _MSC_VER
+ __yield();
+#elif __aarch64__
+ asm("yield");
+#endif
+}
+
+} // Anonymous namespace
+
+namespace Common {
+
+void SpinLock::lock() {
+ while (lck.test_and_set(std::memory_order_acquire)) {
+ ThreadPause();
+ }
+}
+
+void SpinLock::unlock() {
+ lck.clear(std::memory_order_release);
+}
+
+bool SpinLock::try_lock() {
+ if (lck.test_and_set(std::memory_order_acquire)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace Common
diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h
new file mode 100755
index 000000000..3229a8c6a
--- /dev/null
+++ b/src/common/spin_lock.h
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+
+namespace Common {
+
+/**
+ * SpinLock class
+ * a lock similar to mutex that forces a thread to spin wait instead calling the
+ * supervisor. Should be used on short sequences of code.
+ */
+class SpinLock {
+public:
+ SpinLock() = default;
+
+ SpinLock(const SpinLock&) = delete;
+ SpinLock& operator=(const SpinLock&) = delete;
+
+ SpinLock(SpinLock&&) = delete;
+ SpinLock& operator=(SpinLock&&) = delete;
+
+ void lock();
+ void unlock();
+ [[nodiscard]] bool try_lock();
+
+private:
+ std::atomic_flag lck = ATOMIC_FLAG_INIT;
+};
+
+} // namespace Common
diff --git a/src/common/stb.cpp b/src/common/stb.cpp
new file mode 100644
index 000000000..0cd916185
--- /dev/null
+++ b/src/common/stb.cpp
@@ -0,0 +1,7 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_ONLY_PNG
+#define STBI_NO_STDIO
+#include "common/stb.h"
diff --git a/src/common/stb.h b/src/common/stb.h
new file mode 100644
index 000000000..6f4d34483
--- /dev/null
+++ b/src/common/stb.h
@@ -0,0 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
diff --git a/src/common/support/avdec.h b/src/common/support/avdec.h
new file mode 100644
index 000000000..fa3483dc4
--- /dev/null
+++ b/src/common/support/avdec.h
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+// support header file for libav
+
+// The av_err2str macro in libavutil/error.h does not play nice with C++
+#ifdef av_err2str
+#undef av_err2str
+#include
+av_always_inline std::string av_err2string(int errnum) {
+ char errbuf[AV_ERROR_MAX_STRING_SIZE];
+ return av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, errnum);
+}
+#define av_err2str(err) av_err2string(err).c_str()
+#endif // av_err2str
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 46df68c38..c87aea6ef 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -147,6 +147,10 @@ void SetCurrentThreadName(const char* name) {
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
}
+void SetThreadName(void* thread, const char* name) {
+ SetThreadDescription(thread, UTF8ToUTF16W(name).data());
+}
+
#else // !MSVC_VER, so must be POSIX threads
// MinGW with the POSIX threading model does not support pthread_setname_np
@@ -170,11 +174,19 @@ void SetCurrentThreadName(const char* name) {
pthread_setname_np(pthread_self(), name);
#endif
}
+
+void SetThreadName(void* thread, const char* name) {
+ // TODO
+}
#endif
#if defined(_WIN32)
void SetCurrentThreadName(const char*) {
- // Do Nothing on MingW
+ // Do Nothing on MinGW
+}
+
+void SetThreadName(void* thread, const char* name) {
+ // Do Nothing on MinGW
}
#endif
diff --git a/src/common/thread.h b/src/common/thread.h
index fd962f8e5..175ba9445 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -23,6 +23,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority);
void SetCurrentThreadName(const char* name);
+void SetThreadName(void* thread, const char* name);
+
class AccurateTimer {
std::chrono::nanoseconds target_interval{};
std::chrono::nanoseconds total_wait{};
diff --git a/src/common/va_ctx.h b/src/common/va_ctx.h
new file mode 100644
index 000000000..e0b8c0bab
--- /dev/null
+++ b/src/common/va_ctx.h
@@ -0,0 +1,111 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include
+#include "common/types.h"
+
+#define VA_ARGS \
+ uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
+ uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
+ __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
+
+#define VA_CTX(ctx) \
+ alignas(16)::Common::VaCtx ctx{}; \
+ (ctx).reg_save_area.gp[0] = rdi; \
+ (ctx).reg_save_area.gp[1] = rsi; \
+ (ctx).reg_save_area.gp[2] = rdx; \
+ (ctx).reg_save_area.gp[3] = rcx; \
+ (ctx).reg_save_area.gp[4] = r8; \
+ (ctx).reg_save_area.gp[5] = r9; \
+ (ctx).reg_save_area.fp[0] = xmm0; \
+ (ctx).reg_save_area.fp[1] = xmm1; \
+ (ctx).reg_save_area.fp[2] = xmm2; \
+ (ctx).reg_save_area.fp[3] = xmm3; \
+ (ctx).reg_save_area.fp[4] = xmm4; \
+ (ctx).reg_save_area.fp[5] = xmm5; \
+ (ctx).reg_save_area.fp[6] = xmm6; \
+ (ctx).reg_save_area.fp[7] = xmm7; \
+ (ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
+ (ctx).va_list.gp_offset = offsetof(::Common::VaRegSave, gp); \
+ (ctx).va_list.fp_offset = offsetof(::Common::VaRegSave, fp); \
+ (ctx).va_list.overflow_arg_area = &overflow_arg_area;
+
+namespace Common {
+
+// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure
+
+struct VaList {
+ u32 gp_offset;
+ u32 fp_offset;
+ void* overflow_arg_area;
+ void* reg_save_area;
+};
+
+struct VaRegSave {
+ u64 gp[6];
+ __m128 fp[8];
+};
+
+struct VaCtx {
+ VaRegSave reg_save_area;
+ VaList va_list;
+};
+
+template
+T vaArgRegSaveAreaGp(VaList* l) {
+ auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->gp_offset);
+ l->gp_offset += Size;
+ return *addr;
+}
+template
+T vaArgOverflowArgArea(VaList* l) {
+ auto ptr = ((reinterpret_cast(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
+ auto* addr = reinterpret_cast(ptr);
+ l->overflow_arg_area = reinterpret_cast(ptr + Size);
+ return *addr;
+}
+
+template
+T vaArgRegSaveAreaFp(VaList* l) {
+ auto* addr = reinterpret_cast(static_cast(l->reg_save_area) + l->fp_offset);
+ l->fp_offset += Size;
+ return *addr;
+}
+
+inline int vaArgInteger(VaList* l) {
+ if (l->gp_offset <= 40) {
+ return vaArgRegSaveAreaGp(l);
+ }
+ return vaArgOverflowArgArea(l);
+}
+
+inline long long vaArgLongLong(VaList* l) {
+ if (l->gp_offset <= 40) {
+ return vaArgRegSaveAreaGp(l);
+ }
+ return vaArgOverflowArgArea(l);
+}
+inline long vaArgLong(VaList* l) {
+ if (l->gp_offset <= 40) {
+ return vaArgRegSaveAreaGp(l);
+ }
+ return vaArgOverflowArgArea(l);
+}
+
+inline double vaArgDouble(VaList* l) {
+ if (l->fp_offset <= 160) {
+ return vaArgRegSaveAreaFp(l);
+ }
+ return vaArgOverflowArgArea(l);
+}
+
+template
+T* vaArgPtr(VaList* l) {
+ if (l->gp_offset <= 40) {
+ return vaArgRegSaveAreaGp(l);
+ }
+ return vaArgOverflowArgArea(l);
+}
+
+} // namespace Common
diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp
index 8ba99e32d..24f5e9f87 100644
--- a/src/core/address_space.cpp
+++ b/src/core/address_space.cpp
@@ -1,13 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include