mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
Merge branch 'shadps4-emu:main' into main
This commit is contained in:
commit
f2b82d3db1
@ -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
|
||||
|
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@ -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
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -414,3 +414,7 @@ FodyWeavers.xsd
|
||||
|
||||
# for macOS
|
||||
**/.DS_Store
|
||||
|
||||
# JetBrains
|
||||
.idea
|
||||
cmake-build-*
|
||||
|
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -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
|
168
CMakeLists.txt
168
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)
|
||||
|
@ -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"
|
||||
|
19
cmake/Findstb.cmake
Normal file
19
cmake/Findstb.cmake
Normal file
@ -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)
|
@ -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()
|
46
dist/MacOSBundleInfo.plist.in
vendored
Normal file
46
dist/MacOSBundleInfo.plist.in
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>shadps4</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.shadps4-emu.shadps4</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>shadps4</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.games</string>
|
||||
<key>GCSupportsGameMode</key>
|
||||
<true/>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string></string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@ -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`
|
||||
|
19
documents/patching-shader.md
Normal file
19
documents/patching-shader.md
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
-->
|
||||
|
||||
### 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
|
42
externals/CMakeLists.txt
vendored
42
externals/CMakeLists.txt
vendored
@ -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()
|
||||
|
2
externals/LibAtrac9
vendored
2
externals/LibAtrac9
vendored
@ -1 +1 @@
|
||||
Subproject commit 3acdcdc78f129c2e6145331ff650fa76dd88d62c
|
||||
Subproject commit 9640129dc6f2afbca6ceeca3019856e8653a5fb2
|
2
externals/date
vendored
2
externals/date
vendored
@ -1 +1 @@
|
||||
Subproject commit dd8affc6de5755e07638bf0a14382d29549d6ee9
|
||||
Subproject commit 28b7b232521ace2c8ef3f2ad4126daec3569c14f
|
2
externals/ext-boost
vendored
2
externals/ext-boost
vendored
@ -1 +1 @@
|
||||
Subproject commit f2474e1b584fb7a3ed6f85ba875e6eacd742ec8a
|
||||
Subproject commit ca6f230e67be7cc45fc919057f07b2aee64dadc1
|
2
externals/ffmpeg-core
vendored
2
externals/ffmpeg-core
vendored
@ -1 +1 @@
|
||||
Subproject commit e30b7d7fe228bfb3f6e41ce1040b44a15eb7d5e0
|
||||
Subproject commit 27de97c826b6b40c255891c37ac046a25836a575
|
2
externals/glslang
vendored
2
externals/glslang
vendored
@ -1 +1 @@
|
||||
Subproject commit e61d7bb3006f451968714e2f653412081871e1ee
|
||||
Subproject commit a0995c49ebcaca2c6d3b03efbabf74f3843decdb
|
1
externals/libpng
vendored
Submodule
1
externals/libpng
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c1cc0f3f4c3d4abd11ca68c59446a29ff6f95003
|
2
externals/magic_enum
vendored
2
externals/magic_enum
vendored
@ -1 +1 @@
|
||||
Subproject commit 126539e13cccdc2e75ce770e94f3c26403099fa5
|
||||
Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
|
2
externals/pugixml
vendored
2
externals/pugixml
vendored
@ -1 +1 @@
|
||||
Subproject commit 3b17184379fcaaeb7f1fbe08018b7fedf2640b3b
|
||||
Subproject commit 4bc14418d12d289dd9978fdce9490a45deeb653e
|
2
externals/sdl3
vendored
2
externals/sdl3
vendored
@ -1 +1 @@
|
||||
Subproject commit 54e622c2e6af456bfef382fae44c17682d5ac88a
|
||||
Subproject commit 3a1d76d298db023f6cf37fb08ee766f20a4e12ab
|
2
externals/toml11
vendored
2
externals/toml11
vendored
@ -1 +1 @@
|
||||
Subproject commit f925e7f287c0008813c2294798cf9ca167fd9ffd
|
||||
Subproject commit 7f6c574ff5aa1053534e7e19c0a4f22bf4c6aaca
|
2
externals/tracy
vendored
2
externals/tracy
vendored
@ -1 +1 @@
|
||||
Subproject commit b8061982cad0210b649541016c88ff5faa90733c
|
||||
Subproject commit 143a53d1985b8e52a7590a0daca30a0a7c653b42
|
2
externals/vma
vendored
2
externals/vma
vendored
@ -1 +1 @@
|
||||
Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39
|
||||
Subproject commit 5a53a198945ba8260fbc58fadb788745ce6aa263
|
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
@ -1 +1 @@
|
||||
Subproject commit d91597a82f881d473887b560a03a7edf2720b72c
|
||||
Subproject commit 6a74a7d65cafa19e38ec116651436cce6efd5b2e
|
2
externals/xbyak
vendored
2
externals/xbyak
vendored
@ -1 +1 @@
|
||||
Subproject commit d067f0d3f55696ae8bc9a25ad7012ee80f221d54
|
||||
Subproject commit 4e44f4614ddbf038f2a6296f5b906d5c72691e0f
|
2
externals/xxhash
vendored
2
externals/xxhash
vendored
@ -1 +1 @@
|
||||
Subproject commit d4ad85e4afaad5c780f54db1dc967fff5a869ffd
|
||||
Subproject commit 2bf8313b934633b2a5b7e8fd239645b85e10c852
|
2
externals/zydis
vendored
2
externals/zydis
vendored
@ -1 +1 @@
|
||||
Subproject commit 9d298eb8067ff62a237203d1e1470785033e185c
|
||||
Subproject commit bffbb610cfea643b98e87658b9058382f7522807
|
@ -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 <SDL3/SDL_audio.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include <mutex> // 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
|
@ -1,39 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#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<PortOut, Libraries::AudioOut::SCE_AUDIO_OUT_NUM_PORTS> portsOut;
|
||||
};
|
||||
|
||||
} // namespace Audio
|
@ -22,6 +22,12 @@ template <typename T>
|
||||
return static_cast<T>(value - value % size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::is_integral_v<T>
|
||||
[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
|
||||
return (value & (alignment - 1)) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::is_integral_v<T>
|
||||
[[nodiscard]] constexpr bool Is16KBAligned(T value) {
|
||||
|
@ -3,13 +3,14 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <common/version.h>
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/xchar.h> // for wstring support
|
||||
#include <toml.hpp>
|
||||
#include "common/logging/formatter.h"
|
||||
|
||||
#include "common/path_util.h"
|
||||
#include "config.h"
|
||||
#include "logging/formatter.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace toml {
|
||||
template <typename TC, typename K>
|
||||
@ -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<std::string> m_pkg_viewer;
|
||||
std::vector<std::string> m_elf_viewer;
|
||||
std::vector<std::string> 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<std::string>& pkgList) {
|
||||
m_pkg_viewer.resize(pkgList.size());
|
||||
m_pkg_viewer = pkgList;
|
||||
}
|
||||
|
||||
void setElfViewer(const std::vector<std::string>& elfList) {
|
||||
m_elf_viewer.resize(elfList.size());
|
||||
m_elf_viewer = elfList;
|
||||
}
|
||||
|
||||
void setRecentFiles(const std::vector<std::string>& 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<std::filesystem::path>& 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<std::string> getPkgViewer() {
|
||||
return m_pkg_viewer;
|
||||
}
|
||||
|
||||
std::vector<std::string> getElfViewer() {
|
||||
return m_elf_viewer;
|
||||
}
|
||||
|
||||
std::vector<std::string> 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<bool>(gpu, "nullGpu", false);
|
||||
shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", false);
|
||||
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false);
|
||||
shouldPatchShaders = toml::find_or<bool>(gpu, "patchShaders", true);
|
||||
vblankDivider = toml::find_or<int>(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<bool>(debug, "DebugDump", false);
|
||||
isShaderDebug = toml::find_or<bool>(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<int>(gui, "mw_width", 0);
|
||||
m_window_size_H = toml::find_or<int>(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<std::vector<std::string>>(gui, "installDirs", {});
|
||||
for (const auto& dir : install_dir_array) {
|
||||
addGameInstallDir(std::filesystem::path{dir});
|
||||
}
|
||||
const auto install_dir_array =
|
||||
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
|
||||
for (const auto& dir : install_dir_array) {
|
||||
addGameInstallDir(std::filesystem::path{dir});
|
||||
}
|
||||
|
||||
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
||||
@ -575,6 +618,7 @@ void load(const std::filesystem::path& path) {
|
||||
m_language = toml::find_or<int>(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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#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";
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -28,7 +28,7 @@ std::string g_game_serial;
|
||||
std::string patchFile;
|
||||
std::vector<patchInfo> 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 {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
163
src/common/slab_heap.h
Normal file
163
src/common/slab_heap.h
Normal file
@ -0,0 +1,163 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#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<Node*>(obj);
|
||||
node->next = m_head;
|
||||
m_head = node;
|
||||
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<Node*> 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<uintptr_t>(memory);
|
||||
m_end = m_start + num_obj * obj_size;
|
||||
m_peak = m_start;
|
||||
|
||||
// Free the objects.
|
||||
u8* cur = reinterpret_cast<u8*>(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<uintptr_t>(obj));
|
||||
ASSERT(contained);
|
||||
SlabHeapImpl::Free(obj);
|
||||
}
|
||||
|
||||
size_t GetObjectIndex(const void* obj) const {
|
||||
return (reinterpret_cast<uintptr_t>(obj) - m_start) / this->GetObjectSize();
|
||||
}
|
||||
|
||||
size_t GetPeakIndex() const {
|
||||
return this->GetObjectIndex(reinterpret_cast<const void*>(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 <typename T>
|
||||
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<T*>(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
|
@ -3,10 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bit>
|
||||
#include <compare>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/assert.h"
|
||||
|
53
src/common/spin_lock.cpp
Executable file
53
src/common/spin_lock.cpp
Executable file
@ -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 <intrin.h>
|
||||
#if _M_AMD64
|
||||
#define __x86_64__ 1
|
||||
#endif
|
||||
#if _M_ARM64
|
||||
#define __aarch64__ 1
|
||||
#endif
|
||||
#else
|
||||
#if __x86_64__
|
||||
#include <xmmintrin.h>
|
||||
#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
|
33
src/common/spin_lock.h
Executable file
33
src/common/spin_lock.h
Executable file
@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
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
|
7
src/common/stb.cpp
Normal file
7
src/common/stb.cpp
Normal file
@ -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"
|
6
src/common/stb.h
Normal file
6
src/common/stb.h
Normal file
@ -0,0 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stb_image.h>
|
17
src/common/support/avdec.h
Normal file
17
src/common/support/avdec.h
Normal file
@ -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 <string>
|
||||
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
|
@ -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
|
||||
|
||||
|
@ -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{};
|
||||
|
111
src/common/va_ctx.h
Normal file
111
src/common/va_ctx.h
Normal file
@ -0,0 +1,111 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#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 <class T, uint32_t Size>
|
||||
T vaArgRegSaveAreaGp(VaList* l) {
|
||||
auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->gp_offset);
|
||||
l->gp_offset += Size;
|
||||
return *addr;
|
||||
}
|
||||
template <class T, u64 Align, u64 Size>
|
||||
T vaArgOverflowArgArea(VaList* l) {
|
||||
auto ptr = ((reinterpret_cast<u64>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
|
||||
auto* addr = reinterpret_cast<T*>(ptr);
|
||||
l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
|
||||
return *addr;
|
||||
}
|
||||
|
||||
template <class T, uint32_t Size>
|
||||
T vaArgRegSaveAreaFp(VaList* l) {
|
||||
auto* addr = reinterpret_cast<T*>(static_cast<u8*>(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<int, 8>(l);
|
||||
}
|
||||
return vaArgOverflowArgArea<int, 1, 8>(l);
|
||||
}
|
||||
|
||||
inline long long vaArgLongLong(VaList* l) {
|
||||
if (l->gp_offset <= 40) {
|
||||
return vaArgRegSaveAreaGp<long long, 8>(l);
|
||||
}
|
||||
return vaArgOverflowArgArea<long long, 1, 8>(l);
|
||||
}
|
||||
inline long vaArgLong(VaList* l) {
|
||||
if (l->gp_offset <= 40) {
|
||||
return vaArgRegSaveAreaGp<long, 8>(l);
|
||||
}
|
||||
return vaArgOverflowArgArea<long, 1, 8>(l);
|
||||
}
|
||||
|
||||
inline double vaArgDouble(VaList* l) {
|
||||
if (l->fp_offset <= 160) {
|
||||
return vaArgRegSaveAreaFp<double, 16>(l);
|
||||
}
|
||||
return vaArgOverflowArgArea<double, 1, 8>(l);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* vaArgPtr(VaList* l) {
|
||||
if (l->gp_offset <= 40) {
|
||||
return vaArgRegSaveAreaGp<T*, 8>(l);
|
||||
}
|
||||
return vaArgOverflowArgArea<T*, 1, 8>(l);
|
||||
}
|
||||
|
||||
} // namespace Common
|
@ -1,13 +1,14 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <map>
|
||||
#include <boost/icl/separate_interval_set.hpp>
|
||||
#include "common/alignment.h"
|
||||
#include "common/arch.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "core/address_space.h"
|
||||
#include "core/libraries/kernel/memory_management.h"
|
||||
#include "core/libraries/kernel/memory.h"
|
||||
#include "core/memory.h"
|
||||
#include "libraries/error_codes.h"
|
||||
|
||||
@ -40,6 +41,12 @@ static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE_PRO;
|
||||
}
|
||||
}
|
||||
|
||||
struct MemoryRegion {
|
||||
VAddr base;
|
||||
size_t size;
|
||||
bool is_mapped;
|
||||
};
|
||||
|
||||
struct AddressSpace::Impl {
|
||||
Impl() : process{GetCurrentProcess()} {
|
||||
// Allocate virtual address placeholder for our address space.
|
||||
@ -75,6 +82,7 @@ struct AddressSpace::Impl {
|
||||
Common::GetLastErrorMsg());
|
||||
|
||||
// Take the reduction off of the system managed area, and leave the others unchanged.
|
||||
reduction = size_t(virtual_base - SYSTEM_MANAGED_MIN);
|
||||
system_managed_base = virtual_base;
|
||||
system_managed_size = SystemManagedSize - reduction;
|
||||
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
|
||||
@ -95,7 +103,8 @@ struct AddressSpace::Impl {
|
||||
const uintptr_t system_managed_addr = reinterpret_cast<uintptr_t>(system_managed_base);
|
||||
const uintptr_t system_reserved_addr = reinterpret_cast<uintptr_t>(system_reserved_base);
|
||||
const uintptr_t user_addr = reinterpret_cast<uintptr_t>(user_base);
|
||||
placeholders.insert({system_managed_addr, virtual_size - reduction});
|
||||
regions.emplace(system_managed_addr,
|
||||
MemoryRegion{system_managed_addr, virtual_size - reduction, false});
|
||||
|
||||
// Allocate backing file that represents the total physical memory.
|
||||
backing_handle =
|
||||
@ -132,42 +141,15 @@ struct AddressSpace::Impl {
|
||||
}
|
||||
|
||||
void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, ULONG prot, uintptr_t fd = 0) {
|
||||
const size_t aligned_size = Common::AlignUp(size, 16_KB);
|
||||
const auto it = placeholders.find(virtual_addr);
|
||||
ASSERT_MSG(it != placeholders.end(), "Cannot map already mapped region");
|
||||
ASSERT_MSG(virtual_addr >= it->lower() && virtual_addr + aligned_size <= it->upper(),
|
||||
"Map range must be fully contained in a placeholder");
|
||||
|
||||
// Windows only allows splitting a placeholder into two.
|
||||
// This means that if the map range is fully
|
||||
// contained the the placeholder we need to perform two split operations,
|
||||
// one at the start and at the end.
|
||||
const VAddr placeholder_start = it->lower();
|
||||
const VAddr placeholder_end = it->upper();
|
||||
const VAddr virtual_end = virtual_addr + aligned_size;
|
||||
|
||||
// If the placeholder doesn't exactly start at virtual_addr, split it at the start.
|
||||
if (placeholder_start != virtual_addr) {
|
||||
VirtualFreeEx(process, reinterpret_cast<LPVOID>(placeholder_start),
|
||||
virtual_addr - placeholder_start, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
|
||||
}
|
||||
|
||||
// If the placeholder doesn't exactly end at virtual_end, split it at the end.
|
||||
if (placeholder_end != virtual_end) {
|
||||
VirtualFreeEx(process, reinterpret_cast<LPVOID>(virtual_end),
|
||||
placeholder_end - virtual_end, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
|
||||
}
|
||||
|
||||
// Remove the placeholder.
|
||||
placeholders.erase({virtual_addr, virtual_end});
|
||||
|
||||
// Perform the map.
|
||||
// Before mapping we must carve a placeholder with the exact properties of our mapping.
|
||||
auto* region = EnsureSplitRegionForMapping(virtual_addr, size);
|
||||
region->is_mapped = true;
|
||||
void* ptr = nullptr;
|
||||
if (phys_addr != -1) {
|
||||
HANDLE backing = fd ? reinterpret_cast<HANDLE>(fd) : backing_handle;
|
||||
if (fd && prot == PAGE_READONLY) {
|
||||
DWORD resultvar;
|
||||
ptr = VirtualAlloc2(process, reinterpret_cast<PVOID>(virtual_addr), aligned_size,
|
||||
ptr = VirtualAlloc2(process, reinterpret_cast<PVOID>(virtual_addr), size,
|
||||
MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER,
|
||||
PAGE_READWRITE, nullptr, 0);
|
||||
bool ret = ReadFile(backing, ptr, size, &resultvar, NULL);
|
||||
@ -176,12 +158,11 @@ struct AddressSpace::Impl {
|
||||
ASSERT_MSG(ret, "VirtualProtect failed. {}", Common::GetLastErrorMsg());
|
||||
} else {
|
||||
ptr = MapViewOfFile3(backing, process, reinterpret_cast<PVOID>(virtual_addr),
|
||||
phys_addr, aligned_size, MEM_REPLACE_PLACEHOLDER, prot,
|
||||
nullptr, 0);
|
||||
phys_addr, size, MEM_REPLACE_PLACEHOLDER, prot, nullptr, 0);
|
||||
}
|
||||
} else {
|
||||
ptr =
|
||||
VirtualAlloc2(process, reinterpret_cast<PVOID>(virtual_addr), aligned_size,
|
||||
VirtualAlloc2(process, reinterpret_cast<PVOID>(virtual_addr), size,
|
||||
MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER, prot, nullptr, 0);
|
||||
}
|
||||
ASSERT_MSG(ptr, "{}", Common::GetLastErrorMsg());
|
||||
@ -202,33 +183,118 @@ struct AddressSpace::Impl {
|
||||
|
||||
// The unmap call will create a new placeholder region. We need to see if we can coalesce it
|
||||
// with neighbors.
|
||||
VAddr placeholder_start = virtual_addr;
|
||||
VAddr placeholder_end = virtual_addr + size;
|
||||
JoinRegionsAfterUnmap(virtual_addr, size);
|
||||
}
|
||||
|
||||
// The following code is inspired from Dolphin's MemArena
|
||||
// https://github.com/dolphin-emu/dolphin/blob/deee3ee4/Source/Core/Common/MemArenaWin.cpp#L212
|
||||
MemoryRegion* EnsureSplitRegionForMapping(VAddr address, size_t size) {
|
||||
// Find closest region that is <= the given address by using upper bound and decrementing
|
||||
auto it = regions.upper_bound(address);
|
||||
ASSERT_MSG(it != regions.begin(), "Invalid address {:#x}", address);
|
||||
--it;
|
||||
ASSERT_MSG(!it->second.is_mapped,
|
||||
"Attempt to map {:#x} with size {:#x} which overlaps with {:#x} mapping",
|
||||
address, size, it->second.base);
|
||||
auto& [base, region] = *it;
|
||||
|
||||
const VAddr mapping_address = region.base;
|
||||
const size_t region_size = region.size;
|
||||
if (mapping_address == address) {
|
||||
// If this region is already split up correctly we don't have to do anything
|
||||
if (region_size == size) {
|
||||
return ®ion;
|
||||
}
|
||||
|
||||
ASSERT_MSG(region_size >= size,
|
||||
"Region with address {:#x} and size {:#x} can't fit {:#x}", mapping_address,
|
||||
region_size, size);
|
||||
|
||||
// Split the placeholder.
|
||||
if (!VirtualFreeEx(process, LPVOID(address), size,
|
||||
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)) {
|
||||
UNREACHABLE_MSG("Region splitting failed: {}", Common::GetLastErrorMsg());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Update tracked mappings and return the first of the two
|
||||
region.size = size;
|
||||
const VAddr new_mapping_start = address + size;
|
||||
regions.emplace_hint(std::next(it), new_mapping_start,
|
||||
MemoryRegion(new_mapping_start, region_size - size, false));
|
||||
return ®ion;
|
||||
}
|
||||
|
||||
ASSERT(mapping_address < address);
|
||||
|
||||
// Is there enough space to map this?
|
||||
const size_t offset_in_region = address - mapping_address;
|
||||
const size_t minimum_size = size + offset_in_region;
|
||||
ASSERT(region_size >= minimum_size);
|
||||
|
||||
// Split the placeholder.
|
||||
if (!VirtualFreeEx(process, LPVOID(address), size,
|
||||
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)) {
|
||||
UNREACHABLE_MSG("Region splitting failed: {}", Common::GetLastErrorMsg());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do we now have two regions or three regions?
|
||||
if (region_size == minimum_size) {
|
||||
// Split into two; update tracked mappings and return the second one
|
||||
region.size = offset_in_region;
|
||||
it = regions.emplace_hint(std::next(it), address, MemoryRegion(address, size, false));
|
||||
return &it->second;
|
||||
} else {
|
||||
// Split into three; update tracked mappings and return the middle one
|
||||
region.size = offset_in_region;
|
||||
const VAddr middle_mapping_start = address;
|
||||
const size_t middle_mapping_size = size;
|
||||
const VAddr after_mapping_start = address + size;
|
||||
const size_t after_mapping_size = region_size - minimum_size;
|
||||
it = regions.emplace_hint(std::next(it), after_mapping_start,
|
||||
MemoryRegion(after_mapping_start, after_mapping_size, false));
|
||||
it = regions.emplace_hint(
|
||||
it, middle_mapping_start,
|
||||
MemoryRegion(middle_mapping_start, middle_mapping_size, false));
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void JoinRegionsAfterUnmap(VAddr address, size_t size) {
|
||||
// There should be a mapping that matches the request exactly, find it
|
||||
auto it = regions.find(address);
|
||||
ASSERT_MSG(it != regions.end() && it->second.size == size,
|
||||
"Invalid address/size given to unmap.");
|
||||
auto& [base, region] = *it;
|
||||
region.is_mapped = false;
|
||||
|
||||
// Check if a placeholder exists right before us.
|
||||
const auto left_it = placeholders.find(virtual_addr - 1);
|
||||
if (left_it != placeholders.end()) {
|
||||
ASSERT_MSG(left_it->upper() == virtual_addr,
|
||||
"Left placeholder does not end at virtual_addr!");
|
||||
placeholder_start = left_it->lower();
|
||||
VirtualFreeEx(process, reinterpret_cast<LPVOID>(placeholder_start),
|
||||
placeholder_end - placeholder_start,
|
||||
MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
|
||||
auto it_prev = it != regions.begin() ? std::prev(it) : regions.end();
|
||||
if (it_prev != regions.end() && !it_prev->second.is_mapped) {
|
||||
const size_t total_size = it_prev->second.size + size;
|
||||
if (!VirtualFreeEx(process, LPVOID(it_prev->first), total_size,
|
||||
MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) {
|
||||
UNREACHABLE_MSG("Region coalescing failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
|
||||
it_prev->second.size = total_size;
|
||||
regions.erase(it);
|
||||
it = it_prev;
|
||||
}
|
||||
|
||||
// Check if a placeholder exists right after us.
|
||||
const auto right_it = placeholders.find(placeholder_end + 1);
|
||||
if (right_it != placeholders.end()) {
|
||||
ASSERT_MSG(right_it->lower() == placeholder_end,
|
||||
"Right placeholder does not start at virtual_end!");
|
||||
placeholder_end = right_it->upper();
|
||||
VirtualFreeEx(process, reinterpret_cast<LPVOID>(placeholder_start),
|
||||
placeholder_end - placeholder_start,
|
||||
MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS);
|
||||
}
|
||||
auto it_next = std::next(it);
|
||||
if (it_next != regions.end() && !it_next->second.is_mapped) {
|
||||
const size_t total_size = it->second.size + it_next->second.size;
|
||||
if (!VirtualFreeEx(process, LPVOID(it->first), total_size,
|
||||
MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) {
|
||||
UNREACHABLE_MSG("Region coalescing failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
|
||||
// Insert the new placeholder.
|
||||
placeholders.insert({placeholder_start, placeholder_end});
|
||||
it->second.size = total_size;
|
||||
regions.erase(it_next);
|
||||
}
|
||||
}
|
||||
|
||||
void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) {
|
||||
@ -251,18 +317,22 @@ struct AddressSpace::Impl {
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD old_flags{};
|
||||
bool success =
|
||||
VirtualProtect(reinterpret_cast<void*>(virtual_addr), size, new_flags, &old_flags);
|
||||
|
||||
if (!success) {
|
||||
LOG_ERROR(Common_Memory,
|
||||
"Failed to change virtual memory protection for address {:#x}, size {}",
|
||||
virtual_addr, size);
|
||||
const VAddr virtual_end = virtual_addr + size;
|
||||
auto it = --regions.upper_bound(virtual_addr);
|
||||
for (; it->first < virtual_end; it++) {
|
||||
if (!it->second.is_mapped) {
|
||||
continue;
|
||||
}
|
||||
const auto& region = it->second;
|
||||
const size_t range_addr = std::max(region.base, virtual_addr);
|
||||
const size_t range_size = std::min(region.base + region.size, virtual_end) - range_addr;
|
||||
DWORD old_flags{};
|
||||
if (!VirtualProtectEx(process, LPVOID(range_addr), range_size, new_flags, &old_flags)) {
|
||||
UNREACHABLE_MSG(
|
||||
"Failed to change virtual memory protection for address {:#x}, size {}",
|
||||
range_addr, range_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Use assert to ensure success in debug builds
|
||||
DEBUG_ASSERT(success && "Failed to change virtual memory protection");
|
||||
}
|
||||
|
||||
HANDLE process{};
|
||||
@ -275,7 +345,7 @@ struct AddressSpace::Impl {
|
||||
size_t system_reserved_size{};
|
||||
u8* user_base{};
|
||||
size_t user_size{};
|
||||
boost::icl::separate_interval_set<uintptr_t> placeholders;
|
||||
std::map<VAddr, MemoryRegion> regions;
|
||||
};
|
||||
#else
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
/// Initializes a stack for the current thread for use by patch implementations.
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "common/singleton.h"
|
||||
#include "debug_state.h"
|
||||
#include "devtools/widget/common.h"
|
||||
#include "libraries/kernel/time_management.h"
|
||||
#include "libraries/kernel/time.h"
|
||||
#include "libraries/system/msgdialog.h"
|
||||
#include "video_core/amdgpu/pm4_cmds.h"
|
||||
|
||||
@ -157,7 +157,7 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
if (is_compute) {
|
||||
dump.is_compute = true;
|
||||
const auto& cs = dump.regs.cs_program;
|
||||
dump.cs_data = ComputerShaderDump{
|
||||
dump.cs_data = PipelineComputerProgramDump{
|
||||
.cs_program = cs,
|
||||
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
||||
};
|
||||
@ -167,7 +167,7 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
auto stage = regs.ProgramForStage(i);
|
||||
if (stage->address_lo != 0) {
|
||||
auto code = stage->Code();
|
||||
dump.stages[i] = ShaderDump{
|
||||
dump.stages[i] = PipelineShaderProgramDump{
|
||||
.user_data = *stage,
|
||||
.code = std::vector<u32>{code.begin(), code.end()},
|
||||
};
|
||||
@ -176,3 +176,10 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugStateImpl::CollectShader(const std::string& name, std::span<const u32> spv,
|
||||
std::span<const u32> raw_code) {
|
||||
shader_dump_list.emplace_back(name, std::vector<u32>{spv.begin(), spv.end()},
|
||||
std::vector<u32>{raw_code.begin(), raw_code.end()});
|
||||
std::ranges::sort(shader_dump_list, {}, &ShaderDump::name);
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ namespace Core::Devtools {
|
||||
class Layer;
|
||||
namespace Widget {
|
||||
class FrameGraph;
|
||||
}
|
||||
class ShaderList;
|
||||
} // namespace Widget
|
||||
} // namespace Core::Devtools
|
||||
|
||||
namespace DebugStateType {
|
||||
@ -49,12 +50,12 @@ struct QueueDump {
|
||||
uintptr_t base_addr;
|
||||
};
|
||||
|
||||
struct ShaderDump {
|
||||
struct PipelineShaderProgramDump {
|
||||
Vulkan::Liverpool::ShaderProgram user_data{};
|
||||
std::vector<u32> code{};
|
||||
};
|
||||
|
||||
struct ComputerShaderDump {
|
||||
struct PipelineComputerProgramDump {
|
||||
Vulkan::Liverpool::ComputeProgram cs_program{};
|
||||
std::vector<u32> code{};
|
||||
};
|
||||
@ -63,8 +64,8 @@ struct RegDump {
|
||||
bool is_compute{false};
|
||||
static constexpr size_t MaxShaderStages = 5;
|
||||
Vulkan::Liverpool::Regs regs{};
|
||||
std::array<ShaderDump, MaxShaderStages> stages{};
|
||||
ComputerShaderDump cs_data{};
|
||||
std::array<PipelineShaderProgramDump, MaxShaderStages> stages{};
|
||||
PipelineComputerProgramDump cs_data{};
|
||||
};
|
||||
|
||||
struct FrameDump {
|
||||
@ -73,9 +74,41 @@ struct FrameDump {
|
||||
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
||||
};
|
||||
|
||||
struct ShaderDump {
|
||||
std::string name;
|
||||
std::vector<u32> spv;
|
||||
std::vector<u32> raw_code;
|
||||
|
||||
std::string cache_spv_disasm{};
|
||||
std::string cache_raw_disasm{};
|
||||
|
||||
ShaderDump(std::string name, std::vector<u32> spv, std::vector<u32> raw_code)
|
||||
: name(std::move(name)), spv(std::move(spv)), raw_code(std::move(raw_code)) {}
|
||||
|
||||
ShaderDump(const ShaderDump& other) = delete;
|
||||
ShaderDump(ShaderDump&& other) noexcept
|
||||
: name{std::move(other.name)}, spv{std::move(other.spv)},
|
||||
raw_code{std::move(other.raw_code)}, cache_spv_disasm{std::move(other.cache_spv_disasm)},
|
||||
cache_raw_disasm{std::move(other.cache_raw_disasm)} {}
|
||||
ShaderDump& operator=(const ShaderDump& other) = delete;
|
||||
ShaderDump& operator=(ShaderDump&& other) noexcept {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
name = std::move(other.name);
|
||||
spv = std::move(other.spv);
|
||||
raw_code = std::move(other.raw_code);
|
||||
cache_spv_disasm = std::move(other.cache_spv_disasm);
|
||||
cache_raw_disasm = std::move(other.cache_raw_disasm);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class DebugStateImpl {
|
||||
friend class Core::Devtools::Layer;
|
||||
friend class Core::Devtools::Widget::FrameGraph;
|
||||
friend class Core::Devtools::Widget::ShaderList;
|
||||
|
||||
std::queue<std::string> debug_message_popup;
|
||||
|
||||
std::mutex guest_threads_mutex{};
|
||||
std::vector<ThreadID> guest_threads{};
|
||||
@ -94,7 +127,7 @@ class DebugStateImpl {
|
||||
std::shared_mutex frame_dump_list_mutex;
|
||||
std::vector<FrameDump> frame_dump_list{};
|
||||
|
||||
std::queue<std::string> debug_message_popup;
|
||||
std::vector<ShaderDump> shader_dump_list{};
|
||||
|
||||
public:
|
||||
void ShowDebugMessage(std::string message) {
|
||||
@ -152,6 +185,9 @@ public:
|
||||
|
||||
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
|
||||
|
||||
void CollectShader(const std::string& name, std::span<const u32> spv,
|
||||
std::span<const u32> raw_code);
|
||||
};
|
||||
} // namespace DebugStateType
|
||||
|
||||
|
12
src/core/devices/base_device.cpp
Normal file
12
src/core/devices/base_device.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
BaseDevice::BaseDevice() = default;
|
||||
|
||||
BaseDevice::~BaseDevice() = default;
|
||||
|
||||
} // namespace Core::Devices
|
72
src/core/devices/base_device.h
Normal file
72
src/core/devices/base_device.h
Normal file
@ -0,0 +1,72 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/libraries/kernel/orbis_error.h>
|
||||
#include "common/types.h"
|
||||
#include "common/va_ctx.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
struct OrbisKernelStat;
|
||||
struct SceKernelIovec;
|
||||
} // namespace Libraries::Kernel
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class BaseDevice {
|
||||
public:
|
||||
explicit BaseDevice();
|
||||
|
||||
virtual ~BaseDevice() = 0;
|
||||
|
||||
virtual int ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
return ORBIS_KERNEL_ERROR_ENOTTY;
|
||||
}
|
||||
|
||||
virtual s64 write(const void* buf, size_t nbytes) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 lseek(s64 offset, int whence) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 read(void* buf, size_t nbytes) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual int fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s32 fsync() {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual int ftruncate(s64 length) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual int getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
67
src/core/devices/ioccom.h
Normal file
67
src/core/devices/ioccom.h
Normal file
@ -0,0 +1,67 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ioccom.h 8.2 (Berkeley) 3/28/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define IOCPARM_SHIFT 13 /* number of bits for ioctl size */
|
||||
#define IOCPARM_MASK ((1 << IOCPARM_SHIFT) - 1) /* parameter length mask */
|
||||
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
||||
#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16))
|
||||
#define IOCGROUP(x) (((x) >> 8) & 0xff)
|
||||
|
||||
#define IOCPARM_MAX (1 << IOCPARM_SHIFT) /* max size of ioctl */
|
||||
#define IOC_VOID 0x20000000 /* no parameters */
|
||||
#define IOC_OUT 0x40000000 /* copy out parameters */
|
||||
#define IOC_IN 0x80000000 /* copy in parameters */
|
||||
#define IOC_INOUT (IOC_IN | IOC_OUT)
|
||||
#define IOC_DIRMASK (IOC_VOID | IOC_OUT | IOC_IN)
|
||||
|
||||
#define _IOC(inout, group, num, len) \
|
||||
((unsigned long)((inout) | (((len) & IOCPARM_MASK) << 16) | ((group) << 8) | (num)))
|
||||
#define _IO(g, n) _IOC(IOC_VOID, (g), (n), 0)
|
||||
#define _IOWINT(g, n) _IOC(IOC_VOID, (g), (n), sizeof(int))
|
||||
#define _IOR(g, n, t) _IOC(IOC_OUT, (g), (n), sizeof(t))
|
||||
#define _IOW(g, n, t) _IOC(IOC_IN, (g), (n), sizeof(t))
|
||||
/* this should be _IORW, but stdio got there first */
|
||||
#define _IOWR(g, n, t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
|
||||
|
||||
/*
|
||||
# Simple parse of ioctl cmd
|
||||
def parse(v):
|
||||
print('inout', (v >> 24 & 0xFF))
|
||||
print('len', hex(v >> 16 & 0xFF))
|
||||
print('group', chr(v >> 8 & 0xFF))
|
||||
print('num', hex(v & 0xFF))
|
||||
*/
|
65
src/core/devices/logger.cpp
Normal file
65
src/core/devices/logger.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/kernel/file_system.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
Logger::Logger(std::string prefix, bool is_err) : prefix(std::move(prefix)), is_err(is_err) {}
|
||||
|
||||
Logger::~Logger() = default;
|
||||
|
||||
s64 Logger::write(const void* buf, size_t nbytes) {
|
||||
log(static_cast<const char*>(buf), nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
size_t Logger::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
|
||||
}
|
||||
return iovcnt;
|
||||
}
|
||||
|
||||
s64 Logger::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
log(static_cast<const char*>(buf), nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
s32 Logger::fsync() {
|
||||
log_flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Logger::log(const char* buf, size_t nbytes) {
|
||||
std::scoped_lock lock{mtx};
|
||||
const char* end = buf + nbytes;
|
||||
for (const char* it = buf; it < end; ++it) {
|
||||
char c = *it;
|
||||
if (c == '\r') {
|
||||
continue;
|
||||
}
|
||||
if (c == '\n') {
|
||||
log_flush();
|
||||
continue;
|
||||
}
|
||||
buffer.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::log_flush() {
|
||||
std::scoped_lock lock{mtx};
|
||||
if (buffer.empty()) {
|
||||
return;
|
||||
}
|
||||
if (is_err) {
|
||||
LOG_ERROR(Tty, "[{}] {}", prefix, std::string_view{buffer});
|
||||
} else {
|
||||
LOG_INFO(Tty, "[{}] {}", prefix, std::string_view{buffer});
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
} // namespace Core::Devices
|
37
src/core/devices/logger.h
Normal file
37
src/core/devices/logger.h
Normal file
@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base_device.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class Logger final : BaseDevice {
|
||||
std::string prefix;
|
||||
bool is_err;
|
||||
|
||||
std::recursive_mutex mtx;
|
||||
std::vector<char> buffer;
|
||||
|
||||
public:
|
||||
explicit Logger(std::string prefix, bool is_err);
|
||||
|
||||
~Logger() override;
|
||||
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
|
||||
s32 fsync() override;
|
||||
|
||||
private:
|
||||
void log(const char* buf, size_t nbytes);
|
||||
void log_flush();
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
55
src/core/devices/nop_device.h
Normal file
55
src/core/devices/nop_device.h
Normal file
@ -0,0 +1,55 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class NopDevice final : BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
explicit NopDevice(u32 handle) : handle(handle) {}
|
||||
|
||||
~NopDevice() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override {
|
||||
return 0;
|
||||
}
|
||||
s64 write(const void* buf, size_t nbytes) override {
|
||||
return 0;
|
||||
}
|
||||
size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
|
||||
return 0;
|
||||
}
|
||||
size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override {
|
||||
return 0;
|
||||
}
|
||||
s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override {
|
||||
return 0;
|
||||
}
|
||||
s64 lseek(s64 offset, int whence) override {
|
||||
return 0;
|
||||
}
|
||||
s64 read(void* buf, size_t nbytes) override {
|
||||
return 0;
|
||||
}
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
|
||||
return 0;
|
||||
}
|
||||
s32 fsync() override {
|
||||
return 0;
|
||||
}
|
||||
int ftruncate(s64 length) override {
|
||||
return 0;
|
||||
}
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override {
|
||||
return 0;
|
||||
}
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
@ -289,6 +289,16 @@ const char* GetContextRegName(u32 reg_offset) {
|
||||
return "mmSPI_PS_INPUT_CNTL_2";
|
||||
case mmSPI_PS_INPUT_CNTL_3:
|
||||
return "mmSPI_PS_INPUT_CNTL_3";
|
||||
case mmPA_SU_POLY_OFFSET_FRONT_SCALE:
|
||||
return "mmPA_SU_POLY_OFFSET_FRONT_SCALE";
|
||||
case mmPA_SU_POLY_OFFSET_FRONT_OFFSET:
|
||||
return "mmPA_SU_POLY_OFFSET_FRONT_OFFSET";
|
||||
case mmPA_SU_POLY_OFFSET_BACK_SCALE:
|
||||
return "mmPA_SU_POLY_OFFSET_BACK_SCALE";
|
||||
case mmPA_SU_POLY_OFFSET_BACK_OFFSET:
|
||||
return "mmPA_SU_POLY_OFFSET_BACK_OFFSET";
|
||||
case mmPA_SU_POLY_OFFSET_CLAMP:
|
||||
return "mmPA_SU_POLY_OFFSET_CLAMP";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "layer.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common/config.h"
|
||||
@ -9,10 +11,14 @@
|
||||
#include "core/debug_state.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "layer.h"
|
||||
#include "options.h"
|
||||
#include "video_core/renderer_vulkan/vk_presenter.h"
|
||||
#include "widget/frame_dump.h"
|
||||
#include "widget/frame_graph.h"
|
||||
#include "widget/memory_map.h"
|
||||
#include "widget/shader_list.h"
|
||||
|
||||
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
||||
|
||||
using namespace ImGui;
|
||||
using namespace Core::Devtools;
|
||||
@ -32,6 +38,9 @@ static float debug_popup_timing = 3.0f;
|
||||
|
||||
static bool just_opened_options = false;
|
||||
|
||||
static Widget::MemoryMapViewer memory_map;
|
||||
static Widget::ShaderList shader_list;
|
||||
|
||||
// clang-format off
|
||||
static std::string help_text =
|
||||
#include "help.txt"
|
||||
@ -60,6 +69,7 @@ void L::DrawMenuBar() {
|
||||
}
|
||||
if (BeginMenu("GPU Tools")) {
|
||||
MenuItem("Show frame info", nullptr, &frame_graph.is_open);
|
||||
MenuItem("Show loaded shaders", nullptr, &shader_list.open);
|
||||
if (BeginMenu("Dump frames")) {
|
||||
SliderInt("Count", &dump_frame_count, 1, 5);
|
||||
if (MenuItem("Dump", "Ctrl+Alt+F9", nullptr, !DebugState.DumpingCurrentFrame())) {
|
||||
@ -71,6 +81,19 @@ void L::DrawMenuBar() {
|
||||
open_popup_help = MenuItem("Help & Tips");
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (BeginMenu("Display")) {
|
||||
if (BeginMenu("Brightness")) {
|
||||
SliderFloat("Gamma", &presenter->GetGammaRef(), 0.1f, 2.0f);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (BeginMenu("Debug")) {
|
||||
if (MenuItem("Memory map")) {
|
||||
memory_map.open = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
EndMainMenuBar();
|
||||
}
|
||||
|
||||
@ -165,19 +188,29 @@ void L::DrawAdvanced() {
|
||||
bool close_popup_options = true;
|
||||
if (BeginPopupModal("GPU Tools Options", &close_popup_options,
|
||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) {
|
||||
static char disassembly_cli[512];
|
||||
static char disassembler_cli_isa[512];
|
||||
static char disassembler_cli_spv[512];
|
||||
static bool frame_dump_render_on_collapse;
|
||||
|
||||
if (just_opened_options) {
|
||||
just_opened_options = false;
|
||||
auto s = Options.disassembly_cli.copy(disassembly_cli, sizeof(disassembly_cli) - 1);
|
||||
disassembly_cli[s] = '\0';
|
||||
auto s = Options.disassembler_cli_isa.copy(disassembler_cli_isa,
|
||||
sizeof(disassembler_cli_isa) - 1);
|
||||
disassembler_cli_isa[s] = '\0';
|
||||
s = Options.disassembler_cli_spv.copy(disassembler_cli_spv,
|
||||
sizeof(disassembler_cli_spv) - 1);
|
||||
disassembler_cli_spv[s] = '\0';
|
||||
frame_dump_render_on_collapse = Options.frame_dump_render_on_collapse;
|
||||
}
|
||||
|
||||
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
|
||||
InputText("Shader isa disassembler: ", disassembler_cli_isa, sizeof(disassembler_cli_isa));
|
||||
if (IsItemHovered()) {
|
||||
SetTooltip(R"(Command to disassemble shaders. Example "dis.exe" --raw "{src}")");
|
||||
SetTooltip(R"(Command to disassemble shaders. Example: dis.exe --raw "{src}")");
|
||||
}
|
||||
InputText("Shader SPIRV disassembler: ", disassembler_cli_spv,
|
||||
sizeof(disassembler_cli_spv));
|
||||
if (IsItemHovered()) {
|
||||
SetTooltip(R"(Command to disassemble shaders. Example: spirv-cross -V "{src}")");
|
||||
}
|
||||
Checkbox("Show frame dump popups even when collapsed", &frame_dump_render_on_collapse);
|
||||
if (IsItemHovered()) {
|
||||
@ -186,7 +219,8 @@ void L::DrawAdvanced() {
|
||||
}
|
||||
|
||||
if (Button("Save")) {
|
||||
Options.disassembly_cli = disassembly_cli;
|
||||
Options.disassembler_cli_isa = disassembler_cli_isa;
|
||||
Options.disassembler_cli_spv = disassembler_cli_spv;
|
||||
Options.frame_dump_render_on_collapse = frame_dump_render_on_collapse;
|
||||
SaveIniSettingsToDisk(io.IniFilename);
|
||||
CloseCurrentPopup();
|
||||
@ -209,6 +243,13 @@ void L::DrawAdvanced() {
|
||||
|
||||
EndPopup();
|
||||
}
|
||||
|
||||
if (memory_map.open) {
|
||||
memory_map.Draw();
|
||||
}
|
||||
if (shader_list.open) {
|
||||
shader_list.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
void L::DrawSimple() {
|
||||
|
@ -12,8 +12,12 @@ TOptions Options;
|
||||
void LoadOptionsConfig(const char* line) {
|
||||
char str[512];
|
||||
int i;
|
||||
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
|
||||
Options.disassembly_cli = str;
|
||||
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
|
||||
Options.disassembler_cli_isa = str;
|
||||
return;
|
||||
}
|
||||
if (sscanf(line, "disassembler_cli_spv=%511[^\n]", str) == 1) {
|
||||
Options.disassembler_cli_spv = str;
|
||||
return;
|
||||
}
|
||||
if (sscanf(line, "frame_dump_render_on_collapse=%d", &i) == 1) {
|
||||
@ -23,7 +27,8 @@ void LoadOptionsConfig(const char* line) {
|
||||
}
|
||||
|
||||
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
||||
buf->appendf("disassembly_cli=%s\n", Options.disassembly_cli.c_str());
|
||||
buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str());
|
||||
buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str());
|
||||
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,8 @@ struct ImGuiTextBuffer;
|
||||
namespace Core::Devtools {
|
||||
|
||||
struct TOptions {
|
||||
std::string disassembly_cli{};
|
||||
std::string disassembler_cli_isa{"clrxdisasm --raw \"{src}\""};
|
||||
std::string disassembler_cli_spv{"spirv-cross -V \"{src}\""};
|
||||
bool frame_dump_render_on_collapse{false};
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
// Credits to https://github.com/psucien/tlg-emu-tools/
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
#include <gcn/si_ci_vi_merged_offset.h>
|
||||
#include <imgui.h>
|
||||
@ -1224,12 +1225,12 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||
}
|
||||
|
||||
Text("queue : %s", queue_name);
|
||||
Text("base addr: %08llX", cmdb_addr);
|
||||
Text("base addr: %08" PRIXPTR, cmdb_addr);
|
||||
SameLine();
|
||||
if (SmallButton("Memory >")) {
|
||||
cmdb_view.Open ^= true;
|
||||
}
|
||||
Text("size : %04llX", cmdb_size);
|
||||
Text("size : %04zX", cmdb_size);
|
||||
Separator();
|
||||
|
||||
{
|
||||
@ -1292,12 +1293,12 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||
if (batch.type == static_cast<AmdGpu::PM4ItOpcode>(0xFF)) {
|
||||
ignore_header = true;
|
||||
} else if (!batch.marker.empty()) {
|
||||
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s | %s",
|
||||
snprintf(batch_hdr, sizeof(batch_hdr), "%08" PRIXPTR ": batch-%03d %s | %s",
|
||||
cmdb_addr + batch.start_addr, batch.id,
|
||||
Gcn::GetOpCodeName(static_cast<u32>(batch.type)),
|
||||
batch.marker.c_str());
|
||||
} else {
|
||||
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s",
|
||||
snprintf(batch_hdr, sizeof(batch_hdr), "%08" PRIXPTR ": batch-%03d %s",
|
||||
cmdb_addr + batch.start_addr, batch.id,
|
||||
Gcn::GetOpCodeName(static_cast<u32>(batch.type)));
|
||||
}
|
||||
@ -1305,7 +1306,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||
if (batch.id == batch_bp) { // highlight batch at breakpoint
|
||||
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
||||
}
|
||||
if (batch.id == highlight_batch) {
|
||||
if (batch.id == highlight_batch && !group_batches) {
|
||||
PushStyleColor(ImGuiCol_Text, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||
}
|
||||
|
||||
@ -1348,7 +1349,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||
}
|
||||
|
||||
if (show_batch_content) {
|
||||
auto processed_size = 0ull;
|
||||
size_t processed_size = 0;
|
||||
auto bb = ctx.LastItemData.Rect;
|
||||
if (group_batches && !ignore_header) {
|
||||
Indent();
|
||||
@ -1364,9 +1365,9 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||
op = pm4_t3->opcode;
|
||||
|
||||
char header_name[128];
|
||||
sprintf(header_name, "%08llX: %s",
|
||||
cmdb_addr + batch.start_addr + processed_size,
|
||||
Gcn::GetOpCodeName((u32)op));
|
||||
snprintf(header_name, sizeof(header_name), "%08" PRIXPTR ": %s",
|
||||
cmdb_addr + batch.start_addr + processed_size,
|
||||
Gcn::GetOpCodeName(static_cast<u32>(op)));
|
||||
|
||||
bool open_pm4 = TreeNode(header_name);
|
||||
if (!group_batches) {
|
||||
@ -1458,7 +1459,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||
}
|
||||
}
|
||||
|
||||
if (batch.id == highlight_batch) {
|
||||
if (batch.id == highlight_batch && !group_batches) {
|
||||
PopStyleColor();
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/types.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define popen _popen
|
||||
#define pclose _pclose
|
||||
#endif
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
/*
|
||||
* Generic PM4 header
|
||||
@ -106,4 +114,53 @@ static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
inline std::optional<std::string> exec_cli(const char* cli) {
|
||||
std::array<char, 64> buffer{};
|
||||
std::string output;
|
||||
const auto f = popen(cli, "r");
|
||||
if (!f) {
|
||||
pclose(f);
|
||||
return {};
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), f)) {
|
||||
output += buffer.data();
|
||||
}
|
||||
pclose(f);
|
||||
return output;
|
||||
}
|
||||
|
||||
inline std::string RunDisassembler(const std::string& disassembler_cli,
|
||||
const std::vector<u32>& shader_code) {
|
||||
std::string shader_dis;
|
||||
|
||||
if (disassembler_cli.empty()) {
|
||||
shader_dis = "No disassembler set";
|
||||
} else {
|
||||
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
|
||||
|
||||
constexpr std::string_view src_arg = "{src}";
|
||||
std::string cli = disassembler_cli;
|
||||
const auto pos = cli.find(src_arg);
|
||||
if (pos == std::string::npos) {
|
||||
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument\n" +
|
||||
disassembler_cli);
|
||||
} else {
|
||||
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||
file.Write(shader_code);
|
||||
file.Close();
|
||||
|
||||
auto result = exec_cli(cli.c_str());
|
||||
shader_dis = result.value_or("Could not disassemble shader");
|
||||
if (shader_dis.empty()) {
|
||||
shader_dis = "Disassembly empty or failed";
|
||||
}
|
||||
|
||||
std::filesystem::remove(bin_path);
|
||||
}
|
||||
}
|
||||
|
||||
return shader_dis;
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -4,7 +4,7 @@
|
||||
#include <cstdio>
|
||||
#include <fmt/chrono.h>
|
||||
#include <imgui.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/io_file.h"
|
||||
#include "core/devtools/options.h"
|
||||
|
@ -458,7 +458,7 @@ struct MemoryEditor {
|
||||
data_write = data_next = true;
|
||||
if (data_editing_addr_next != (size_t)-1)
|
||||
data_write = data_next = false;
|
||||
unsigned int data_input_value = 0;
|
||||
u32 data_input_value = 0;
|
||||
if (!ReadOnly && data_write &&
|
||||
sscanf(DataInputBuf, "%X", &data_input_value) == 1) {
|
||||
if (WriteFn)
|
||||
@ -929,7 +929,7 @@ struct MemoryEditor {
|
||||
default:
|
||||
case ImGuiDataType_COUNT:
|
||||
break;
|
||||
} // Switch
|
||||
} // Switch
|
||||
IM_ASSERT(0); // Shouldn't reach
|
||||
}
|
||||
};
|
||||
|
135
src/core/devtools/widget/memory_map.cpp
Normal file
135
src/core/devtools/widget/memory_map.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cinttypes>
|
||||
#include <imgui.h>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "core/debug_state.h"
|
||||
#include "core/memory.h"
|
||||
#include "memory_map.h"
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
bool MemoryMapViewer::Iterator::DrawLine() {
|
||||
if (is_vma) {
|
||||
if (vma.it == vma.end) {
|
||||
return false;
|
||||
}
|
||||
auto m = vma.it->second;
|
||||
if (m.type == VMAType::Free) {
|
||||
++vma.it;
|
||||
return DrawLine();
|
||||
}
|
||||
TableNextColumn();
|
||||
Text("%" PRIXPTR, m.base);
|
||||
TableNextColumn();
|
||||
Text("%zX", m.size);
|
||||
TableNextColumn();
|
||||
Text("%s", magic_enum::enum_name(m.type).data());
|
||||
TableNextColumn();
|
||||
Text("%s", magic_enum::enum_name(m.prot).data());
|
||||
TableNextColumn();
|
||||
if (m.is_exec) {
|
||||
Text("X");
|
||||
}
|
||||
TableNextColumn();
|
||||
Text("%s", m.name.c_str());
|
||||
++vma.it;
|
||||
return true;
|
||||
}
|
||||
if (dmem.it == dmem.end) {
|
||||
return false;
|
||||
}
|
||||
auto m = dmem.it->second;
|
||||
if (m.is_free) {
|
||||
++dmem.it;
|
||||
return DrawLine();
|
||||
}
|
||||
TableNextColumn();
|
||||
Text("%" PRIXPTR, m.base);
|
||||
TableNextColumn();
|
||||
Text("%zX", m.size);
|
||||
TableNextColumn();
|
||||
auto type = static_cast<::Libraries::Kernel::MemoryTypes>(m.memory_type);
|
||||
Text("%s", magic_enum::enum_name(type).data());
|
||||
TableNextColumn();
|
||||
Text("%d", m.is_pooled);
|
||||
++dmem.it;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryMapViewer::Draw() {
|
||||
SetNextWindowSize({600.0f, 500.0f}, ImGuiCond_FirstUseEver);
|
||||
if (!Begin("Memory map", &open)) {
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
auto mem = Memory::Instance();
|
||||
std::scoped_lock lck{mem->mutex};
|
||||
|
||||
{
|
||||
bool next_showing_vma = showing_vma;
|
||||
if (showing_vma) {
|
||||
PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||
}
|
||||
if (Button("VMem")) {
|
||||
next_showing_vma = true;
|
||||
}
|
||||
if (showing_vma) {
|
||||
PopStyleColor();
|
||||
}
|
||||
SameLine();
|
||||
if (!showing_vma) {
|
||||
PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||
}
|
||||
if (Button("DMem")) {
|
||||
next_showing_vma = false;
|
||||
}
|
||||
if (!showing_vma) {
|
||||
PopStyleColor();
|
||||
}
|
||||
showing_vma = next_showing_vma;
|
||||
}
|
||||
|
||||
Iterator it{};
|
||||
if (showing_vma) {
|
||||
it.is_vma = true;
|
||||
it.vma.it = mem->vma_map.begin();
|
||||
it.vma.end = mem->vma_map.end();
|
||||
} else {
|
||||
it.is_vma = false;
|
||||
it.dmem.it = mem->dmem_map.begin();
|
||||
it.dmem.end = mem->dmem_map.end();
|
||||
}
|
||||
|
||||
if (BeginTable("memory_view_table", showing_vma ? 6 : 4,
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_SizingFixedFit)) {
|
||||
if (showing_vma) {
|
||||
TableSetupColumn("Address");
|
||||
TableSetupColumn("Size");
|
||||
TableSetupColumn("Type");
|
||||
TableSetupColumn("Prot");
|
||||
TableSetupColumn("Is Exec");
|
||||
TableSetupColumn("Name");
|
||||
} else {
|
||||
TableSetupColumn("Address");
|
||||
TableSetupColumn("Size");
|
||||
TableSetupColumn("Type");
|
||||
TableSetupColumn("Pooled");
|
||||
}
|
||||
TableHeadersRow();
|
||||
|
||||
while (it.DrawLine())
|
||||
;
|
||||
EndTable();
|
||||
}
|
||||
|
||||
End();
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
33
src/core/devtools/widget/memory_map.h
Normal file
33
src/core/devtools/widget/memory_map.h
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
class MemoryMapViewer {
|
||||
struct Iterator {
|
||||
bool is_vma;
|
||||
struct {
|
||||
MemoryManager::DMemMap::iterator it;
|
||||
MemoryManager::DMemMap::iterator end;
|
||||
} dmem;
|
||||
struct {
|
||||
MemoryManager::VMAMap::iterator it;
|
||||
MemoryManager::VMAMap::iterator end;
|
||||
} vma;
|
||||
|
||||
bool DrawLine();
|
||||
};
|
||||
|
||||
bool showing_vma = true;
|
||||
|
||||
public:
|
||||
bool open = false;
|
||||
|
||||
void Draw();
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <imgui.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "cmd_list.h"
|
||||
#include "common.h"
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <imgui.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
@ -25,21 +25,6 @@ using magic_enum::enum_name;
|
||||
|
||||
constexpr auto depth_id = 0xF3;
|
||||
|
||||
static std::optional<std::string> exec_cli(const char* cli) {
|
||||
std::array<char, 64> buffer{};
|
||||
std::string output;
|
||||
const auto f = popen(cli, "r");
|
||||
if (!f) {
|
||||
pclose(f);
|
||||
return {};
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), f)) {
|
||||
output += buffer.data();
|
||||
}
|
||||
pclose(f);
|
||||
return output;
|
||||
}
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
void RegView::ProcessShader(int shader_id) {
|
||||
@ -54,38 +39,12 @@ void RegView::ProcessShader(int shader_id) {
|
||||
user_data = s.user_data.user_data;
|
||||
}
|
||||
|
||||
std::string shader_dis;
|
||||
|
||||
if (Options.disassembly_cli.empty()) {
|
||||
shader_dis = "No disassembler set";
|
||||
} else {
|
||||
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
|
||||
|
||||
constexpr std::string_view src_arg = "{src}";
|
||||
std::string cli = Options.disassembly_cli;
|
||||
const auto pos = cli.find(src_arg);
|
||||
if (pos == std::string::npos) {
|
||||
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument");
|
||||
} else {
|
||||
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||
file.Write(shader_code);
|
||||
file.Close();
|
||||
|
||||
auto result = exec_cli(cli.c_str());
|
||||
shader_dis = result.value_or("Could not disassemble shader");
|
||||
if (shader_dis.empty()) {
|
||||
shader_dis = "Disassembly empty or failed";
|
||||
}
|
||||
|
||||
std::filesystem::remove(bin_path);
|
||||
}
|
||||
}
|
||||
std::string shader_dis = RunDisassembler(Options.disassembler_cli_isa, shader_code);
|
||||
|
||||
MemoryEditor hex_view;
|
||||
hex_view.Open = true;
|
||||
hex_view.ReadOnly = true;
|
||||
hex_view.Cols = 8;
|
||||
hex_view.Cols = 16;
|
||||
hex_view.OptShowAscii = false;
|
||||
hex_view.OptShowOptions = false;
|
||||
|
||||
@ -376,7 +335,9 @@ void RegView::Draw() {
|
||||
if (!shader) {
|
||||
Text("Stage not selected");
|
||||
} else {
|
||||
shader->hex_view.DrawContents(shader->user_data.data(), shader->user_data.size());
|
||||
shader->hex_view.DrawContents(shader->user_data.data(),
|
||||
shader->user_data.size() *
|
||||
sizeof(Vulkan::Liverpool::UserData::value_type));
|
||||
}
|
||||
}
|
||||
End();
|
||||
|
95
src/core/devtools/widget/shader_list.cpp
Normal file
95
src/core/devtools/widget/shader_list.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_list.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common/config.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "core/devtools/options.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
void ShaderList::DrawShader(DebugStateType::ShaderDump& value) {
|
||||
if (!loaded_data) {
|
||||
loaded_data = true;
|
||||
if (value.cache_raw_disasm.empty()) {
|
||||
value.cache_raw_disasm = RunDisassembler(Options.disassembler_cli_isa, value.raw_code);
|
||||
}
|
||||
isa_editor.SetText(value.cache_raw_disasm);
|
||||
|
||||
if (value.cache_spv_disasm.empty()) {
|
||||
value.cache_spv_disasm = RunDisassembler(Options.disassembler_cli_spv, value.spv);
|
||||
}
|
||||
spv_editor.SetText(value.cache_spv_disasm);
|
||||
}
|
||||
|
||||
if (SmallButton("<-")) {
|
||||
selected_shader = -1;
|
||||
}
|
||||
SameLine();
|
||||
Text("%s", value.name.c_str());
|
||||
SameLine(0.0f, 7.0f);
|
||||
if (BeginCombo("Shader type", showing_isa ? "ISA" : "SPIRV", ImGuiComboFlags_WidthFitPreview)) {
|
||||
if (Selectable("SPIRV")) {
|
||||
showing_isa = false;
|
||||
}
|
||||
if (Selectable("ISA")) {
|
||||
showing_isa = true;
|
||||
}
|
||||
EndCombo();
|
||||
}
|
||||
|
||||
if (showing_isa) {
|
||||
isa_editor.Render("ISA", GetContentRegionAvail());
|
||||
} else {
|
||||
spv_editor.Render("SPIRV", GetContentRegionAvail());
|
||||
}
|
||||
}
|
||||
|
||||
ShaderList::ShaderList() {
|
||||
isa_editor.SetPalette(TextEditor::GetDarkPalette());
|
||||
isa_editor.SetReadOnly(true);
|
||||
spv_editor.SetPalette(TextEditor::GetDarkPalette());
|
||||
spv_editor.SetReadOnly(true);
|
||||
spv_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::GLSL());
|
||||
}
|
||||
|
||||
void ShaderList::Draw() {
|
||||
SetNextWindowSize({500.0f, 600.0f}, ImGuiCond_FirstUseEver);
|
||||
if (!Begin("Shader list", &open)) {
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config::collectShadersForDebug()) {
|
||||
DrawCenteredText("Enable 'CollectShader' in config to see shaders");
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected_shader >= 0) {
|
||||
DrawShader(DebugState.shader_dump_list[selected_shader]);
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
auto width = GetContentRegionAvail().x;
|
||||
int i = 0;
|
||||
for (const auto& shader : DebugState.shader_dump_list) {
|
||||
if (ButtonEx(shader.name.c_str(), {width, 20.0f}, ImGuiButtonFlags_NoHoveredOnFocus)) {
|
||||
selected_shader = i;
|
||||
loaded_data = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
End();
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
28
src/core/devtools/widget/shader_list.h
Normal file
28
src/core/devtools/widget/shader_list.h
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/debug_state.h"
|
||||
#include "text_editor.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
class ShaderList {
|
||||
int selected_shader = -1;
|
||||
TextEditor isa_editor{};
|
||||
TextEditor spv_editor{};
|
||||
bool loaded_data = false;
|
||||
bool showing_isa = false;
|
||||
|
||||
void DrawShader(DebugStateType::ShaderDump& value);
|
||||
|
||||
public:
|
||||
ShaderList();
|
||||
|
||||
bool open = false;
|
||||
|
||||
void Draw();
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -131,7 +131,7 @@ static int UTF8CharLength(TextEditor::Char c) {
|
||||
}
|
||||
|
||||
// "Borrowed" from ImGui source
|
||||
static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) {
|
||||
static inline int ImTextCharToUtf8(char* buf, int buf_size, u32 c) {
|
||||
if (c < 0x80) {
|
||||
buf[0] = (char)c;
|
||||
return 1;
|
||||
|
@ -1,31 +1,30 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <zlib-ng.h>
|
||||
#include <zlib.h>
|
||||
#include "common/io_file.h"
|
||||
#include "common/logging/formatter.h"
|
||||
#include "core/file_format/pkg.h"
|
||||
#include "core/file_format/pkg_type.h"
|
||||
|
||||
static void DecompressPFSC(std::span<const char> compressed_data,
|
||||
std::span<char> decompressed_data) {
|
||||
zng_stream decompressStream;
|
||||
static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
|
||||
z_stream decompressStream;
|
||||
decompressStream.zalloc = Z_NULL;
|
||||
decompressStream.zfree = Z_NULL;
|
||||
decompressStream.opaque = Z_NULL;
|
||||
|
||||
if (zng_inflateInit(&decompressStream) != Z_OK) {
|
||||
if (inflateInit(&decompressStream) != Z_OK) {
|
||||
// std::cerr << "Error initializing zlib for deflation." << std::endl;
|
||||
}
|
||||
|
||||
decompressStream.avail_in = compressed_data.size();
|
||||
decompressStream.next_in = reinterpret_cast<const Bytef*>(compressed_data.data());
|
||||
decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
|
||||
decompressStream.avail_out = decompressed_data.size();
|
||||
decompressStream.next_out = reinterpret_cast<Bytef*>(decompressed_data.data());
|
||||
decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
|
||||
|
||||
if (zng_inflate(&decompressStream, Z_FINISH)) {
|
||||
if (inflate(&decompressStream, Z_FINISH)) {
|
||||
}
|
||||
if (zng_inflateEnd(&decompressStream) != Z_OK) {
|
||||
if (inflateEnd(&decompressStream) != Z_OK) {
|
||||
// std::cerr << "Error ending zlib inflate" << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -97,24 +97,22 @@ struct PlaygoChunk {
|
||||
|
||||
class PlaygoFile {
|
||||
public:
|
||||
bool initialized;
|
||||
OrbisPlayGoHandle handle;
|
||||
OrbisPlayGoChunkId id;
|
||||
OrbisPlayGoLocus locus;
|
||||
OrbisPlayGoInstallSpeed speed;
|
||||
s64 speed_tick;
|
||||
OrbisPlayGoEta eta;
|
||||
OrbisPlayGoLanguageMask langMask;
|
||||
OrbisPlayGoHandle handle = 0;
|
||||
OrbisPlayGoChunkId id = 0;
|
||||
OrbisPlayGoLocus locus = OrbisPlayGoLocus::NotDownloaded;
|
||||
OrbisPlayGoInstallSpeed speed = OrbisPlayGoInstallSpeed::Trickle;
|
||||
s64 speed_tick = 0;
|
||||
OrbisPlayGoEta eta = 0;
|
||||
OrbisPlayGoLanguageMask langMask = 0;
|
||||
std::vector<PlaygoChunk> chunks;
|
||||
|
||||
public:
|
||||
PlaygoFile()
|
||||
: initialized(false), handle(0), id(0), locus(0), speed(ORBIS_PLAYGO_INSTALL_SPEED_TRICKLE),
|
||||
speed_tick(0), eta(0), langMask(0), playgoHeader{0} {}
|
||||
explicit PlaygoFile() = default;
|
||||
~PlaygoFile() = default;
|
||||
|
||||
bool Open(const std::filesystem::path& filepath);
|
||||
bool LoadChunks(const Common::FS::IOFile& file);
|
||||
|
||||
PlaygoHeader& GetPlaygoHeader() {
|
||||
return playgoHeader;
|
||||
}
|
||||
|
@ -21,8 +21,13 @@ static inline u32 get_max_size(std::string_view key, u32 default_value) {
|
||||
}
|
||||
|
||||
bool PSF::Open(const std::filesystem::path& filepath) {
|
||||
using namespace std::chrono;
|
||||
if (std::filesystem::exists(filepath)) {
|
||||
last_write = std::filesystem::last_write_time(filepath);
|
||||
const auto t = std::filesystem::last_write_time(filepath);
|
||||
const auto rel =
|
||||
duration_cast<seconds>(t - std::filesystem::file_time_type::clock::now()).count();
|
||||
const auto tp = system_clock::to_time_t(system_clock::now() + seconds{rel});
|
||||
last_write = system_clock::from_time_t(tp);
|
||||
}
|
||||
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
@ -99,7 +104,7 @@ bool PSF::Encode(const std::filesystem::path& filepath) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
last_write = std::filesystem::file_time_type::clock::now();
|
||||
last_write = std::chrono::system_clock::now();
|
||||
|
||||
const auto psf_buffer = Encode();
|
||||
const size_t written = file.Write(psf_buffer);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <span>
|
||||
#include <string>
|
||||
@ -71,7 +72,7 @@ public:
|
||||
void AddString(std::string key, std::string value, bool update = false);
|
||||
void AddInteger(std::string key, s32 value, bool update = false);
|
||||
|
||||
[[nodiscard]] std::filesystem::file_time_type GetLastWrite() const {
|
||||
[[nodiscard]] std::chrono::system_clock::time_point GetLastWrite() const {
|
||||
return last_write;
|
||||
}
|
||||
|
||||
@ -80,7 +81,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::filesystem::file_time_type last_write;
|
||||
mutable std::chrono::system_clock::time_point last_write;
|
||||
|
||||
std::vector<Entry> entry_list;
|
||||
|
||||
|
@ -5,13 +5,9 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/stb.h"
|
||||
#include "splash.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_ONLY_PNG
|
||||
#define STBI_NO_STDIO
|
||||
#include "externals/stb_image.h"
|
||||
|
||||
bool Splash::Open(const std::filesystem::path& filepath) {
|
||||
ASSERT_MSG(filepath.stem().string() != "png", "Unexpected file format passed");
|
||||
|
||||
|
114
src/core/file_sys/file.cpp
Normal file
114
src/core/file_sys/file.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "core/file_sys/file.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <io.h>
|
||||
#include <share.h>
|
||||
#include <windows.h>
|
||||
#include "common/ntapi.h"
|
||||
#endif
|
||||
|
||||
namespace Core::FileSys {
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
int File::Open(const std::filesystem::path& path, Common::FS::FileAccessMode f_access) {
|
||||
DWORD access{};
|
||||
if (f_access == Common::FS::FileAccessMode::Read) {
|
||||
access = GENERIC_READ;
|
||||
} else if (f_access == Common::FS::FileAccessMode::Write) {
|
||||
access = GENERIC_WRITE;
|
||||
} else if (f_access == Common::FS::FileAccessMode::ReadWrite) {
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
handle = CreateFileW(path.native().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
s64 File::Read(void* buf, size_t nbytes) {
|
||||
DWORD bytes_read;
|
||||
if (!ReadFile(handle, buf, nbytes, &bytes_read, nullptr)) {
|
||||
UNREACHABLE_MSG("ReadFile failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
s64 File::Pread(void* buf, size_t nbytes, s64 offset) {
|
||||
OVERLAPPED ol{};
|
||||
ol.Offset = offset;
|
||||
ol.OffsetHigh = offset >> 32;
|
||||
DWORD bytes_read;
|
||||
if (!ReadFile(handle, buf, nbytes, &bytes_read, &ol)) {
|
||||
UNREACHABLE_MSG("ReadFile failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
s64 File::Write(const void* buf, size_t nbytes) {
|
||||
DWORD bytes_written;
|
||||
if (!WriteFile(handle, buf, nbytes, &bytes_written, nullptr)) {
|
||||
UNREACHABLE_MSG("WriteFile failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
s64 File::Pwrite(const void* buf, size_t nbytes, s64 offset) {
|
||||
OVERLAPPED ol{};
|
||||
ol.Offset = offset;
|
||||
ol.OffsetHigh = offset >> 32;
|
||||
DWORD bytes_written;
|
||||
if (!WriteFile(handle, buf, nbytes, &bytes_written, &ol)) {
|
||||
UNREACHABLE_MSG("WriteFile failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
void File::SetSize(s64 size) {
|
||||
Lseek(size, 0);
|
||||
if (!SetEndOfFile(handle)) {
|
||||
UNREACHABLE_MSG("SetEndOfFile failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
}
|
||||
|
||||
void File::Flush() {
|
||||
FlushFileBuffers(handle);
|
||||
}
|
||||
|
||||
s64 File::Lseek(s64 offset, int whence) {
|
||||
LARGE_INTEGER new_file_pointer;
|
||||
DWORD origin{};
|
||||
if (whence == 0) {
|
||||
origin = FILE_BEGIN;
|
||||
} else if (whence == 1) {
|
||||
origin = FILE_CURRENT;
|
||||
} else if (whence == 2) {
|
||||
origin = FILE_END;
|
||||
}
|
||||
if (!SetFilePointerEx(handle, LARGE_INTEGER{.QuadPart = offset}, &new_file_pointer, origin)) {
|
||||
UNREACHABLE_MSG("SetFilePointerEx failed: {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
return new_file_pointer.QuadPart;
|
||||
}
|
||||
|
||||
void File::Unlink() {
|
||||
FILE_DISPOSITION_INFORMATION disposition;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
disposition.DeleteFile = TRUE;
|
||||
NtSetInformationFile(handle, &iosb, &disposition, sizeof(disposition),
|
||||
FileDispositionInformation);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Core::FileSys
|
@ -4,12 +4,12 @@
|
||||
#include <algorithm>
|
||||
#include "common/config.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/devices/logger.h"
|
||||
#include "core/devices/nop_device.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
|
||||
namespace Core::FileSys {
|
||||
|
||||
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
|
||||
|
||||
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder,
|
||||
bool read_only) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
@ -135,7 +135,6 @@ int HandleTable::CreateHandle() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
auto* file = new File{};
|
||||
file->is_directory = false;
|
||||
file->is_opened = false;
|
||||
|
||||
int existingFilesNum = m_files.size();
|
||||
@ -143,23 +142,23 @@ int HandleTable::CreateHandle() {
|
||||
for (int index = 0; index < existingFilesNum; index++) {
|
||||
if (m_files.at(index) == nullptr) {
|
||||
m_files[index] = file;
|
||||
return index + RESERVED_HANDLES;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
m_files.push_back(file);
|
||||
return m_files.size() + RESERVED_HANDLES - 1;
|
||||
return m_files.size() - 1;
|
||||
}
|
||||
|
||||
void HandleTable::DeleteHandle(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
delete m_files.at(d - RESERVED_HANDLES);
|
||||
m_files[d - RESERVED_HANDLES] = nullptr;
|
||||
delete m_files.at(d);
|
||||
m_files[d] = nullptr;
|
||||
}
|
||||
|
||||
File* HandleTable::GetFile(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_files.at(d - RESERVED_HANDLES);
|
||||
return m_files.at(d);
|
||||
}
|
||||
|
||||
File* HandleTable::GetFile(const std::filesystem::path& host_name) {
|
||||
@ -171,4 +170,20 @@ File* HandleTable::GetFile(const std::filesystem::path& host_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HandleTable::CreateStdHandles() {
|
||||
auto setup = [this](const char* path, auto* device) {
|
||||
int fd = CreateHandle();
|
||||
auto* file = GetFile(fd);
|
||||
file->is_opened = true;
|
||||
file->type = FileType::Device;
|
||||
file->m_guest_name = path;
|
||||
file->device =
|
||||
std::shared_ptr<Devices::BaseDevice>{reinterpret_cast<Devices::BaseDevice*>(device)};
|
||||
};
|
||||
// order matters
|
||||
setup("/dev/stdin", new Devices::NopDevice(0)); // stdin
|
||||
setup("/dev/stdout", new Devices::Logger("stdout", false)); // stdout
|
||||
setup("/dev/stderr", new Devices::Logger("stderr", true)); // stderr
|
||||
}
|
||||
|
||||
} // namespace Core::FileSys
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
#include <tsl/robin_map.h>
|
||||
#include "common/io_file.h"
|
||||
#include "core/devices/base_device.h"
|
||||
|
||||
namespace Core::FileSys {
|
||||
|
||||
@ -55,15 +56,22 @@ struct DirEntry {
|
||||
bool isFile;
|
||||
};
|
||||
|
||||
enum class FileType {
|
||||
Regular, // standard file
|
||||
Directory,
|
||||
Device,
|
||||
};
|
||||
|
||||
struct File {
|
||||
std::atomic_bool is_opened{};
|
||||
std::atomic_bool is_directory{};
|
||||
std::atomic<FileType> type{FileType::Regular};
|
||||
std::filesystem::path m_host_name;
|
||||
std::string m_guest_name;
|
||||
Common::FS::IOFile f;
|
||||
std::vector<DirEntry> dirents;
|
||||
u32 dirents_index;
|
||||
std::mutex m_mutex;
|
||||
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
|
||||
};
|
||||
|
||||
class HandleTable {
|
||||
@ -76,6 +84,8 @@ public:
|
||||
File* GetFile(int d);
|
||||
File* GetFile(const std::filesystem::path& host_name);
|
||||
|
||||
void CreateStdHandles();
|
||||
|
||||
private:
|
||||
std::vector<File*> m_files;
|
||||
std::mutex m_mutex;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace Libraries::Ajm {
|
||||
|
||||
@ -19,7 +19,7 @@ constexpr int ORBIS_AJM_CHANNELMASK_QUAD = 0x0033;
|
||||
constexpr int ORBIS_AJM_CHANNELMASK_5POINT1 = 0x060F;
|
||||
constexpr int ORBIS_AJM_CHANNELMASK_7POINT1 = 0x063F;
|
||||
|
||||
static std::unique_ptr<AjmContext> context{};
|
||||
static std::unordered_map<u32, std::unique_ptr<AjmContext>> contexts{};
|
||||
|
||||
u32 GetChannelMask(u32 num_channels) {
|
||||
switch (num_channels) {
|
||||
@ -40,7 +40,13 @@ u32 GetChannelMask(u32 num_channels) {
|
||||
|
||||
int PS4_SYSV_ABI sceAjmBatchCancel(const u32 context_id, const u32 batch_id) {
|
||||
LOG_INFO(Lib_Ajm, "called context_id = {} batch_id = {}", context_id, batch_id);
|
||||
return context->BatchCancel(batch_id);
|
||||
|
||||
auto it = contexts.find(context_id);
|
||||
if (it == contexts.end()) {
|
||||
return ORBIS_AJM_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return it->second->BatchCancel(batch_id);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAjmBatchErrorDump() {
|
||||
@ -90,14 +96,26 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context_id, u8* p_batch, u32 batch_s
|
||||
u32* out_batch_id) {
|
||||
LOG_TRACE(Lib_Ajm, "called context = {}, batch_size = {:#x}, priority = {}", context_id,
|
||||
batch_size, priority);
|
||||
return context->BatchStartBuffer(p_batch, batch_size, priority, batch_error, out_batch_id);
|
||||
|
||||
auto it = contexts.find(context_id);
|
||||
if (it == contexts.end()) {
|
||||
return ORBIS_AJM_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return it->second->BatchStartBuffer(p_batch, batch_size, priority, batch_error, out_batch_id);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAjmBatchWait(const u32 context_id, const u32 batch_id, const u32 timeout,
|
||||
AjmBatchError* const batch_error) {
|
||||
LOG_TRACE(Lib_Ajm, "called context = {}, batch_id = {}, timeout = {}", context_id, batch_id,
|
||||
timeout);
|
||||
return context->BatchWait(batch_id, timeout, batch_error);
|
||||
|
||||
auto it = contexts.find(context_id);
|
||||
if (it == contexts.end()) {
|
||||
return ORBIS_AJM_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return it->second->BatchWait(batch_id, timeout, batch_error);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData() {
|
||||
@ -117,12 +135,12 @@ int PS4_SYSV_ABI sceAjmFinalize() {
|
||||
|
||||
int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* p_context_id) {
|
||||
LOG_INFO(Lib_Ajm, "called reserved = {}", reserved);
|
||||
ASSERT_MSG(context == nullptr, "Multiple contexts are currently unsupported.");
|
||||
if (p_context_id == nullptr || reserved != 0) {
|
||||
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
*p_context_id = 1;
|
||||
context = std::make_unique<AjmContext>();
|
||||
u32 id = contexts.size() + 1;
|
||||
*p_context_id = id;
|
||||
contexts.emplace(id, std::make_unique<AjmContext>());
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -135,12 +153,24 @@ int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context_id, AjmCodecType codec_type,
|
||||
AjmInstanceFlags flags, u32* out_instance) {
|
||||
LOG_INFO(Lib_Ajm, "called context = {}, codec_type = {}, flags = {:#x}", context_id,
|
||||
magic_enum::enum_name(codec_type), flags.raw);
|
||||
return context->InstanceCreate(codec_type, flags, out_instance);
|
||||
|
||||
auto it = contexts.find(context_id);
|
||||
if (it == contexts.end()) {
|
||||
return ORBIS_AJM_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return it->second->InstanceCreate(codec_type, flags, out_instance);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context_id, u32 instance_id) {
|
||||
LOG_INFO(Lib_Ajm, "called context = {}, instance = {}", context_id, instance_id);
|
||||
return context->InstanceDestroy(instance_id);
|
||||
|
||||
auto it = contexts.find(context_id);
|
||||
if (it == contexts.end()) {
|
||||
return ORBIS_AJM_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return it->second->InstanceDestroy(instance_id);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAjmInstanceExtend() {
|
||||
@ -168,7 +198,13 @@ int PS4_SYSV_ABI sceAjmModuleRegister(u32 context_id, AjmCodecType codec_type, s
|
||||
if (reserved != 0) {
|
||||
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return context->ModuleRegister(codec_type);
|
||||
|
||||
auto it = contexts.find(context_id);
|
||||
if (it == contexts.end()) {
|
||||
return ORBIS_AJM_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return it->second->ModuleRegister(codec_type);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAjmModuleUnregister() {
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/ajm/ajm.h"
|
||||
#include "core/libraries/ajm/ajm_at9.h"
|
||||
#include "core/libraries/ajm/ajm_context.h"
|
||||
@ -53,6 +54,7 @@ s32 AjmContext::ModuleRegister(AjmCodecType type) {
|
||||
}
|
||||
|
||||
void AjmContext::WorkerThread(std::stop_token stop) {
|
||||
Common::SetCurrentThreadName("shadPS4:AjmWorker");
|
||||
while (!stop.stop_requested()) {
|
||||
auto batch = batch_queue.PopWait(stop);
|
||||
if (batch != nullptr) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "core/libraries/ajm/ajm_instance.h"
|
||||
#include "core/libraries/ajm/ajm_mp3.h"
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace Libraries::Ajm {
|
||||
|
||||
|
@ -12,6 +12,8 @@ extern "C" {
|
||||
#include <libswresample/swresample.h>
|
||||
}
|
||||
|
||||
#include "common/support/avdec.h"
|
||||
|
||||
namespace Libraries::Ajm {
|
||||
|
||||
// Following tables have been reversed from AJM library
|
||||
|
@ -6,34 +6,30 @@
|
||||
#include "app_content.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_format/psf.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/app_content/app_content_error.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::AppContent {
|
||||
|
||||
int32_t addcont_count = 0;
|
||||
|
||||
struct AddContInfo {
|
||||
char entitlementLabel[ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE];
|
||||
char entitlement_label[ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE];
|
||||
OrbisAppContentAddcontDownloadStatus status;
|
||||
OrbisAppContentGetEntitlementKey key;
|
||||
};
|
||||
|
||||
std::array<AddContInfo, ORBIS_APP_CONTENT_INFO_LIST_MAX_SIZE> addcont_info = {{
|
||||
static std::array<AddContInfo, ORBIS_APP_CONTENT_INFO_LIST_MAX_SIZE> addcont_info = {{
|
||||
{"0000000000000000",
|
||||
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED,
|
||||
OrbisAppContentAddcontDownloadStatus::Installed,
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00}},
|
||||
}};
|
||||
|
||||
std::string title_id;
|
||||
static s32 addcont_count = 0;
|
||||
static std::string title_id;
|
||||
|
||||
int PS4_SYSV_ABI _Z5dummyv() {
|
||||
LOG_ERROR(Lib_AppContent, "(STUBBED) called");
|
||||
@ -64,12 +60,11 @@ int PS4_SYSV_ABI sceAppContentAddcontMount(u32 service_label,
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
|
||||
for (int i = 0; i < addcont_count; i++) {
|
||||
if (strncmp(entitlement_label->data, addcont_info[i].entitlementLabel,
|
||||
if (strncmp(entitlement_label->data, addcont_info[i].entitlement_label,
|
||||
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addcont_info[i].status != ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED) {
|
||||
if (addcont_info[i].status != OrbisAppContentAddcontDownloadStatus::Installed) {
|
||||
return ORBIS_APP_CONTENT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
@ -170,14 +165,14 @@ int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label,
|
||||
}
|
||||
|
||||
for (auto i = 0; i < addcont_count; i++) {
|
||||
if (strncmp(entitlementLabel->data, addcont_info[i].entitlementLabel,
|
||||
if (strncmp(entitlementLabel->data, addcont_info[i].entitlement_label,
|
||||
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_AppContent, "found DLC {}", entitlementLabel->data);
|
||||
|
||||
strncpy(info->entitlement_label.data, addcont_info[i].entitlementLabel,
|
||||
strncpy(info->entitlement_label.data, addcont_info[i].entitlement_label,
|
||||
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE);
|
||||
info->status = addcont_info[i].status;
|
||||
return ORBIS_OK;
|
||||
@ -202,7 +197,7 @@ int PS4_SYSV_ABI sceAppContentGetAddcontInfoList(u32 service_label,
|
||||
|
||||
int dlcs_to_list = addcont_count < list_num ? addcont_count : list_num;
|
||||
for (int i = 0; i < dlcs_to_list; i++) {
|
||||
strncpy(list[i].entitlement_label.data, addcont_info[i].entitlementLabel,
|
||||
strncpy(list[i].entitlement_label.data, addcont_info[i].entitlement_label,
|
||||
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE);
|
||||
list[i].status = addcont_info[i].status;
|
||||
}
|
||||
@ -224,7 +219,7 @@ int PS4_SYSV_ABI sceAppContentGetEntitlementKey(
|
||||
}
|
||||
|
||||
for (int i = 0; i < addcont_count; i++) {
|
||||
if (strncmp(entitlement_label->data, addcont_info[i].entitlementLabel,
|
||||
if (strncmp(entitlement_label->data, addcont_info[i].entitlement_label,
|
||||
ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
@ -252,21 +247,19 @@ int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initPar
|
||||
} else {
|
||||
UNREACHABLE_MSG("Failed to get TITLE_ID");
|
||||
}
|
||||
auto addon_path = addons_dir / title_id;
|
||||
if (std::filesystem::exists(addon_path)) {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(addon_path)) {
|
||||
if (entry.is_directory()) {
|
||||
auto entitlement_label = entry.path().filename().string();
|
||||
|
||||
AddContInfo info{};
|
||||
info.status = ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED;
|
||||
strcpy(info.entitlementLabel, entitlement_label.c_str());
|
||||
|
||||
addcont_info[addcont_count++] = info;
|
||||
}
|
||||
}
|
||||
const auto addon_path = addons_dir / title_id;
|
||||
if (!std::filesystem::exists(addon_path)) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(addon_path)) {
|
||||
if (entry.is_directory()) {
|
||||
auto entitlement_label = entry.path().filename().string();
|
||||
auto& info = addcont_info[addcont_count++];
|
||||
info.status = OrbisAppContentAddcontDownloadStatus::Installed;
|
||||
entitlement_label.copy(info.entitlement_label, sizeof(info.entitlement_label));
|
||||
}
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -314,9 +307,11 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataMount() {
|
||||
|
||||
int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option,
|
||||
OrbisAppContentMountPoint* mountPoint) {
|
||||
if (mountPoint == nullptr)
|
||||
if (mountPoint == nullptr) {
|
||||
return ORBIS_APP_CONTENT_ERROR_PARAMETER;
|
||||
strncpy(mountPoint->data, "/temp0", 16);
|
||||
}
|
||||
static constexpr std::string_view TmpMount = "/temp0";
|
||||
TmpMount.copy(mountPoint->data, sizeof(mountPoint->data));
|
||||
LOG_INFO(Lib_AppContent, "sceAppContentTemporaryDataMount2: option = {}, mountPoint = {}",
|
||||
option, mountPoint->data);
|
||||
return ORBIS_OK;
|
||||
|
@ -30,7 +30,7 @@ struct OrbisAppContentBootParam {
|
||||
char reserved2[32];
|
||||
};
|
||||
|
||||
typedef u32 OrbisAppContentTemporaryDataOption;
|
||||
using OrbisAppContentTemporaryDataOption = u32;
|
||||
|
||||
constexpr int ORBIS_APP_CONTENT_MOUNTPOINT_DATA_MAXSIZE = 16;
|
||||
|
||||
@ -44,12 +44,12 @@ constexpr int ORBIS_NP_UNIFIED_ENTITLEMENT_LABEL_SIZE = 17;
|
||||
constexpr int ORBIS_APP_CONTENT_ENTITLEMENT_KEY_SIZE = 16;
|
||||
constexpr int ORBIS_APP_CONTENT_INFO_LIST_MAX_SIZE = 2500;
|
||||
|
||||
enum OrbisAppContentAddcontDownloadStatus : u32 {
|
||||
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_NO_EXTRA_DATA = 0,
|
||||
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_NO_IN_QUEUE = 1,
|
||||
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_DOWNLOADING = 2,
|
||||
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_DOWNLOAD_SUSPENDED = 3,
|
||||
ORBIS_APP_CONTENT_ADDCONT_DOWNLOAD_STATUS_INSTALLED = 4
|
||||
enum class OrbisAppContentAddcontDownloadStatus : u32 {
|
||||
NoExtraData = 0,
|
||||
NoInQueue = 1,
|
||||
Downloading = 2,
|
||||
DownloadSuspended = 3,
|
||||
Installed = 4
|
||||
};
|
||||
|
||||
struct OrbisNpUnifiedEntitlementLabel {
|
||||
@ -57,11 +57,11 @@ struct OrbisNpUnifiedEntitlementLabel {
|
||||
char padding[3];
|
||||
};
|
||||
|
||||
typedef u32 OrbisAppContentAppParamId;
|
||||
using OrbisAppContentAppParamId = u32;
|
||||
|
||||
struct OrbisAppContentAddcontInfo {
|
||||
OrbisNpUnifiedEntitlementLabel entitlement_label;
|
||||
u32 status;
|
||||
OrbisAppContentAddcontDownloadStatus status;
|
||||
};
|
||||
|
||||
struct OrbisAppContentGetEntitlementKey {
|
||||
@ -119,4 +119,4 @@ int PS4_SYSV_ABI sceAppContentGetAddcontInfoListByIroTag();
|
||||
int PS4_SYSV_ABI sceAppContentGetDownloadedStoreCountry();
|
||||
|
||||
void RegisterlibSceAppContent(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::AppContent
|
||||
} // namespace Libraries::AppContent
|
||||
|
11
src/core/libraries/app_content/app_content_error.h
Normal file
11
src/core/libraries/app_content/app_content_error.h
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
// AppContent library
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
|
||||
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
@ -2,32 +2,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <memory>
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "audio_core/sdl_audio.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/audio/sdl_audio.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
static std::unique_ptr<Audio::SDLAudio> audio;
|
||||
static std::unique_ptr<SDLAudioOut> audio;
|
||||
|
||||
static std::string_view GetAudioOutPort(u32 port) {
|
||||
static std::string_view GetAudioOutPort(OrbisAudioOutPort port) {
|
||||
switch (port) {
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_MAIN:
|
||||
case OrbisAudioOutPort::Main:
|
||||
return "MAIN";
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_BGM:
|
||||
case OrbisAudioOutPort::Bgm:
|
||||
return "BGM";
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_VOICE:
|
||||
case OrbisAudioOutPort::Voice:
|
||||
return "VOICE";
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_PERSONAL:
|
||||
case OrbisAudioOutPort::Personal:
|
||||
return "PERSONAL";
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_PADSPK:
|
||||
case OrbisAudioOutPort::Padspk:
|
||||
return "PADSPK";
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_AUX:
|
||||
case OrbisAudioOutPort::Aux:
|
||||
return "AUX";
|
||||
default:
|
||||
return "INVALID";
|
||||
@ -36,21 +36,21 @@ static std::string_view GetAudioOutPort(u32 port) {
|
||||
|
||||
static std::string_view GetAudioOutParamFormat(OrbisAudioOutParamFormat param) {
|
||||
switch (param) {
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
|
||||
case OrbisAudioOutParamFormat::S16Mono:
|
||||
return "S16_MONO";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
|
||||
case OrbisAudioOutParamFormat::S16Stereo:
|
||||
return "S16_STEREO";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
|
||||
case OrbisAudioOutParamFormat::S16_8CH:
|
||||
return "S16_8CH";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
|
||||
case OrbisAudioOutParamFormat::FloatMono:
|
||||
return "FLOAT_MONO";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
|
||||
case OrbisAudioOutParamFormat::FloatStereo:
|
||||
return "FLOAT_STEREO";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
|
||||
case OrbisAudioOutParamFormat::Float_8CH:
|
||||
return "FLOAT_8CH";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
|
||||
case OrbisAudioOutParamFormat::S16_8CH_Std:
|
||||
return "S16_8CH_STD";
|
||||
case ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
|
||||
case OrbisAudioOutParamFormat::Float_8CH_Std:
|
||||
return "FLOAT_8CH_STD";
|
||||
default:
|
||||
return "INVALID";
|
||||
@ -59,11 +59,11 @@ static std::string_view GetAudioOutParamFormat(OrbisAudioOutParamFormat param) {
|
||||
|
||||
static std::string_view GetAudioOutParamAttr(OrbisAudioOutParamAttr attr) {
|
||||
switch (attr) {
|
||||
case ORBIS_AUDIO_OUT_PARAM_ATTR_NONE:
|
||||
case OrbisAudioOutParamAttr::None:
|
||||
return "NONE";
|
||||
case ORBIS_AUDIO_OUT_PARAM_ATTR_RESTRICTED:
|
||||
case OrbisAudioOutParamAttr::Restricted:
|
||||
return "RESTRICTED";
|
||||
case ORBIS_AUDIO_OUT_PARAM_ATTR_MIX_TO_MAIN:
|
||||
case OrbisAudioOutParamAttr::MixToMain:
|
||||
return "MIX_TO_MAIN";
|
||||
default:
|
||||
return "INVALID";
|
||||
@ -180,29 +180,23 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
int type = 0;
|
||||
int channels_num = 0;
|
||||
|
||||
if (const auto err = audio->AudioOutGetStatus(handle, &type, &channels_num); err != ORBIS_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const auto [type, channels_num] = audio->GetStatus(handle);
|
||||
state->rerouteCounter = 0;
|
||||
state->volume = 127; // max volume
|
||||
state->volume = 127;
|
||||
|
||||
switch (type) {
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_MAIN:
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_BGM:
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_VOICE:
|
||||
case OrbisAudioOutPort::Main:
|
||||
case OrbisAudioOutPort::Bgm:
|
||||
case OrbisAudioOutPort::Voice:
|
||||
state->output = 1;
|
||||
state->channel = (channels_num > 2 ? 2 : channels_num);
|
||||
break;
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_PERSONAL:
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_PADSPK:
|
||||
case OrbisAudioOutPort::Personal:
|
||||
case OrbisAudioOutPort::Padspk:
|
||||
state->output = 4;
|
||||
state->channel = 1;
|
||||
break;
|
||||
case ORBIS_AUDIO_OUT_PORT_TYPE_AUX:
|
||||
case OrbisAudioOutPort::Aux:
|
||||
state->output = 0;
|
||||
state->channel = 0;
|
||||
break;
|
||||
@ -243,7 +237,7 @@ int PS4_SYSV_ABI sceAudioOutInit() {
|
||||
if (audio != nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT;
|
||||
}
|
||||
audio = std::make_unique<Audio::SDLAudio>();
|
||||
audio = std::make_unique<SDLAudioOut>();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -287,7 +281,8 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
||||
user_id, GetAudioOutPort(port_type), index, length, sample_rate,
|
||||
GetAudioOutParamFormat(param_type.data_format),
|
||||
GetAudioOutParamAttr(param_type.attributes));
|
||||
if ((port_type < 0 || port_type > 4) && (port_type != 127)) {
|
||||
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
|
||||
(port_type != OrbisAudioOutPort::Aux)) {
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid port type");
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT_TYPE;
|
||||
}
|
||||
@ -303,18 +298,19 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
||||
if (index != 0) {
|
||||
LOG_ERROR(Lib_AudioOut, "index is not valid !=0 {}", index);
|
||||
}
|
||||
OrbisAudioOutParamFormat format = param_type.data_format;
|
||||
if (format < 0 || format > 7) {
|
||||
const auto format = param_type.data_format.Value();
|
||||
if (format < OrbisAudioOutParamFormat::S16Mono ||
|
||||
format > OrbisAudioOutParamFormat::Float_8CH_Std) {
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid format");
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
OrbisAudioOutParamAttr attr = param_type.attributes;
|
||||
if (attr < 0 || attr > 2) {
|
||||
const auto attr = param_type.attributes;
|
||||
if (attr < OrbisAudioOutParamAttr::None || attr > OrbisAudioOutParamAttr::MixToMain) {
|
||||
// TODO Handle attributes in output audio device
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid format attribute");
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
return audio->AudioOutOpen(port_type, length, sample_rate, format);
|
||||
return audio->Open(port_type, length, sample_rate, format);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutOpenEx() {
|
||||
@ -330,7 +326,7 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
|
||||
// Nothing to output
|
||||
return ORBIS_OK;
|
||||
}
|
||||
return audio->AudioOutOutput(handle, ptr);
|
||||
return audio->Output(handle, ptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) {
|
||||
@ -435,7 +431,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
return audio->AudioOutSetVolume(handle, flag, vol);
|
||||
return audio->SetVolume(handle, flag, vol);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutSetVolumeDown() {
|
||||
|
@ -9,46 +9,36 @@
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
constexpr int SCE_AUDIO_OUT_VOLUME_0DB = 32768; // max volume value
|
||||
|
||||
// main up to 8 ports, BGM 1 port, voice up to 4 ports,
|
||||
// Main up to 8 ports, BGM 1 port, voice up to 4 ports,
|
||||
// personal up to 4 ports, padspk up to 5 ports, aux 1 port
|
||||
constexpr int SCE_AUDIO_OUT_NUM_PORTS = 22;
|
||||
constexpr int SCE_AUDIO_OUT_VOLUME_0DB = 32768; // max volume value
|
||||
|
||||
enum OrbisAudioOutPort {
|
||||
ORBIS_AUDIO_OUT_PORT_TYPE_MAIN = 0,
|
||||
ORBIS_AUDIO_OUT_PORT_TYPE_BGM = 1,
|
||||
ORBIS_AUDIO_OUT_PORT_TYPE_VOICE = 2,
|
||||
ORBIS_AUDIO_OUT_PORT_TYPE_PERSONAL = 3,
|
||||
ORBIS_AUDIO_OUT_PORT_TYPE_PADSPK = 4,
|
||||
ORBIS_AUDIO_OUT_PORT_TYPE_AUX = 127
|
||||
enum class OrbisAudioOutPort { Main = 0, Bgm = 1, Voice = 2, Personal = 3, Padspk = 4, Aux = 127 };
|
||||
|
||||
enum class OrbisAudioOutParamFormat {
|
||||
S16Mono = 0,
|
||||
S16Stereo = 1,
|
||||
S16_8CH = 2,
|
||||
FloatMono = 3,
|
||||
FloatStereo = 4,
|
||||
Float_8CH = 5,
|
||||
S16_8CH_Std = 6,
|
||||
Float_8CH_Std = 7
|
||||
};
|
||||
|
||||
enum OrbisAudioOutParamFormat {
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO = 0,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO = 1,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH = 2,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO = 3,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO = 4,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH = 5,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD = 6,
|
||||
ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD = 7
|
||||
enum class OrbisAudioOutParamAttr {
|
||||
None = 0,
|
||||
Restricted = 1,
|
||||
MixToMain = 2,
|
||||
};
|
||||
|
||||
enum OrbisAudioOutParamAttr {
|
||||
ORBIS_AUDIO_OUT_PARAM_ATTR_NONE = 0,
|
||||
ORBIS_AUDIO_OUT_PARAM_ATTR_RESTRICTED = 1,
|
||||
ORBIS_AUDIO_OUT_PARAM_ATTR_MIX_TO_MAIN = 2,
|
||||
};
|
||||
|
||||
struct OrbisAudioOutParamExtendedInformation {
|
||||
union {
|
||||
BitField<0, 8, OrbisAudioOutParamFormat> data_format;
|
||||
BitField<8, 8, u32> reserve0;
|
||||
BitField<16, 4, OrbisAudioOutParamAttr> attributes;
|
||||
BitField<20, 10, u32> reserve1;
|
||||
BitField<31, 1, u32> unused;
|
||||
};
|
||||
union OrbisAudioOutParamExtendedInformation {
|
||||
BitField<0, 8, OrbisAudioOutParamFormat> data_format;
|
||||
BitField<8, 8, u32> reserve0;
|
||||
BitField<16, 4, OrbisAudioOutParamAttr> attributes;
|
||||
BitField<20, 10, u32> reserve1;
|
||||
BitField<31, 1, u32> unused;
|
||||
};
|
||||
|
||||
struct OrbisAudioOutOutputParam {
|
||||
|
34
src/core/libraries/audio/audioout_error.h
Normal file
34
src/core/libraries/audio/audioout_error.h
Normal file
@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
// AudioOut library
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_NOT_OPENED = 0x80260001;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_BUSY = 0x80260002;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_PORT = 0x80260003;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_POINTER = 0x80260004;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_PORT_FULL = 0x80260005;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_SIZE = 0x80260006;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT = 0x80260007;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ = 0x80260008;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_VOLUME = 0x80260009;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_PORT_TYPE = 0x8026000A;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_CONF_TYPE = 0x8026000C;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_OUT_OF_MEMORY = 0x8026000D;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT = 0x8026000E;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_NOT_INIT = 0x8026000F;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_MEMORY = 0x80260010;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_SYSTEM_RESOURCE = 0x80260011;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_TRANS_EVENT = 0x80260012;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_FLAG = 0x80260013;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_MIXLEVEL = 0x80260014;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_ARG = 0x80260015;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_INVALID_PARAM = 0x80260016;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_MASTERING_FATAL = 0x80260200;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_MASTERING_INVALID_API_PARAM = 0x80260201;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_MASTERING_INVALID_CONFIG = 0x80260202;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_MASTERING_NOT_INITIALIZED = 0x80260203;
|
||||
constexpr int ORBIS_AUDIO_OUT_ERROR_MASTERING_INVALID_STATES_ID = 0x80260204;
|
141
src/core/libraries/audio/sdl_audio.cpp
Normal file
141
src/core/libraries/audio/sdl_audio.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <mutex>
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/audio/sdl_audio.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
|
||||
|
||||
s32 SDLAudioOut::Open(OrbisAudioOutPort type, u32 samples_num, u32 freq,
|
||||
OrbisAudioOutParamFormat format) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
const auto port = std::ranges::find(ports_out, false, &PortOut::is_open);
|
||||
if (port == ports_out.end()) {
|
||||
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
|
||||
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
|
||||
}
|
||||
|
||||
port->is_open = true;
|
||||
port->type = type;
|
||||
port->samples_num = samples_num;
|
||||
port->freq = freq;
|
||||
port->format = format;
|
||||
SDL_AudioFormat sampleFormat;
|
||||
switch (format) {
|
||||
case OrbisAudioOutParamFormat::S16Mono:
|
||||
sampleFormat = SDL_AUDIO_S16;
|
||||
port->channels_num = 1;
|
||||
port->sample_size = 2;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::FloatMono:
|
||||
sampleFormat = SDL_AUDIO_F32;
|
||||
port->channels_num = 1;
|
||||
port->sample_size = 4;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::S16Stereo:
|
||||
sampleFormat = SDL_AUDIO_S16;
|
||||
port->channels_num = 2;
|
||||
port->sample_size = 2;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::FloatStereo:
|
||||
sampleFormat = SDL_AUDIO_F32;
|
||||
port->channels_num = 2;
|
||||
port->sample_size = 4;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::S16_8CH:
|
||||
sampleFormat = SDL_AUDIO_S16;
|
||||
port->channels_num = 8;
|
||||
port->sample_size = 2;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::Float_8CH:
|
||||
sampleFormat = SDL_AUDIO_F32;
|
||||
port->channels_num = 8;
|
||||
port->sample_size = 4;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::S16_8CH_Std:
|
||||
sampleFormat = SDL_AUDIO_S16;
|
||||
port->channels_num = 8;
|
||||
port->sample_size = 2;
|
||||
break;
|
||||
case OrbisAudioOutParamFormat::Float_8CH_Std:
|
||||
sampleFormat = SDL_AUDIO_F32;
|
||||
port->channels_num = 8;
|
||||
port->sample_size = 4;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown format");
|
||||
}
|
||||
|
||||
port->volume.fill(Libraries::AudioOut::SCE_AUDIO_OUT_VOLUME_0DB);
|
||||
|
||||
SDL_AudioSpec fmt;
|
||||
SDL_zero(fmt);
|
||||
fmt.format = sampleFormat;
|
||||
fmt.channels = port->channels_num;
|
||||
fmt.freq = freq;
|
||||
port->stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port->stream));
|
||||
return std::distance(ports_out.begin(), port) + 1;
|
||||
}
|
||||
|
||||
s32 SDLAudioOut::Output(s32 handle, const void* ptr) {
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
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);
|
||||
while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
||||
SDL_Delay(0);
|
||||
}
|
||||
return result ? ORBIS_OK : -1;
|
||||
}
|
||||
|
||||
s32 SDLAudioOut::SetVolume(s32 handle, s32 bitflag, s32* volume) {
|
||||
using Libraries::AudioOut::OrbisAudioOutParamFormat;
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
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::Float_8CH_Std ||
|
||||
port.format == OrbisAudioOutParamFormat::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;
|
||||
}
|
||||
|
||||
} // namespace Libraries::AudioOut
|
42
src/core/libraries/audio/sdl_audio.h
Normal file
42
src/core/libraries/audio/sdl_audio.h
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
class SDLAudioOut {
|
||||
public:
|
||||
explicit SDLAudioOut() = default;
|
||||
~SDLAudioOut() = default;
|
||||
|
||||
s32 Open(OrbisAudioOutPort type, u32 samples_num, u32 freq, OrbisAudioOutParamFormat format);
|
||||
s32 Output(s32 handle, const void* ptr);
|
||||
s32 SetVolume(s32 handle, s32 bitflag, s32* volume);
|
||||
|
||||
constexpr std::pair<OrbisAudioOutPort, int> GetStatus(s32 handle) const {
|
||||
const auto& port = ports_out.at(handle - 1);
|
||||
return std::make_pair(port.type, port.channels_num);
|
||||
}
|
||||
|
||||
private:
|
||||
struct PortOut {
|
||||
SDL_AudioStream* stream;
|
||||
u32 samples_num;
|
||||
u32 freq;
|
||||
OrbisAudioOutParamFormat format;
|
||||
OrbisAudioOutPort type;
|
||||
int channels_num;
|
||||
std::array<int, 8> volume;
|
||||
u8 sample_size;
|
||||
bool is_open;
|
||||
};
|
||||
std::shared_mutex m_mutex;
|
||||
std::array<PortOut, Libraries::AudioOut::SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
|
||||
};
|
||||
|
||||
} // namespace Libraries::AudioOut
|
@ -1,19 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio3d.h"
|
||||
#include "audio3d_error.h"
|
||||
#include "audio3d_impl.h"
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio3d/audio3d.h"
|
||||
#include "core/libraries/audio3d/audio3d_error.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::Audio3d {
|
||||
|
||||
// Audio3d
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dInitialize(s64 iReserved) {
|
||||
LOG_INFO(Lib_Audio3d, "iReserved = {}", iReserved);
|
||||
return ORBIS_OK;
|
||||
@ -25,18 +21,19 @@ int PS4_SYSV_ABI sceAudio3dTerminate() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* sParameters) {
|
||||
if (sParameters != NULL) {
|
||||
sParameters->szSizeThis = sizeof(OrbisAudio3dOpenParameters);
|
||||
sParameters->uiGranularity = 256;
|
||||
sParameters->eRate = ORBIS_AUDIO3D_RATE_48000;
|
||||
sParameters->uiMaxObjects = 512;
|
||||
sParameters->uiQueueDepth = 2;
|
||||
sParameters->eBufferMode = ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH;
|
||||
sParameters->uiNumBeds = 2;
|
||||
} else {
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* parameters) {
|
||||
if (parameters == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "Invalid OpenParameters ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
parameters->size_this = sizeof(OrbisAudio3dOpenParameters);
|
||||
parameters->granularity = 256;
|
||||
parameters->rate = OrbisAudio3dRate::Rate48000;
|
||||
parameters->max_objects = 512;
|
||||
parameters->queue_depth = 2;
|
||||
parameters->buffer_mode = OrbisAudio3dBufferMode::AdvanceAndPush;
|
||||
parameters->num_beds = 2;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId iUserId,
|
||||
@ -65,24 +62,24 @@ int PS4_SYSV_ABI sceAudio3dPortFlush(OrbisAudio3dPortId uiPortId) {
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId uiPortId, OrbisAudio3dBlocking eBlocking) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dAttributeId* pCapabilities,
|
||||
unsigned int* pNumCapabilities) {
|
||||
u32* pNumCapabilities) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId uiPortId, unsigned int* pQueueLevel,
|
||||
unsigned int* pQueueAvailable) {
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId uiPortId, u32* pQueueLevel,
|
||||
u32* pQueueAvailable) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
@ -107,24 +104,24 @@ int PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId uiPortId,
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId uiPortId, unsigned int uiNumChannels,
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
|
||||
OrbisAudio3dFormat eFormat, const void* pBuffer,
|
||||
unsigned int uiNumSamples) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}", uiPortId,
|
||||
uiNumChannels, uiNumSamples);
|
||||
u32 uiNumSamples) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}", uiPortId,
|
||||
uiNumChannels, uiNumSamples);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId uiPortId, unsigned int uiNumChannels,
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
|
||||
OrbisAudio3dFormat eFormat, const void* pBuffer,
|
||||
unsigned int uiNumSamples,
|
||||
OrbisAudio3dOutputRoute eOutputRoute, bool bRestricted) {
|
||||
u32 uiNumSamples, OrbisAudio3dOutputRoute eOutputRoute,
|
||||
bool bRestricted) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}, bRestricted = {}",
|
||||
uiPortId, uiNumChannels, uiNumSamples, bRestricted);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
size_t PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize(unsigned int uiNumSpeakers, bool bIs3d) {
|
||||
size_t PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize(u32 uiNumSpeakers, bool bIs3d) {
|
||||
LOG_INFO(Lib_Audio3d, "uiNumSpeakers = {}, bIs3d = {}", uiNumSpeakers, bIs3d);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
@ -152,7 +149,7 @@ int PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray(OrbisAudio3dSpeakerArrayHandle han
|
||||
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients(OrbisAudio3dSpeakerArrayHandle handle,
|
||||
OrbisAudio3dPosition pos, float fSpread,
|
||||
float* pCoefficients,
|
||||
unsigned int uiNumCoefficients) {
|
||||
u32 uiNumCoefficients) {
|
||||
LOG_INFO(Lib_Audio3d, "fSpread = {}, uiNumCoefficients = {}", fSpread, uiNumCoefficients);
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
@ -164,8 +161,7 @@ int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients(OrbisAudio3dSpeakerArr
|
||||
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2(OrbisAudio3dSpeakerArrayHandle handle,
|
||||
OrbisAudio3dPosition pos, float fSpread,
|
||||
float* pCoefficients,
|
||||
unsigned int uiNumCoefficients,
|
||||
bool bHeightAware,
|
||||
u32 uiNumCoefficients, bool bHeightAware,
|
||||
float fDownmixSpreadRadius) {
|
||||
LOG_INFO(Lib_Audio3d,
|
||||
"fSpread = {}, uiNumCoefficients = {}, bHeightAware = {}, fDownmixSpreadRadius = {}",
|
||||
@ -191,7 +187,7 @@ s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle) {
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, const void* ptr) {
|
||||
LOG_INFO(Lib_Audio3d, "handle = {}", handle);
|
||||
LOG_TRACE(Lib_Audio3d, "handle = {}", handle);
|
||||
if (ptr == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid Output ptr");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
@ -209,8 +205,8 @@ s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(::Libraries::AudioOut::OrbisAudioOutO
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortCreate(unsigned int uiGranularity, OrbisAudio3dRate eRate,
|
||||
s64 iReserved, OrbisAudio3dPortId* pId) {
|
||||
int PS4_SYSV_ABI sceAudio3dPortCreate(u32 uiGranularity, OrbisAudio3dRate eRate, s64 iReserved,
|
||||
OrbisAudio3dPortId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiGranularity = {}, iReserved = {}", uiGranularity, iReserved);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
@ -341,4 +337,4 @@ void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym) {
|
||||
sceAudio3dSetGpuRenderer);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Audio3d
|
||||
} // namespace Libraries::Audio3d
|
||||
|
@ -15,56 +15,57 @@ namespace Libraries::Audio3d {
|
||||
|
||||
class Audio3d;
|
||||
|
||||
typedef int OrbisUserServiceUserId;
|
||||
typedef unsigned int OrbisAudio3dPortId;
|
||||
typedef unsigned int OrbisAudio3dObjectId;
|
||||
typedef unsigned int OrbisAudio3dAttributeId;
|
||||
using OrbisUserServiceUserId = s32;
|
||||
using OrbisAudio3dPortId = u32;
|
||||
using OrbisAudio3dObjectId = u32;
|
||||
using OrbisAudio3dAttributeId = u32;
|
||||
|
||||
enum OrbisAudio3dFormat {
|
||||
ORBIS_AUDIO3D_FORMAT_S16 = 0, // s16
|
||||
ORBIS_AUDIO3D_FORMAT_FLOAT = 1 // f32
|
||||
enum class OrbisAudio3dFormat {
|
||||
S16 = 0,
|
||||
Float = 1,
|
||||
};
|
||||
|
||||
enum OrbisAudio3dRate { ORBIS_AUDIO3D_RATE_48000 = 0 };
|
||||
|
||||
enum OrbisAudio3dBufferMode {
|
||||
ORBIS_AUDIO3D_BUFFER_NO_ADVANCE = 0,
|
||||
ORBIS_AUDIO3D_BUFFER_ADVANCE_NO_PUSH = 1,
|
||||
ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH = 2
|
||||
enum class OrbisAudio3dRate {
|
||||
Rate48000 = 0,
|
||||
};
|
||||
|
||||
enum OrbisAudio3dBlocking { ORBIS_AUDIO3D_BLOCKING_ASYNC = 0, ORBIS_AUDIO3D_BLOCKING_SYNC = 1 };
|
||||
enum class OrbisAudio3dBufferMode { NoAdvance = 0, AdvanceNoPush = 1, AdvanceAndPush = 2 };
|
||||
|
||||
enum OrbisAudio3dPassthrough {
|
||||
ORBIS_AUDIO3D_PASSTHROUGH_NONE = 0,
|
||||
ORBIS_AUDIO3D_PASSTHROUGH_LEFT = 1,
|
||||
ORBIS_AUDIO3D_PASSTHROUGH_RIGHT = 2
|
||||
enum class OrbisAudio3dBlocking {
|
||||
Async = 0,
|
||||
Sync = 1,
|
||||
};
|
||||
|
||||
enum OrbisAudio3dOutputRoute {
|
||||
ORBIS_AUDIO3D_OUTPUT_BOTH = 0,
|
||||
ORBIS_AUDIO3D_OUTPUT_HMU_ONLY = 1,
|
||||
ORBIS_AUDIO3D_OUTPUT_TV_ONLY = 2
|
||||
enum class OrbisAudio3dPassthrough {
|
||||
None = 0,
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
};
|
||||
|
||||
enum OrbisAudio3dAmbisonics {
|
||||
ORBIS_AUDIO3D_AMBISONICS_NONE = ~0,
|
||||
ORBIS_AUDIO3D_AMBISONICS_W = 0,
|
||||
ORBIS_AUDIO3D_AMBISONICS_X = 1,
|
||||
ORBIS_AUDIO3D_AMBISONICS_Y = 2,
|
||||
ORBIS_AUDIO3D_AMBISONICS_Z = 3,
|
||||
ORBIS_AUDIO3D_AMBISONICS_R = 4,
|
||||
ORBIS_AUDIO3D_AMBISONICS_S = 5,
|
||||
ORBIS_AUDIO3D_AMBISONICS_T = 6,
|
||||
ORBIS_AUDIO3D_AMBISONICS_U = 7,
|
||||
ORBIS_AUDIO3D_AMBISONICS_V = 8,
|
||||
ORBIS_AUDIO3D_AMBISONICS_K = 9,
|
||||
ORBIS_AUDIO3D_AMBISONICS_L = 10,
|
||||
ORBIS_AUDIO3D_AMBISONICS_M = 11,
|
||||
ORBIS_AUDIO3D_AMBISONICS_N = 12,
|
||||
ORBIS_AUDIO3D_AMBISONICS_O = 13,
|
||||
ORBIS_AUDIO3D_AMBISONICS_P = 14,
|
||||
ORBIS_AUDIO3D_AMBISONICS_Q = 15
|
||||
enum class OrbisAudio3dOutputRoute {
|
||||
Both = 0,
|
||||
HmuOnly = 1,
|
||||
TvOnly = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dAmbisonics : u32 {
|
||||
None = ~0U,
|
||||
W = 0,
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Z = 3,
|
||||
R = 4,
|
||||
S = 5,
|
||||
T = 6,
|
||||
U = 7,
|
||||
V = 8,
|
||||
K = 9,
|
||||
L = 10,
|
||||
M = 11,
|
||||
N = 12,
|
||||
O = 13,
|
||||
P = 14,
|
||||
Q = 15
|
||||
};
|
||||
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePcm = 0x00000001;
|
||||
@ -86,21 +87,21 @@ struct OrbisAudio3dSpeakerArray;
|
||||
using OrbisAudio3dSpeakerArrayHandle = OrbisAudio3dSpeakerArray*; // head
|
||||
|
||||
struct OrbisAudio3dOpenParameters {
|
||||
size_t szSizeThis;
|
||||
unsigned int uiGranularity;
|
||||
OrbisAudio3dRate eRate;
|
||||
unsigned int uiMaxObjects;
|
||||
unsigned int uiQueueDepth;
|
||||
OrbisAudio3dBufferMode eBufferMode;
|
||||
size_t size_this;
|
||||
u32 granularity;
|
||||
OrbisAudio3dRate rate;
|
||||
u32 max_objects;
|
||||
u32 queue_depth;
|
||||
OrbisAudio3dBufferMode buffer_mode;
|
||||
char padding[32];
|
||||
unsigned int uiNumBeds;
|
||||
u32 num_beds;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dAttribute {
|
||||
OrbisAudio3dAttributeId uiAttributeId;
|
||||
OrbisAudio3dAttributeId attribute_id;
|
||||
char padding[32];
|
||||
const void* pValue;
|
||||
size_t szValue;
|
||||
const void* p_value;
|
||||
size_t value;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dPosition {
|
||||
@ -110,25 +111,25 @@ struct OrbisAudio3dPosition {
|
||||
};
|
||||
|
||||
struct OrbisAudio3dPcm {
|
||||
OrbisAudio3dFormat eFormat;
|
||||
const void* pSampleBuffer;
|
||||
unsigned int uiNumSamples;
|
||||
OrbisAudio3dFormat format;
|
||||
const void* sample_buffer;
|
||||
u32 num_samples;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dSpeakerArrayParameters {
|
||||
OrbisAudio3dPosition* pSpeakerPosition;
|
||||
unsigned int uiNumSpeakers;
|
||||
bool bIs3d;
|
||||
void* pBuffer;
|
||||
size_t szSize;
|
||||
OrbisAudio3dPosition* speaker_position;
|
||||
u32 num_speakers;
|
||||
bool is_3d;
|
||||
void* buffer;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dApplicationSpecific {
|
||||
size_t szSizeThis;
|
||||
u8 cApplicationSpecific[32];
|
||||
size_t size_this;
|
||||
u8 application_specific[32];
|
||||
};
|
||||
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* sParameters);
|
||||
|
||||
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Audio3d
|
||||
} // namespace Libraries::Audio3d
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user