diff --git a/.ci/build-mac-arm64.sh b/.ci/build-mac-arm64.sh index 8be887a164..a40a37972c 100644 --- a/.ci/build-mac-arm64.sh +++ b/.ci/build-mac-arm64.sh @@ -72,13 +72,13 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then cd qt-downloader git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597 # nested Qt 6.8.1 URL workaround - sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader - sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader + # sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader + # sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader cd "/tmp/Qt" "$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64" - sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround - "$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64" + # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround + "$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64" fi cd "$WORKDIR" diff --git a/.ci/build-mac.sh b/.ci/build-mac.sh index 9b541b3a53..e6ef1a0178 100644 --- a/.ci/build-mac.sh +++ b/.ci/build-mac.sh @@ -40,13 +40,13 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then cd qt-downloader git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597 # nested Qt 6.8.1 URL workaround - sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader - sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader + # sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader + # sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader cd "/tmp/Qt" "$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64" - sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround - "$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64" + # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround + "$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64" fi cd "$WORKDIR" diff --git a/3rdparty/7zip/7zip b/3rdparty/7zip/7zip index e008ce3976..e5431fa6f5 160000 --- a/3rdparty/7zip/7zip +++ b/3rdparty/7zip/7zip @@ -1 +1 @@ -Subproject commit e008ce3976c087bfd21344af8f00a23cf69d4174 +Subproject commit e5431fa6f5505e385c6f9367260717e9c47dc2ee diff --git a/3rdparty/FAudio b/3rdparty/FAudio index 74d45e615c..b7c2e109ea 160000 --- a/3rdparty/FAudio +++ b/3rdparty/FAudio @@ -1 +1 @@ -Subproject commit 74d45e615c2e7510c7e0f2ccb91dc6d7ccae4bec +Subproject commit b7c2e109ea86b82109244c9c4569ce9ad0c884df diff --git a/3rdparty/OpenAL/openal-soft b/3rdparty/OpenAL/openal-soft index d3875f333f..90191edd20 160000 --- a/3rdparty/OpenAL/openal-soft +++ b/3rdparty/OpenAL/openal-soft @@ -1 +1 @@ -Subproject commit d3875f333fb6abe2f39d82caca329414871ae53b +Subproject commit 90191edd20bb877c5cbddfdac7ec0fe49ad93727 diff --git a/3rdparty/curl/curl b/3rdparty/curl/curl index b1ef0e1a01..75a2079d5c 160000 --- a/3rdparty/curl/curl +++ b/3rdparty/curl/curl @@ -1 +1 @@ -Subproject commit b1ef0e1a01c0bb6ee5367bd9c186a603bde3615a +Subproject commit 75a2079d5c28debb2eaa848ca9430f1fe0d7844c diff --git a/3rdparty/libsdl-org/SDL b/3rdparty/libsdl-org/SDL index c98c4fbff6..9c821dc21c 160000 --- a/3rdparty/libsdl-org/SDL +++ b/3rdparty/libsdl-org/SDL @@ -1 +1 @@ -Subproject commit c98c4fbff6d8f3016a3ce6685bf8f43433c3efcc +Subproject commit 9c821dc21ccbd69b2bda421fdb35cb4ae2da8f5e diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 88ff7e2991..dd59303337 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -566,9 +566,41 @@ void fmt_class_string::format(std::string& out, u64 arg) fmt::append(out, "\n(in file %s", loc.file_name()); } - if (auto func = loc.function_name(); func && func[0]) + if (std::string_view full_func{loc.function_name() ? loc.function_name() : ""}; !full_func.empty()) { - fmt::append(out, ", in function %s)", func); + // Remove useless disambiguators + std::string func = fmt::replace_all(std::string(full_func), { + {"struct ", ""}, + {"class ", ""}, + {"enum ", ""}, + {"typename ", ""}, +#ifdef _MSC_VER + {"__cdecl ", ""}, +#endif + {"unsigned long long", "ullong"}, + //{"unsigned long", "ulong"}, // ullong + {"unsigned int", "uint"}, + {"unsigned short", "ushort"}, + {"unsigned char", "uchar"}}); + + // Remove function argument signature for long names + for (usz index = func.find_first_of('('); index != umax && func.size() >= 100u; index = func.find_first_of('(', index)) + { + // Operator() function + if (func.compare(0, 3, "()("sv) == 0 || func.compare(0, 3, "() "sv)) + { + if (usz not_space = func.find_first_not_of(' ', index + 2); not_space != umax && func[not_space] == '(') + { + index += 2; + continue; + } + } + + func = func.substr(0, index) + "()"; + break; + } + + fmt::append(out, ", in function '%s')", func); } else { diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 000910848f..c31a0b804f 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1360,7 +1360,7 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe // check if address is RawSPU MMIO register do if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) { - auto thread = idm::get>(spu_thread::find_raw_spu((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); + auto thread = idm::get_unlocked>(spu_thread::find_raw_spu((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); if (!thread) { @@ -1548,7 +1548,7 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe } } - if (auto pf_port = idm::get(pf_port_id); pf_port && pf_port->queue) + if (auto pf_port = idm::get_unlocked(pf_port_id); pf_port && pf_port->queue) { // We notify the game that a page fault occurred so it can rectify it. // Note, for data3, were the memory readable AND we got a page fault, it must be due to a write violation since reads are allowed. @@ -2555,13 +2555,13 @@ std::string thread_ctrl::get_name_cached() return *name_cache; } -thread_base::thread_base(native_entry entry, std::string name) +thread_base::thread_base(native_entry entry, std::string name) noexcept : entry_point(entry) , m_tname(make_single_value(std::move(name))) { } -thread_base::~thread_base() +thread_base::~thread_base() noexcept { // Cleanup abandoned tasks: initialize default results and signal this->exec(); @@ -2602,7 +2602,7 @@ bool thread_base::join(bool dtor) const if (i >= 16 && !(i & (i - 1)) && timeout != atomic_wait_timeout::inf) { - sig_log.error(u8"Thread [%s] is too sleepy. Waiting for it %.3fµs already!", *m_tname.load(), (utils::get_tsc() - stamp0) / (utils::get_tsc_freq() / 1000000.)); + sig_log.error("Thread [%s] is too sleepy. Waiting for it %.3fus already!", *m_tname.load(), (utils::get_tsc() - stamp0) / (utils::get_tsc_freq() / 1000000.)); } } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 7f2e0b522f..4350915d70 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -172,9 +172,9 @@ private: friend class named_thread; protected: - thread_base(native_entry, std::string name); + thread_base(native_entry, std::string name) noexcept; - ~thread_base(); + ~thread_base() noexcept; public: // Get CPU cycles since last time this function was called. First call returns 0. @@ -351,7 +351,7 @@ public: // Sets the native thread priority and returns it to zero at destructor struct scoped_priority { - explicit scoped_priority(int prio) + explicit scoped_priority(int prio) noexcept { set_native_priority(prio); } @@ -360,7 +360,7 @@ public: scoped_priority& operator=(const scoped_priority&) = delete; - ~scoped_priority() + ~scoped_priority() noexcept { set_native_priority(0); } @@ -388,7 +388,7 @@ class thread_future_t : public thread_future, result_storage(args)...) , m_func(std::forward(func)) { @@ -417,7 +417,7 @@ public: }; } - ~thread_future_t() + ~thread_future_t() noexcept { if constexpr (!future::empty && !Discard) { @@ -570,7 +570,7 @@ public: named_thread& operator=(const named_thread&) = delete; // Wait for the completion and access result (if not void) - [[nodiscard]] decltype(auto) operator()() + [[nodiscard]] decltype(auto) operator()() noexcept { thread::join(); @@ -581,7 +581,7 @@ public: } // Wait for the completion and access result (if not void) - [[nodiscard]] decltype(auto) operator()() const + [[nodiscard]] decltype(auto) operator()() const noexcept { thread::join(); @@ -593,7 +593,7 @@ public: // Send command to the thread to invoke directly (references should be passed via std::ref()) template - auto operator()(Arg&& arg, Args&&... args) + auto operator()(Arg&& arg, Args&&... args) noexcept { // Overloaded operator() of the Context. constexpr bool v1 = std::is_invocable_v; @@ -667,12 +667,12 @@ public: } // Access thread state - operator thread_state() const + operator thread_state() const noexcept { return static_cast(thread::m_sync.load() & 3); } - named_thread& operator=(thread_state s) + named_thread& operator=(thread_state s) noexcept { if (s == thread_state::created) { @@ -693,7 +693,7 @@ public: if constexpr (std::is_assignable_v) { - static_cast(*this) = s; + static_cast(*this) = thread_state::aborting; } if (notify_sync) @@ -706,13 +706,18 @@ public: { // This participates in emulation stopping, use destruction-alike semantics thread::join(true); + + if constexpr (std::is_assignable_v) + { + static_cast(*this) = thread_state::finished; + } } return *this; } // Context type doesn't need virtual destructor - ~named_thread() + ~named_thread() noexcept { // Assign aborting state forcefully and join thread operator=(thread_state::finished); diff --git a/Utilities/mutex.h b/Utilities/mutex.h index 0b7cba2248..4c09431096 100644 --- a/Utilities/mutex.h +++ b/Utilities/mutex.h @@ -121,7 +121,7 @@ public: void unlock_hle() { - const u32 value = atomic_storage::fetch_add_hle_rel(m_value.raw(), 0u - c_one); + const u32 value = atomic_storage::fetch_add_hle_rel(m_value.raw(), ~c_one + 1); if (value != c_one) [[unlikely]] { diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d8f2fa9258..81e4a92a9b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -132,7 +132,7 @@ jobs: UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac" RELEASE_MESSAGE: "../GitHubReleaseMessage.txt" ARTDIR: $(Build.ArtifactStagingDirectory) - QT_VER: '6.8.1' + QT_VER: '6.7.3' QT_VER_MAIN: '6' LLVM_COMPILER_VER: '16' @@ -193,7 +193,7 @@ jobs: UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac-arm64" RELEASE_MESSAGE: "../GitHubReleaseMessage.txt" ARTDIR: $(Build.ArtifactStagingDirectory) - QT_VER: '6.8.1' + QT_VER: '6.7.3' QT_VER_MAIN: '6' LLVM_COMPILER_VER: '16' diff --git a/darwin/util/sysinfo_darwin.mm b/darwin/util/sysinfo_darwin.mm index e1ffe458f3..0be5eec7f0 100644 --- a/darwin/util/sysinfo_darwin.mm +++ b/darwin/util/sysinfo_darwin.mm @@ -1,5 +1,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic ignored "-Wmissing-declarations" #import #pragma GCC diagnostic pop diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index f4f67a4ea1..2d63e67ab8 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -506,6 +506,7 @@ target_sources(rpcs3_emu PRIVATE RSX/GL/OpenGL.cpp RSX/GL/upscalers/fsr1/fsr_pass.cpp RSX/GSRender.cpp + RSX/Host/MM.cpp RSX/Host/RSXDMAWriter.cpp RSX/Null/NullGSRender.cpp RSX/NV47/FW/draw_call.cpp diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 6aa6a1554e..1b4fc5515b 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -1,6 +1,7 @@ #pragma once #include +#include "Emu/CPU/CPUThread.h" #include "Utilities/StrFmt.h" enum class cpu_disasm_mode @@ -22,7 +23,7 @@ protected: const u8* m_offset{}; const u32 m_start_pc; std::add_pointer_t m_cpu{}; - std::shared_ptr m_cpu_handle; + shared_ptr m_cpu_handle; u32 m_op = 0; void format_by_mode() @@ -81,7 +82,7 @@ public: return const_cast(m_cpu); } - void set_cpu_handle(std::shared_ptr cpu) + void set_cpu_handle(shared_ptr cpu) { m_cpu_handle = std::move(cpu); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index e78824c0b5..520446e991 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -87,7 +87,7 @@ void fmt_class_string::format(std::string& ou const u32 must_have_cpu_id = static_cast(arg); // Dump main_thread - const auto main_ppu = idm::get>(ppu_thread::id_base); + const auto main_ppu = idm::get_unlocked>(ppu_thread::id_base); if (main_ppu) { @@ -99,7 +99,7 @@ void fmt_class_string::format(std::string& ou { if (must_have_cpu_id != ppu_thread::id_base) { - const auto selected_ppu = idm::get>(must_have_cpu_id); + const auto selected_ppu = idm::get_unlocked>(must_have_cpu_id); if (selected_ppu) { @@ -110,7 +110,7 @@ void fmt_class_string::format(std::string& ou } else if (must_have_cpu_id >> 24 == spu_thread::id_base >> 24) { - const auto selected_spu = idm::get>(must_have_cpu_id); + const auto selected_spu = idm::get_unlocked>(must_have_cpu_id); if (selected_spu) { @@ -236,7 +236,7 @@ struct cpu_prof } // Print info - void print(const std::shared_ptr& ptr) + void print(const shared_ptr& ptr) { if (new_samples < min_print_samples || samples == idle) { @@ -263,7 +263,7 @@ struct cpu_prof new_samples = 0; } - static void print_all(std::unordered_map, sample_info>& threads, sample_info& all_info) + static void print_all(std::unordered_map, sample_info>& threads, sample_info& all_info) { u64 new_samples = 0; @@ -319,7 +319,7 @@ struct cpu_prof void operator()() { - std::unordered_map, sample_info> threads; + std::unordered_map, sample_info> threads; while (thread_ctrl::state() != thread_state::aborting) { @@ -335,15 +335,15 @@ struct cpu_prof continue; } - std::shared_ptr ptr; + shared_ptr ptr; if (id >> 24 == 1) { - ptr = idm::get>(id); + ptr = idm::get_unlocked>(id); } else if (id >> 24 == 2) { - ptr = idm::get>(id); + ptr = idm::get_unlocked>(id); } else { @@ -437,7 +437,7 @@ struct cpu_prof continue; } - // Wait, roughly for 20µs + // Wait, roughly for 20us thread_ctrl::wait_for(20, false); } @@ -1302,7 +1302,7 @@ cpu_thread* cpu_thread::get_next_cpu() return nullptr; } -std::shared_ptr make_disasm(const cpu_thread* cpu, std::shared_ptr handle); +std::shared_ptr make_disasm(const cpu_thread* cpu, shared_ptr handle); void cpu_thread::dump_all(std::string& ret) const { @@ -1318,7 +1318,7 @@ void cpu_thread::dump_all(std::string& ret) const if (u32 cur_pc = get_pc(); cur_pc != umax) { // Dump a snippet of currently executed code (may be unreliable with non-static-interpreter decoders) - auto disasm = make_disasm(this, nullptr); + auto disasm = make_disasm(this, null_ptr); const auto rsx = try_get(); @@ -1558,14 +1558,14 @@ u32 CPUDisAsm::DisAsmBranchTarget(s32 /*imm*/) return 0; } -extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock, std::vector>, u32>>* out_list) +extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock, std::vector>, u32>>* out_list) { if (out_list) { out_list->clear(); } - auto get_spus = [old_counter = u64{umax}, spu_list = std::vector>>()](bool can_collect, bool force_collect) mutable + auto get_spus = [old_counter = u64{umax}, spu_list = std::vector>>()](bool can_collect, bool force_collect) mutable { const u64 new_counter = cpu_thread::g_threads_created + cpu_thread::g_threads_deleted; diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp index 43c5f7989b..dfc91c8d2f 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp @@ -1,11 +1,14 @@ #include "stdafx.h" +#include "Emu/perf_meter.hpp" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/lv2/sys_sync.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" #include "Emu/savestate_utils.hpp" +#include "sysPrxForUser.h" #include "cellAdec.h" -#include +#include "util/simd.hpp" #include "util/asm.hpp" LOG_CHANNEL(cellAdec); @@ -225,57 +228,732 @@ void fmt_class_string::format(std::string& out, u64 arg) vm::gvar g_cell_adec_core_ops_lpcm; +void LpcmDecContext::exec(ppu_thread& ppu) +{ + perf_meter<"LPCMDEC"_u64> perf0; + + switch (savestate) + { + case lpcm_dec_state::waiting_for_cmd_mutex_lock: break; + case lpcm_dec_state::waiting_for_cmd_cond_wait: break; + case lpcm_dec_state::waiting_for_output_mutex_lock: goto output_mutex_lock; + case lpcm_dec_state::waiting_for_output_cond_wait: goto output_cond_wait; + case lpcm_dec_state::queue_mutex_lock: goto queue_mutex_lock; + case lpcm_dec_state::executing_cmd: goto execute_cmd; + } + + for (; run_thread; cmd_counter++) + { + cellAdec.trace("Command counter: %llu, waiting for next command...", cmd_counter); + + // Wait for a command to become available + error_occurred |= static_cast(cmd_available.acquire(ppu, savestate) != CELL_OK); + + if (ppu.state & cpu_flag::again) + { + return; + } + + cellAdec.trace("Command available, waiting for output to be consumed..."); + + // Wait for the output to be consumed. + // The output has to be consumed even if the next command is not a decode command + savestate = lpcm_dec_state::waiting_for_output_mutex_lock; + output_mutex_lock: + + error_occurred |= static_cast(sys_mutex_lock(ppu, output_mutex, 0) != CELL_OK); + + if (ppu.state & cpu_flag::again) + { + return; + } + + while (output_locked) + { + savestate = lpcm_dec_state::waiting_for_output_cond_wait; + output_cond_wait: + + ensure(sys_cond_wait(ppu, output_consumed, 0) == CELL_OK); // Error code isn't checked on LLE + + if (ppu.state & cpu_flag::again) + { + return; + } + } + + cellAdec.trace("Output consumed"); + + // Pop command from queue + savestate = lpcm_dec_state::queue_mutex_lock; + queue_mutex_lock: + + ensure(sys_mutex_lock(ppu, queue_mutex, 0) == CELL_OK); // Error code isn't checked on LLE + + if (ppu.state & cpu_flag::again) + { + return; + } + + cmd_queue.pop(cmd); + + ensure(sys_mutex_unlock(ppu, queue_mutex) == CELL_OK); // Error code isn't checked on LLE + + cellAdec.trace("Command type: %d", static_cast(cmd.type.get())); + + savestate = lpcm_dec_state::executing_cmd; + execute_cmd: + + switch (cmd.type) + { + case LpcmDecCmdType::start_seq: + // LLE sends a command to the SPU thread. The SPU thread consumes the command without doing anything, however + error_occurred |= static_cast(sys_mutex_unlock(ppu, output_mutex) != CELL_OK); + break; + + case LpcmDecCmdType::end_seq: + { + // Block savestate creation during callbacks + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return; + } + + // Doesn't do anything else + notify_seq_done.cbFunc(ppu, notify_seq_done.cbArg); + + error_occurred |= static_cast(sys_mutex_unlock(ppu, output_mutex) != CELL_OK); + break; + } + case LpcmDecCmdType::close: + ensure(sys_mutex_unlock(ppu, output_mutex) == CELL_OK); // Error code isn't checked on LLE + return; + + case LpcmDecCmdType::decode_au: + { + // For 20 and 24-bit samples + const u8* const input_u8 = static_cast(cmd.au_start_addr.get_ptr()); + const s64 au_size_u8 = cmd.au_size; + + // For 16-bit samples + const be_t* const input_s16 = static_cast*>(cmd.au_start_addr.get_ptr()); + const s64 au_size_s16 = static_cast(au_size_u8 / sizeof(s16)); + + be_t* const _output = std::assume_aligned<0x80>(output.get_ptr()); + s64 output_size = cmd.au_size; + + s32 sample_num = static_cast(utils::align(+lpcm_param->audioPayloadSize, 0x10)); + s32 channel_num = 0; + + if (!dvd_packing) + { + switch (lpcm_param->sizeOfWord) + { + case CELL_ADEC_BIT_LENGTH_16: output_size = output_size * 32 / 16; sample_num /= 2; break; + case CELL_ADEC_BIT_LENGTH_20: // Same as below + case CELL_ADEC_BIT_LENGTH_24: output_size = output_size * 32 / 24; sample_num /= 3; break; + default: ; // LLE skips decoding entirely, the output buffer isn't written to, and it outputs whatever was there before + } + + // LPCM streams with an odd number of channels contain an empty dummy channel + switch (lpcm_param->channelNumber) + { + case CELL_ADEC_CH_MONO: channel_num = 1; output_size = output_size * 1 / 2; break; + case CELL_ADEC_CH_STEREO: channel_num = 2; break; + case CELL_ADEC_CH_3_0: // Same as below + case CELL_ADEC_CH_2_1: channel_num = 3; output_size = output_size * 3 / 4; break; + case CELL_ADEC_CH_3_1: // Same as below + case CELL_ADEC_CH_2_2: channel_num = 4; break; + case CELL_ADEC_CH_3_2: channel_num = 5; output_size = output_size * 5 / 6; break; + case CELL_ADEC_CH_3_2_LFE: channel_num = 6; break; + case CELL_ADEC_CH_3_4: channel_num = 7; output_size = output_size * 7 / 8; break; + case CELL_ADEC_CH_3_4_LFE: channel_num = 8; break; + default: ; // Don't do anything, LLE simply skips reordering channels + } + + // LLE doesn't check the output size + ensure(output_size <= LPCM_DEC_OUTPUT_BUFFER_SIZE); + ensure(sample_num * sizeof(f32) <= LPCM_DEC_OUTPUT_BUFFER_SIZE); + + // Convert to float + if (lpcm_param->sizeOfWord == CELL_ADEC_BIT_LENGTH_16) + { + s64 i = 0; + for (; i <= au_size_s16 - 8; i += 8) + { + const v128 s16be = v128::loadu(&input_s16[i]); + + // Convert endianess if necessary and shift left by 16 +#if defined(ARCH_X64) && !defined(__SSSE3__) + const v128 s16le = gv_rol16<8>(s16be); + const v128 s32_1 = gv_unpacklo16(gv_bcst16(0), s16le); + const v128 s32_2 = gv_unpackhi16(gv_bcst16(0), s16le); +#else + const v128 s32_1 = std::endian::native == std::endian::little + ? gv_shuffle8(s16be, v128::normal_array_t{ -1, -1, 1, 0, -1, -1, 3, 2, -1, -1, 5, 4, -1, -1, 7, 6 }) + : gv_unpacklo16(s16be, gv_bcst16(0)); + + const v128 s32_2 = std::endian::native == std::endian::little + ? gv_shuffle8(s16be, v128::normal_array_t{ -1, -1, 9, 8, -1, -1, 11, 10, -1, -1, 13, 12, -1, -1, 15, 14 }) + : gv_unpackhi16(s16be, gv_bcst16(0)); +#endif + // Convert to float and divide by INT32_MAX + 1 + const v128 f32_1 = gv_mulfs(gv_cvts32_tofs(s32_1), 1.f / static_cast(0x80000000u)); + const v128 f32_2 = gv_mulfs(gv_cvts32_tofs(s32_2), 1.f / static_cast(0x80000000u)); + + v128::storeu(gv_to_be32(f32_1), &_output[i]); + v128::storeu(gv_to_be32(f32_2), &_output[i + 4]); + } + + for (; i < au_size_s16; i++) + { + _output[i] = static_cast(input_s16[i]) / 0x8000u; + } + } + else if (lpcm_param->sizeOfWord == CELL_ADEC_BIT_LENGTH_20 || lpcm_param->sizeOfWord == CELL_ADEC_BIT_LENGTH_24) + { + s64 i = 0; + for (; i * 3 <= au_size_u8 - static_cast(sizeof(v128)); i += 4) + { + // Load four samples, convert endianness if necessary and shift left by 8 + const v128 _s32 = std::endian::native == std::endian::little + ? gv_shuffle8(v128::loadu(&input_u8[i * 3]), v128::normal_array_t{ -1, 2, 1, 0, -1, 5, 4, 3, -1, 8, 7, 6, -1, 11, 10, 9 }) + : gv_shuffle8(v128::loadu(&input_u8[i * 3]), v128::normal_array_t{ 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 }); + + // Convert to float and divide by INT32_MAX + 1 + const v128 _f32 = gv_mulfs(gv_cvts32_tofs(_s32), 1.f / static_cast(0x80000000u)); + + v128::storeu(gv_to_be32(_f32), &_output[i]); + } + + for (; i * 3 <= au_size_u8 - 3; i++) + { + alignas(alignof(s32)) const u8 s32le[4] = { 0, input_u8[i * 3 + 2], input_u8[i * 3 + 1], input_u8[i * 3] }; + + _output[i] = static_cast(std::bit_cast>(s32le)) / static_cast(0x80000000u); + } + } + + // Reorder channels and remove the dummy channel + + // Input channel order: + // Front Left, Front Right, Center, Side Left, Rear Left, Rear Right, Side Right, LFE + + // Output channel order: + // - up to 3_4: Front Left, Center, Front Right, Side Left, Side Right, Rear Left, Rear Right, LFE + // - 3_4_LFE: Front Left, Front Right, Center, LFE, Side Left, Side Right, Rear Left, Rear Right + + // The following loops can access sample_num % channel_num * sizeof(f32) bytes more than LPCM_DEC_OUTPUT_BUFFER_SIZE (up to 28 bytes). + // This is intended, LLE does something similar. The buffer is much larger than LPCM_DEC_OUTPUT_BUFFER_SIZE (see _CellAdecCoreOpGetMemSize_lpcm()) + switch (lpcm_param->channelNumber) + { + case CELL_ADEC_CH_MONO: + for (s32 i = 0; i < sample_num / 2; i += 4) + { + const v128 tmp1 = v128::loadu(&_output[i * 2]); + const v128 tmp2 = v128::loadu(&_output[i * 2 + 4]); + v128::storeu(gv_shufflefs<0, 2, 0, 2>(tmp1, tmp2), &_output[i]); // Remove every other sample + } + break; + + case CELL_ADEC_CH_STEREO: + case CELL_ADEC_CH_2_2: + // Input order == output order, no need to do anything + break; + + case CELL_ADEC_CH_3_0: + for (s32 i_in = 0, i_out = 0; i_in < sample_num; i_in += 4, i_out += 3) + { + const v128 tmp = gv_shuffle32<0, 2, 1, 3>(v128::loadu(&_output[i_in])); // Swap Front Right and Center + v128::storeu(tmp, &_output[i_out]); + } + break; + + case CELL_ADEC_CH_2_1: + for (s32 i_in = 0, i_out = 0; i_in < sample_num; i_in += 4, i_out += 3) + { + v128::storeu(v128::loadu(&_output[i_in]), &_output[i_out]); + } + break; + + case CELL_ADEC_CH_3_1: + case CELL_ADEC_CH_3_2_LFE: + for (s32 i = 0; i < sample_num; i += channel_num) + { + const u64 tmp = std::rotl(read_from_ptr(&_output[i + 1]), 0x20); // Swap Front Right and Center + std::memcpy(&_output[i + 1], &tmp, sizeof(u64)); + } + break; + + case CELL_ADEC_CH_3_2: + for (s32 i_in = 0, i_out = 0; i_in < sample_num; i_in += 6, i_out += 5) + { + const v128 tmp = gv_shuffle32<0, 2, 1, 3>(v128::loadu(&_output[i_in])); // Swap Front Right and Center + v128::storeu(tmp, &_output[i_out]); + _output[i_out + 4] = _output[i_in + 4]; + } + break; + + case CELL_ADEC_CH_3_4: + for (s32 i_in = 0, i_out = 0; i_in < sample_num; i_in += 8, i_out += 7) + { + const v128 tmp1 = gv_shuffle32<0, 2, 1, 3>(v128::loadu(&_output[i_in])); // Swap Front Right and Center + const v128 tmp2 = gv_shuffle32<2, 0, 1, 3>(v128::loadu(&_output[i_in + 4])); // Reorder Rear Left, Rear Right, Side Right -> Side Right, Rear Left, Rear Right + v128::storeu(tmp1, &_output[i_out]); + v128::storeu(tmp2, &_output[i_out + 4]); + } + break; + + case CELL_ADEC_CH_3_4_LFE: + for (s32 i = 0; i < sample_num; i += 8) + { + const v128 tmp1 = gv_shuffle32<3, 2, 0, 1>(v128::loadu(&_output[i + 4])); // Reorder Rear Left, Rear Right, Side Right, LFE -> LFE, Side Right, Rear Left, Rear Right + v128::storeu(tmp1, &_output[i + 4]); + const u64 tmp2 = std::rotl(read_from_ptr(&_output[i + 3]), 0x20); // Swap Side Left and LFE + std::memcpy(&_output[i + 3], &tmp2, sizeof(u64)); + } + break; + + default: + ; // Don't do anything + } + } + else + { + switch (lpcm_param->sizeOfWord) + { + case CELL_ADEC_BIT_LENGTH_16: output_size = output_size * 32 / 16; break; + case CELL_ADEC_BIT_LENGTH_20: output_size = output_size * 32 / 20; break; + case CELL_ADEC_BIT_LENGTH_24: output_size = output_size * 32 / 24; break; + default: fmt::throw_exception("Unreachable"); // Parameters get verified in adecSetLpcmDvdParams() + } + + // Only the front left and right channels are decoded, all other channels are ignored + switch (lpcm_param->channelNumber) + { + case CELL_ADEC_LPCM_DVD_CH_MONO: // Set channel_num to two for mono as well + case CELL_ADEC_LPCM_DVD_CH_STEREO: channel_num = 2; break; + case 4: channel_num = 3; output_size = output_size * 2 / 3; break; + case 5: channel_num = 4; output_size = output_size * 2 / 4; break; + case CELL_ADEC_LPCM_DVD_CH_3_2: channel_num = 5; output_size = output_size * 2 / 5; break; + case CELL_ADEC_LPCM_DVD_CH_3_2_LFE: channel_num = 6; output_size = output_size * 2 / 6; break; + case CELL_ADEC_LPCM_DVD_CH_3_4: channel_num = 7; output_size = output_size * 2 / 7; break; + case CELL_ADEC_LPCM_DVD_CH_3_4_LFE: channel_num = 8; output_size = output_size * 2 / 8; break; + default: fmt::throw_exception("Unreachable"); // Parameters get verified in adecSetLpcmDvdParams() + } + + // LLE doesn't check the output size + ensure(output_size <= LPCM_DEC_OUTPUT_BUFFER_SIZE); + + // Convert to float + switch (lpcm_param->sizeOfWord) + { + case CELL_ADEC_BIT_LENGTH_16: + { + s64 i_in = 0; + s64 i_out = 0; + for (; i_in <= au_size_s16 - channel_num - 2; i_in += channel_num * 2, i_out += 4) + { + // Load four samples + const v128 tmp1 = gv_loadu32(&input_s16[i_in]); + const v128 tmp2 = gv_loadu32(&input_s16[i_in + channel_num]); + const v128 s16be = gv_unpacklo32(tmp1, tmp2); + + // Convert endianess if necessary and shift left by 16 + const v128 _s32 = std::endian::native == std::endian::little + ? gv_shuffle8(s16be, v128::normal_array_t{ -1, -1, 1, 0, -1, -1, 3, 2, -1, -1, 5, 4, -1, -1, 7, 6 }) + : gv_unpacklo16(s16be, gv_bcst16(0)); + + // Convert to float and divide by INT32_MAX + 1 + const v128 _f32 = gv_mulfs(gv_cvts32_tofs(_s32), 1.f / static_cast(0x80000000u)); + + v128::storeu(gv_to_be32(_f32), &_output[i_out]); + } + + for (; i_in <= au_size_s16 - 2; i_in += channel_num, i_out += 2) + { + const v128 s16be = gv_loadu32(&input_s16[i_in]); + + const v128 _s32 = std::endian::native == std::endian::little + ? gv_shuffle8(s16be, v128::normal_array_t{ -1, -1, 1, 0, -1, -1, 3, 2, -1, -1, 5, 4, -1, -1, 7, 6 }) + : gv_unpacklo16(s16be, gv_bcst16(0)); + + const v128 _f32 = gv_mulfs(gv_cvts32_tofs(_s32), 1.f / static_cast(0x80000000u)); + + std::memcpy(&_output[i_out], &gv_to_be32(_f32)._u64[0], sizeof(u64)); + } + break; + } + case CELL_ADEC_BIT_LENGTH_20: + { + const s64 high_bytes_3_4_offset = lpcm_param->channelNumber == CELL_ADEC_LPCM_DVD_CH_MONO ? 5 : channel_num * 2; + const s64 low_bits_1_2_offset = lpcm_param->channelNumber == CELL_ADEC_LPCM_DVD_CH_MONO ? 4 : channel_num * 4; + const s64 low_bits_3_4_offset = channel_num * 4 + channel_num / 2 - !(channel_num & 1); + const s64 next_samples_offset = channel_num * 5; + + // If channel_num is odd, the low bits of samples three and four are in different bytes + alignas(alignof(v128)) static constexpr auto shuffle_ctrl_same_offset = std::endian::native == std::endian::little + ? v128::normal_array_t{ -1, 8, 1, 0, -1, 8, 3, 2, -1, 11, 5, 4, -1, 11, 7, 6 } + : v128::normal_array_t{ 0, 1, 8, -1, 2, 3, 8, -1, 4, 5, 11, -1, 6, 7, 11, -1 }; + + alignas(alignof(v128)) static constexpr auto shuffle_ctrl_different_offset = std::endian::native == std::endian::little + ? v128::normal_array_t{ -1, 8, 1, 0, -1, 8, 3, 2, -1, 10, 5, 4, -1, 11, 7, 6 } + : v128::normal_array_t{ 0, 1, 8, -1, 2, 3, 8, -1, 4, 5, 10, -1, 6, 7, 11, -1 }; + + const v128 shuffle_ctrl = channel_num & 1 ? v128::loadu(&shuffle_ctrl_different_offset) : v128::loadu(&shuffle_ctrl_same_offset); + + alignas(alignof(v128)) static constexpr auto low_bits_mask_same_offset = std::endian::native == std::endian::little + ? v128::normal_array_t{ 0x00, 0xf0, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff } + : v128::normal_array_t{ 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0x0f, 0x00 }; + + alignas(alignof(v128)) static constexpr auto low_bits_mask_different_offset = std::endian::native == std::endian::little + ? v128::normal_array_t{ 0x00, 0xf0, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff } + : v128::normal_array_t{ 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0xf0, 0x00 }; + + const v128 low_bits_mask = channel_num & 1 ? v128::loadu(&low_bits_mask_different_offset) : v128::loadu(&low_bits_mask_same_offset); + + for (s64 i_in = 0, i_out = 0; i_in <= au_size_u8 - low_bits_3_4_offset - (channel_num & 1); i_in += next_samples_offset, i_out += 4) + { + // Load all the high and low bits of four samples + const v128 tmp1 = gv_loadu32(&input_u8[i_in]); + const v128 tmp2 = gv_loadu32(&input_u8[i_in + high_bytes_3_4_offset]); + v128 s20be = gv_unpacklo32(tmp1, tmp2); + s20be = gv_insert16<4>(s20be, read_from_ptr(&input_u8[i_in + low_bits_1_2_offset])); + s20be = gv_insert16<5>(s20be, read_from_ptr(&input_u8[i_in + low_bits_3_4_offset])); + + // Reorder bytes to form four 32-bit integer samples + v128 _s32 = gv_shuffle8(s20be, shuffle_ctrl); + + // Set low 12 bits to zero for each sample + _s32 = _s32 & low_bits_mask; + + // LLE is missing a step: each byte that was ANDed with 0x0f would still need to be shifted left by 4 + + // Convert to float and divide by INT32_MAX + 1 + const v128 _f32 = gv_mulfs(gv_cvts32_tofs(_s32), 1.f / static_cast(0x80000000u)); + + v128::storeu(gv_to_be32(_f32), &_output[i_out]); + } + break; + } + case CELL_ADEC_BIT_LENGTH_24: + { + const s64 high_bytes_3_4_offset = lpcm_param->channelNumber == CELL_ADEC_LPCM_DVD_CH_MONO ? 6 : channel_num * 2; + const s64 low_bytes_1_2_offset = lpcm_param->channelNumber == CELL_ADEC_LPCM_DVD_CH_MONO ? 4 : channel_num * 4; + const s64 low_bytes_3_4_offset = channel_num * 5; + const s64 next_samples_offset = channel_num * 6; + + for (s64 i_in = 0, i_out = 0; i_in <= au_size_u8 - low_bytes_3_4_offset - 2; i_in += next_samples_offset, i_out += 4) + { + // Load all the high and low bytes of four samples + const v128 tmp1 = gv_loadu32(&input_u8[i_in]); + const v128 tmp2 = gv_loadu32(&input_u8[i_in + high_bytes_3_4_offset]); + v128 s24be = gv_unpacklo32(tmp1, tmp2); + s24be = gv_insert16<4>(s24be, read_from_ptr(&input_u8[i_in + low_bytes_1_2_offset])); + s24be = gv_insert16<5>(s24be, read_from_ptr(&input_u8[i_in + low_bytes_3_4_offset])); + + // Reorder bytes to form four 32-bit integer samples + const v128 _s32 = std::endian::native == std::endian::little + ? gv_shuffle8(s24be, v128::normal_array_t{ -1, 8, 1, 0, -1, 9, 3, 2, -1, 10, 5, 4, -1, 11, 7, 6 }) + : gv_shuffle8(s24be, v128::normal_array_t{ 0, 1, 8, -1, 2, 3, 9, -1, 4, 5, 10, -1, 6, 7, 11, -1 }); + + // Convert to float and divide by INT32_MAX + 1 + const v128 _f32 = gv_mulfs(gv_cvts32_tofs(_s32), 1.f / static_cast(0x80000000u)); + + v128::storeu(gv_to_be32(_f32), &_output[i_out]); + } + } + } + } + + // Block savestate creation during callbacks + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return; + } + + if (error_occurred) + { + notify_error.cbFunc(ppu, CELL_ADEC_ERROR_FATAL, notify_error.cbArg); + } + + notify_au_done.cbFunc(ppu, cmd.pcm_handle, notify_au_done.cbArg); + + output_locked = true; + error_occurred |= static_cast(sys_mutex_unlock(ppu, output_mutex) != CELL_OK); + + const vm::var bsi_info{{ lpcm_param->channelNumber, lpcm_param->sampleRate, static_cast(output_size) }}; + + notify_pcm_out.cbFunc(ppu, cmd.pcm_handle, output, static_cast(output_size), notify_pcm_out.cbArg, vm::make_var>(bsi_info), ADEC_CORRECT_PTS_VALUE_TYPE_LPCM_HDMV, error_occurred ? static_cast(CELL_ADEC_ERROR_FATAL) : CELL_OK); + break; + } + default: + fmt::throw_exception("Invalid command"); + } + } +} + +template +error_code LpcmDecContext::send_command(ppu_thread& ppu, auto&&... args) +{ + ppu.state += cpu_flag::wait; + + if (error_code ret = sys_mutex_lock(ppu, queue_size_mutex, 0); ret != CELL_OK) + { + return ret; + } + + if (cmd_queue.full()) + { + ensure(sys_mutex_unlock(ppu, queue_size_mutex) == CELL_OK); // Error code isn't checked on LLE + return CELL_ADEC_ERROR_BUSY; + } + + // LLE copies the parameters directly into the context + if constexpr (type == LpcmDecCmdType::start_seq) + { + *lpcm_param = { args... }; + } + + if (error_code ret = sys_mutex_lock(ppu, queue_mutex, 0); ret != CELL_OK) + { + ensure(sys_mutex_unlock(ppu, queue_size_mutex) == CELL_OK); // Error code isn't checked on LLE + return ret; + } + + cmd_queue.emplace(type, std::forward(args)...); + + if (error_code ret = sys_mutex_unlock(ppu, queue_mutex); ret != CELL_OK + || (ret = cmd_available.release(ppu)) != CELL_OK) + { + ensure(sys_mutex_unlock(ppu, queue_size_mutex) == CELL_OK); // Error code isn't checked on LLE + return ret; + } + + return sys_mutex_unlock(ppu, queue_size_mutex); +} + +inline error_code LpcmDecContext::release_output(ppu_thread& ppu) +{ + if (error_code ret = sys_mutex_lock(ppu, output_mutex, 0); ret != CELL_OK) + { + return ret; + } + + output_locked = false; + + if (error_code ret = sys_cond_signal(ppu, output_consumed); ret != CELL_OK) + { + return ret; // LLE doesn't unlock the mutex + } + + return sys_mutex_unlock(ppu, output_mutex); +} + +void lpcmDecEntry(ppu_thread& ppu, vm::ptr lpcm_dec) +{ + lpcm_dec->exec(ppu); + + if (ppu.state & cpu_flag::again) + { + // For savestates, save argument + ppu.syscall_args[0] = lpcm_dec.addr(); + + return; + } + + ppu_execute<&sys_ppu_thread_exit>(ppu, CELL_OK); +} + error_code _CellAdecCoreOpGetMemSize_lpcm(vm::ptr attr) { - cellAdec.todo("_CellAdecCoreOpGetMemSize_lpcm(attr=*0x%x)", attr); + cellAdec.notice("_CellAdecCoreOpGetMemSize_lpcm(attr=*0x%x)", attr); + + constexpr u32 mem_size = + utils::align(static_cast(sizeof(LpcmDecContext)), 0x80) + + utils::align(static_cast(sizeof(CellAdecParamLpcm)), 0x80) + + 0x100 // Command data for Spurs task + + LPCM_DEC_OUTPUT_BUFFER_SIZE + + 0x2900 // sizeof(CellSpurs) + sizeof(CellSpursTaskset) + + 0x3b400 // Spurs context + + 0x300 // (sizeof(CellSpursQueue) + 0x80 + queue buffer) * 2 + + 0x855; // Unused + + static_assert(mem_size == 0x7ebd5); + + attr->workMemSize = mem_size; return CELL_OK; } -[[noreturn]] error_code _CellAdecCoreOpOpenExt_lpcm(vm::ptr handle, vm::ptr notifyAuDone, vm::ptr notifyAuDoneArg, vm::ptr notifyPcmOut, vm::ptr notifyPcmOutArg, +error_code _CellAdecCoreOpOpenExt_lpcm(ppu_thread& ppu, vm::ptr handle, vm::ptr notifyAuDone, vm::ptr notifyAuDoneArg, vm::ptr notifyPcmOut, vm::ptr notifyPcmOutArg, vm::ptr notifyError, vm::ptr notifyErrorArg, vm::ptr notifySeqDone, vm::ptr notifySeqDoneArg, vm::cptr res, vm::cptr spursRes) { - cellAdec.todo("_CellAdecCoreOpOpenExt_lpcm(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=0x%x, notifyError=*0x%x, notifyErrorArg=0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=0x%x, res=*0x%x, spursRes=*0x%x)", + cellAdec.notice("_CellAdecCoreOpOpenExt_lpcm(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=0x%x, notifyError=*0x%x, notifyErrorArg=0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=0x%x, res=*0x%x, spursRes=*0x%x)", handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, spursRes); - fmt::throw_exception("LPCM decoder not implemented, please disable HLE libadec.sprx"); + ensure(!!handle && !!res); // Not checked on LLE + ensure(handle.aligned(0x80)); // LLE doesn't check the alignment or aligns the address itself + ensure(!!notifyAuDone && !!notifyAuDoneArg && !!notifyPcmOut && !!notifyPcmOutArg && !!notifyError && !!notifyErrorArg && !!notifySeqDone && !!notifySeqDoneArg); // These should always be set + + const u32 end_of_context_addr = handle.addr() + utils::align(static_cast(sizeof(LpcmDecContext)), 0x80); + + handle->cmd_queue.front = 0; + handle->cmd_queue.back = 0; + handle->cmd_queue.size = 0; + handle->run_thread = true; + handle->notify_au_done = { notifyAuDone, notifyAuDoneArg }; + handle->notify_pcm_out = { notifyPcmOut, notifyPcmOutArg }; + handle->notify_error = { notifyError, notifyErrorArg }; + handle->notify_seq_done = { notifySeqDone, notifySeqDoneArg }; + handle->output = vm::bptr::make(end_of_context_addr + 0x180); + handle->lpcm_param.set(end_of_context_addr); + handle->error_occurred = false; + + const vm::var mutex_attr{{ SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem04"_u64 } }}; + const vm::var output_mutex_attr{{ SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem05"_u64 } }}; + const vm::var queue_mutex_attr{{ SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem06"_u64 } }}; + const vm::var cond_attr{{ SYS_SYNC_NOT_PROCESS_SHARED, 0, 0, { "_adec03"_u64 } }}; + + error_code ret = sys_mutex_create(ppu, handle.ptr(&LpcmDecContext::queue_size_mutex), mutex_attr); + ret = ret ? ret : sys_cond_create(ppu, handle.ptr(&LpcmDecContext::queue_size_cond), handle->queue_size_mutex, cond_attr); + ret = ret ? ret : sys_mutex_create(ppu, handle.ptr(&LpcmDecContext::unk_mutex), mutex_attr); + ret = ret ? ret : sys_cond_create(ppu, handle.ptr(&LpcmDecContext::unk_cond), handle->unk_mutex, cond_attr); + ret = ret ? ret : sys_mutex_create(ppu, handle.ptr(&LpcmDecContext::output_mutex), output_mutex_attr); + ret = ret ? ret : sys_cond_create(ppu, handle.ptr(&LpcmDecContext::output_consumed), handle->output_mutex, cond_attr); + ret = ret ? ret : sys_mutex_create(ppu, handle.ptr(&LpcmDecContext::queue_mutex), queue_mutex_attr); + ret = ret ? ret : handle->release_output(ppu); + ret = ret ? ret : handle->cmd_available.init(ppu, handle.ptr(&LpcmDecContext::cmd_available), 0); + ret = ret ? ret : handle->reserved2.init(ppu, handle.ptr(&LpcmDecContext::reserved2), 0); + + if (ret != CELL_OK) + { + return ret; + } + + // HLE exclusive + handle->savestate = lpcm_dec_state::waiting_for_cmd_mutex_lock; + handle->cmd_counter = 0; + + const vm::var _name = vm::make_str("HLE LPCM decoder"); + const auto entry = g_fxo->get().func_addr(FIND_FUNC(lpcmDecEntry)); + + ret = ppu_execute<&sys_ppu_thread_create>(ppu, handle.ptr(&LpcmDecContext::thread_id), entry, handle.addr(), +res->ppuThreadPriority, +res->ppuThreadStackSize, SYS_PPU_THREAD_CREATE_JOINABLE, +_name); + ret = ret ? ret : sys_mutex_create(ppu, handle.ptr(&LpcmDecContext::spurs_queue_pop_mutex), mutex_attr); + ret = ret ? ret : sys_mutex_create(ppu, handle.ptr(&LpcmDecContext::spurs_queue_push_mutex), mutex_attr); + + return ret; } -[[noreturn]] error_code _CellAdecCoreOpOpen_lpcm(vm::ptr handle, vm::ptr notifyAuDone, vm::ptr notifyAuDoneArg, vm::ptr notifyPcmOut, vm::ptr notifyPcmOutArg, +error_code _CellAdecCoreOpOpen_lpcm(ppu_thread& ppu, vm::ptr handle, vm::ptr notifyAuDone, vm::ptr notifyAuDoneArg, vm::ptr notifyPcmOut, vm::ptr notifyPcmOutArg, vm::ptr notifyError, vm::ptr notifyErrorArg, vm::ptr notifySeqDone, vm::ptr notifySeqDoneArg, vm::cptr res) { - cellAdec.todo("_CellAdecCoreOpOpen_lpcm(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x)", + cellAdec.notice("_CellAdecCoreOpOpen_lpcm(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x)", handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res); - fmt::throw_exception("LPCM decoder not implemented, please disable HLE libadec.sprx"); + return _CellAdecCoreOpOpenExt_lpcm(ppu, handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, vm::null); } -error_code _CellAdecCoreOpClose_lpcm(vm::ptr handle) +error_code _CellAdecCoreOpClose_lpcm(ppu_thread& ppu, vm::ptr handle) { - cellAdec.todo("_CellAdecCoreOpClose_lpcm(handle=*0x%x)", handle); + ppu.state += cpu_flag::wait; - return CELL_OK; + cellAdec.notice("_CellAdecCoreOpClose_lpcm(handle=*0x%x)", handle); + + if (error_code ret = sys_mutex_lock(ppu, handle->queue_size_mutex, 0); ret != CELL_OK + || (ret = sys_mutex_lock(ppu, handle->queue_mutex, 0)) != CELL_OK) + { + return ret; + } + + if (handle->cmd_queue.empty()) + { + handle->cmd_queue.emplace(LpcmDecCmdType::close); + + if (error_code ret = sys_mutex_unlock(ppu, handle->queue_mutex); ret != CELL_OK) + { + return ret; // LLE doesn't unlock the queue size mutex + } + + if (error_code ret = handle->cmd_available.release(ppu); ret != CELL_OK) + { + ensure(sys_mutex_unlock(ppu, handle->queue_size_mutex) == CELL_OK); // Error code isn't checked on LLE + return ret; + } + } + else + { + for (auto& cmd : handle->cmd_queue.elements) + { + cmd.type = LpcmDecCmdType::close; + } + + if (error_code ret = sys_mutex_unlock(ppu, handle->queue_mutex); ret != CELL_OK) + { + return ret; // LLE doesn't unlock the queue size mutex + } + } + + error_code ret = sys_mutex_unlock(ppu, handle->queue_size_mutex); + ret = ret ? ret : handle->release_output(ppu); + + vm::var thread_ret; + ret = ret ? ret : sys_ppu_thread_join(ppu, static_cast(handle->thread_id), +thread_ret); + + ret = ret ? ret : sys_cond_destroy(ppu, handle->queue_size_cond); + ret = ret ? ret : sys_cond_destroy(ppu, handle->unk_cond); + ret = ret ? ret : sys_cond_destroy(ppu, handle->output_consumed); + ret = ret ? ret : sys_mutex_destroy(ppu, handle->queue_mutex); + ret = ret ? ret : sys_mutex_destroy(ppu, handle->queue_size_mutex); + ret = ret ? ret : sys_mutex_destroy(ppu, handle->unk_mutex); + ret = ret ? ret : sys_mutex_destroy(ppu, handle->output_mutex); + ret = ret ? ret : handle->cmd_available.finalize(ppu); + ret = ret ? ret : handle->reserved2.finalize(ppu); + ret = ret ? ret : sys_mutex_destroy(ppu, handle->spurs_queue_pop_mutex); + ret = ret ? ret : sys_mutex_destroy(ppu, handle->spurs_queue_push_mutex); + + return ret; } -error_code _CellAdecCoreOpStartSeq_lpcm(vm::ptr handle, vm::ptr lpcmParam) +error_code _CellAdecCoreOpStartSeq_lpcm(ppu_thread& ppu, vm::ptr handle, vm::ptr lpcmParam) { - cellAdec.todo("_CellAdecCoreOpStartSeq_lpcm(handle=*0x%x, lpcmParam=*0x%x)", handle, lpcmParam); + cellAdec.notice("_CellAdecCoreOpStartSeq_lpcm(handle=*0x%x, lpcmParam=*0x%x)", handle, lpcmParam); - return CELL_OK; + ensure(!!handle && !!lpcmParam); // Not checked on LLE + + cellAdec.notice("_CellAdecCoreOpStartSeq_lpcm(): channelNumber=%d, sampleRate=%d, sizeOfWord=%d, audioPayloadSize=0x%x", lpcmParam->channelNumber, lpcmParam->sampleRate, lpcmParam->sizeOfWord, lpcmParam->audioPayloadSize); + + if (lpcmParam->channelNumber >= 0x20u || lpcmParam->sampleRate >= 0x20u || lpcmParam->sizeOfWord >= 0x20u || lpcmParam->audioPayloadSize == 0u) + { + return CELL_ADEC_ERROR_LPCM_ARG; + } + + return handle->send_command(ppu, *lpcmParam); } -error_code _CellAdecCoreOpEndSeq_lpcm(vm::ptr handle) +error_code _CellAdecCoreOpEndSeq_lpcm(ppu_thread& ppu, vm::ptr handle) { - cellAdec.todo("_CellAdecCoreOpEndSeq_lpcm(handle=*0x%x)", handle); + cellAdec.notice("_CellAdecCoreOpEndSeq_lpcm(handle=*0x%x)", handle); - return CELL_OK; + ensure(!!handle); // Not checked on LLE + + return handle->send_command(ppu); } -error_code _CellAdecCoreOpDecodeAu_lpcm(vm::ptr handle, s32 pcmHandle, vm::ptr auInfo) +error_code _CellAdecCoreOpDecodeAu_lpcm(ppu_thread& ppu, vm::ptr handle, s32 pcmHandle, vm::ptr auInfo) { - cellAdec.todo("_CellAdecCoreOpDecodeAu_lpcm(handle=*0x%x, pcmHandle=%d, auInfo=*0x%x)", handle, pcmHandle, auInfo); + cellAdec.trace("_CellAdecCoreOpDecodeAu_lpcm(handle=*0x%x, pcmHandle=%d, auInfo=*0x%x)", handle, pcmHandle, auInfo); - return CELL_OK; + ensure(!!handle && !!auInfo); // Not checked on LLE + + cellAdec.trace("_CellAdecCoreOpDecodeAu_lpcm(): startAddr=*0x%x, size=0x%x, pts=0x%x, userData=0x%016x", auInfo->startAddr, auInfo->size, std::bit_cast>(auInfo->pts), auInfo->userData); + + return handle->send_command(ppu, pcmHandle, *auInfo); } void _CellAdecCoreOpGetVersion_lpcm(vm::ptr> version) @@ -285,18 +963,35 @@ void _CellAdecCoreOpGetVersion_lpcm(vm::ptr> version) *version = 0x20070323; } -error_code _CellAdecCoreOpRealign_lpcm(vm::ptr handle, vm::ptr outBuffer, vm::cptr pcmStartAddr) +error_code _CellAdecCoreOpRealign_lpcm(vm::ptr handle, vm::ptr outBuffer, vm::cptr pcmStartAddr) { - cellAdec.todo("_CellAdecCoreOpRealign_lpcm(handle=*0x%x, outBuffer=*0x%x, pcmStartAddr=*0x%x)", handle, outBuffer, pcmStartAddr); + cellAdec.trace("_CellAdecCoreOpRealign_lpcm(handle=*0x%x, outBuffer=*0x%x, pcmStartAddr=*0x%x)", handle, outBuffer, pcmStartAddr); + + if (!pcmStartAddr) + { + return CELL_ADEC_ERROR_LPCM_ARG; + } + + if (outBuffer) + { + ensure(!!handle); // Not checked on LLE + ensure(vm::check_addr(outBuffer.addr(), vm::page_info_t::page_writable, handle->output_size)); + + std::memcpy(outBuffer.get_ptr(), pcmStartAddr.get_ptr(), handle->output_size); + } return CELL_OK; } -error_code _CellAdecCoreOpReleasePcm_lpcm(vm::ptr handle, s32 pcmHandle, vm::ptr outBuffer) +error_code _CellAdecCoreOpReleasePcm_lpcm(ppu_thread& ppu, vm::ptr handle, s32 pcmHandle, vm::ptr outBuffer) { - cellAdec.todo("_CellAdecCoreOpReleasePcm_lpcm(handle=*0x%x, pcmHandle=%d, outBuffer=*0x%x)", handle, pcmHandle, outBuffer); + ppu.state += cpu_flag::wait; - return CELL_OK; + cellAdec.trace("_CellAdecCoreOpReleasePcm_lpcm(handle=*0x%x, pcmHandle=%d, outBuffer=*0x%x)", handle, pcmHandle, outBuffer); + + ensure(!!handle); // Not checked on LLE + + return handle->release_output(ppu); } s32 _CellAdecCoreOpGetPcmHandleNum_lpcm() @@ -544,8 +1239,8 @@ error_code AdecContext::correct_pts_value(ppu_thread& ppu, s32 pcm_handle, s8 co { switch (correct_pts_type) { - case ADEC_CORRECT_PTS_VALUE_TYPE_LPCM: return 450; - case 1: return 150; + case ADEC_CORRECT_PTS_VALUE_TYPE_LPCM_HDMV: return 450; + case ADEC_CORRECT_PTS_VALUE_TYPE_LPCM_DVD: return 150; case ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz: return 3840; case ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz: return 4180; case ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz: return 5760; @@ -800,6 +1495,15 @@ error_code adecOpen(ppu_thread& ppu, vm::ptr type, vm::cptraudioCodecType); + // Block savestate creation during ppu_thread::fast_call() + std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; + + if (!savestate_lock.owns_lock()) + { + ppu.state += cpu_flag::again; + return {}; + } + const s32 pcm_handle_num = core_ops->getPcmHandleNum(ppu); const u32 bitstream_info_size = core_ops->getBsiInfoSize(ppu); @@ -810,11 +1514,11 @@ error_code adecOpen(ppu_thread& ppu, vm::ptr type, vm::cptraudioCodecType == CELL_ADEC_TYPE_LPCM_DVD) { - // TODO + vm::static_ptr_cast(core_handle)->dvd_packing = true; } else if (type->audioCodecType == CELL_ADEC_TYPE_LPCM_PAMF || type->audioCodecType == CELL_ADEC_TYPE_LPCM_BLURAY) { - // TODO + vm::static_ptr_cast(core_handle)->dvd_packing = false; } _this->_this = _this; @@ -862,15 +1566,6 @@ error_code adecOpen(ppu_thread& ppu, vm::ptr type, vm::cptr::make(g_fxo->get().func_addr(FIND_FUNC(adecNotifyError))); const auto notifySeqDone = vm::ptr::make(g_fxo->get().func_addr(FIND_FUNC(adecNotifySeqDone))); - // Block savestate creation during ppu_thread::fast_call() - std::unique_lock savestate_lock{g_fxo->get(), std::try_to_lock}; - - if (!savestate_lock.owns_lock()) - { - ppu.state += cpu_flag::again; - return {}; - } - if (spursRes) { return core_ops->openExt(ppu, _this->core_handle, notifyAuDone, _this, notifyPcmOut, _this, notifyError, _this, notifySeqDone, _this, res, spursRes); @@ -1013,6 +1708,177 @@ error_code cellAdecEndSeq(ppu_thread& ppu, vm::ptr handle) return handle->core_ops->endSeq(ppu, handle->core_handle); } +error_code adecSetLpcmBlurayParams(vm::ptr handle, u64 userData) +{ + const u8 channel_number = static_cast(userData >> 32); + const u8 sample_rate = static_cast(userData >> 40); + const u8 size_of_word = static_cast(userData >> 48); + const u8 unk = static_cast(userData >> 56); + + handle->lpcm_param->channelNumber = channel_number; + handle->lpcm_param->sampleRate = sample_rate; + handle->lpcm_param->sizeOfWord = size_of_word; + + u32 allocated_channels; + + switch (channel_number) + { + case CELL_ADEC_CH_MONO: + case CELL_ADEC_CH_STEREO: + allocated_channels = 2; + break; + + case CELL_ADEC_CH_3_0: + case CELL_ADEC_CH_2_1: + case CELL_ADEC_CH_3_1: + case CELL_ADEC_CH_2_2: + allocated_channels = 4; + break; + + case CELL_ADEC_CH_3_2: + case CELL_ADEC_CH_3_2_LFE: + allocated_channels = 6; + break; + + case CELL_ADEC_CH_3_4: + case CELL_ADEC_CH_3_4_LFE: + allocated_channels = 8; + break; + + default: + return CELL_ADEC_ERROR_FATAL; + } + + u32 samples_per_frame; + + switch (sample_rate) + { + case CELL_ADEC_FS_48kHz: samples_per_frame = 48000 / 200; break; + case CELL_ADEC_FS_96kHz: samples_per_frame = 96000 / 200; break; + case CELL_ADEC_FS_192kHz: samples_per_frame = 192000 / 200; break; + default: return CELL_ADEC_ERROR_FATAL; + } + + u32 allocated_bytes_per_sample; + + switch (size_of_word) + { + case CELL_ADEC_BIT_LENGTH_16: allocated_bytes_per_sample = 2; break; + case CELL_ADEC_BIT_LENGTH_20: // Same as below + case CELL_ADEC_BIT_LENGTH_24: allocated_bytes_per_sample = 3; break; + default: return CELL_ADEC_ERROR_FATAL; + } + + handle->lpcm_param->audioPayloadSize = allocated_bytes_per_sample * allocated_channels * samples_per_frame * unk; + + return CELL_OK; +} + +error_code adecSetLpcmDvdParams(vm::ptr handle, u64 userData) +{ + const u8 channel_layout = static_cast(userData >> 32); + const u8 sample_rate = static_cast(userData >> 40); + const u8 size_of_word = static_cast(userData >> 48); + const u8 unk = static_cast(userData >> 56); + + handle->lpcm_param->channelNumber = channel_layout; + handle->lpcm_param->sampleRate = sample_rate; + handle->lpcm_param->sizeOfWord = size_of_word; + + u32 samples_per_frame; + + switch (sample_rate) + { + case CELL_ADEC_FS_48kHz: samples_per_frame = 48000 / 600; break; + case CELL_ADEC_FS_96kHz: samples_per_frame = 96000 / 600; break; + default: return CELL_ADEC_ERROR_FATAL; + } + + u32 bits_per_sample; + + switch (size_of_word) + { + case CELL_ADEC_BIT_LENGTH_16: bits_per_sample = 16; break; + case CELL_ADEC_BIT_LENGTH_20: bits_per_sample = 20; break; + case CELL_ADEC_BIT_LENGTH_24: bits_per_sample = 24; break; + default: return CELL_ADEC_ERROR_FATAL; + } + + u32 channel_number; + + switch (channel_layout) + { + case CELL_ADEC_LPCM_DVD_CH_MONO: + channel_number = 1; + break; + + case CELL_ADEC_LPCM_DVD_CH_STEREO: + channel_number = 2; + break; + + case 4: + if (sample_rate == CELL_ADEC_FS_96kHz && size_of_word == CELL_ADEC_BIT_LENGTH_24) + { + return CELL_ADEC_ERROR_FATAL; + } + + channel_number = 3; + break; + + case 5: + if (sample_rate == CELL_ADEC_FS_96kHz && size_of_word != CELL_ADEC_BIT_LENGTH_16) + { + return CELL_ADEC_ERROR_FATAL; + } + + channel_number = 4; + break; + + case CELL_ADEC_LPCM_DVD_CH_3_2: + if (sample_rate == CELL_ADEC_FS_96kHz) + { + return CELL_ADEC_ERROR_FATAL; + } + + channel_number = 5; + break; + + case CELL_ADEC_LPCM_DVD_CH_3_2_LFE: + if (sample_rate == CELL_ADEC_FS_96kHz || size_of_word == CELL_ADEC_BIT_LENGTH_24) + { + return CELL_ADEC_ERROR_FATAL; + } + + channel_number = 6; + break; + + case CELL_ADEC_LPCM_DVD_CH_3_4: + if (sample_rate == CELL_ADEC_FS_96kHz || size_of_word != CELL_ADEC_BIT_LENGTH_16) + { + return CELL_ADEC_ERROR_FATAL; + } + + channel_number = 7; + break; + + case CELL_ADEC_LPCM_DVD_CH_3_4_LFE: + if (sample_rate == CELL_ADEC_FS_96kHz || size_of_word != CELL_ADEC_BIT_LENGTH_16) + { + return CELL_ADEC_ERROR_FATAL; + } + + channel_number = 8; + break; + + default: + return CELL_ADEC_ERROR_FATAL; + } + + handle->lpcm_param->audioPayloadSize = bits_per_sample * channel_number * samples_per_frame / 8 * unk; + + return CELL_OK; +} + error_code cellAdecDecodeAu(ppu_thread& ppu, vm::ptr handle, vm::ptr auInfo) { // Block savestate creation during ppu_thread::fast_call() @@ -1052,11 +1918,17 @@ error_code cellAdecDecodeAu(ppu_thread& ppu, vm::ptr handle, vm::pt if (handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_BLURAY) { - // TODO + if (adecSetLpcmBlurayParams(vm::static_ptr_cast(handle->core_handle), auInfo->userData) != CELL_OK) + { + return CELL_ADEC_ERROR_FATAL; + } } else if (handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_DVD) { - // TODO + if (adecSetLpcmDvdParams(vm::static_ptr_cast(handle->core_handle), auInfo->userData) != CELL_OK) + { + return CELL_ADEC_ERROR_FATAL; + } } return handle->core_ops->decodeAu(ppu, handle->core_handle, pcmHandle, auInfo); @@ -1104,7 +1976,7 @@ error_code cellAdecGetPcm(ppu_thread& ppu, vm::ptr handle, vm::ptr< if (handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_PAMF || handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_BLURAY || handle->type.audioCodecType == CELL_ADEC_TYPE_LPCM_DVD) { - // TODO + vm::static_ptr_cast(handle->core_handle)->output_size = pcm_item->size; } if (error_code ret = handle->core_ops->realign(ppu, handle->core_handle, outBuffer, pcm_queue_entry->pcm_item->startAddr); ret != CELL_OK) @@ -1206,6 +2078,8 @@ DECLARE(ppu_module_manager::cellAdec)("cellAdec", []() REG_HIDDEN_FUNC(_CellAdecCoreOpGetPcmHandleNum_lpcm); REG_HIDDEN_FUNC(_CellAdecCoreOpGetBsiInfoSize_lpcm); REG_HIDDEN_FUNC(_CellAdecCoreOpOpenExt_lpcm); + + REG_HIDDEN_FUNC(lpcmDecEntry); }); DECLARE(ppu_module_manager::cell_libac3dec)("cell_libac3dec", [] diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.h b/rpcs3/Emu/Cell/Modules/cellAdec.h index 1cbeca08b8..a43c3f0aef 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.h +++ b/rpcs3/Emu/Cell/Modules/cellAdec.h @@ -253,7 +253,7 @@ enum CellAdecSampleRate : s32 CELL_ADEC_FS_8kHz, }; -enum CellAdecBitLength : s32 +enum CellAdecBitLength : u32 { CELL_ADEC_BIT_LENGTH_RESERVED1, CELL_ADEC_BIT_LENGTH_16, @@ -352,8 +352,8 @@ enum AdecCorrectPtsValueType : s8 ADEC_CORRECT_PTS_VALUE_TYPE_UNSPECIFIED = -1, // Adds a fixed amount - ADEC_CORRECT_PTS_VALUE_TYPE_LPCM = 0, - // 1 + ADEC_CORRECT_PTS_VALUE_TYPE_LPCM_HDMV = 0, + ADEC_CORRECT_PTS_VALUE_TYPE_LPCM_DVD = 1, // Unused for some reason, the DVD player probably takes care of timestamps itself ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz = 2, ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz = 3, ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz = 4, @@ -562,6 +562,11 @@ public: { ensure(sys_mutex_lock(ppu, mutex, 0) == CELL_OK); // Error code isn't checked on LLE + if (ppu.state & cpu_flag::again) // Savestate was created while waiting on the mutex + { + return {}; + } + if (entries[front].state == 0xff) { ensure(sys_mutex_unlock(ppu, mutex) == CELL_OK); // Error code isn't checked on LLE @@ -648,6 +653,20 @@ static_assert(std::is_standard_layout_v && std::is_trivial_v channelNumber; @@ -664,6 +683,216 @@ struct CellAdecLpcmInfo be_t outputDataSize; }; +// HLE exclusive, for savestates +enum class lpcm_dec_state : u8 +{ + waiting_for_cmd_mutex_lock, + waiting_for_cmd_cond_wait, + waiting_for_output_mutex_lock, + waiting_for_output_cond_wait, + queue_mutex_lock, + executing_cmd +}; + +class LpcmDecSemaphore +{ + be_t value; + be_t mutex; // sys_mutex_t + be_t cond; // sys_cond_t + +public: + error_code init(ppu_thread& ppu, vm::ptr _this, u32 initial_value) + { + value = initial_value; + + const vm::var mutex_attr{{ SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, SYS_SYNC_NOT_PROCESS_SHARED, SYS_SYNC_NOT_ADAPTIVE, 0, 0, 0, { "_adem01"_u64 } }}; + const vm::var cond_attr{{ SYS_SYNC_NOT_PROCESS_SHARED, 0, 0, { "_adec01"_u64 } }}; + + if (error_code ret = sys_mutex_create(ppu, _this.ptr(&LpcmDecSemaphore::mutex), mutex_attr); ret != CELL_OK) + { + return ret; + } + + return sys_cond_create(ppu, _this.ptr(&LpcmDecSemaphore::cond), mutex, cond_attr); + } + + error_code finalize(ppu_thread& ppu) const + { + if (error_code ret = sys_cond_destroy(ppu, cond); ret != CELL_OK) + { + return ret; + } + + return sys_mutex_destroy(ppu, mutex); + } + + error_code release(ppu_thread& ppu) + { + if (error_code ret = sys_mutex_lock(ppu, mutex, 0); ret != CELL_OK) + { + return ret; + } + + value++; + + if (error_code ret = sys_cond_signal(ppu, cond); ret != CELL_OK) + { + return ret; // LLE doesn't unlock the mutex + } + + return sys_mutex_unlock(ppu, mutex); + } + + error_code acquire(ppu_thread& ppu, lpcm_dec_state& savestate) + { + if (savestate == lpcm_dec_state::waiting_for_cmd_cond_wait) + { + goto cond_wait; + } + + savestate = lpcm_dec_state::waiting_for_cmd_mutex_lock; + + if (error_code ret = sys_mutex_lock(ppu, mutex, 0); ret != CELL_OK) + { + return ret; + } + + if (ppu.state & cpu_flag::again) + { + return {}; + } + + if (value == 0u) + { + savestate = lpcm_dec_state::waiting_for_cmd_cond_wait; + cond_wait: + + if (error_code ret = sys_cond_wait(ppu, cond, 0); ret != CELL_OK) + { + return ret; // LLE doesn't unlock the mutex + } + + if (ppu.state & cpu_flag::again) + { + return {}; + } + } + + value--; + + return sys_mutex_unlock(ppu, mutex); + } +}; + +CHECK_SIZE(LpcmDecSemaphore, 0xc); + +enum class LpcmDecCmdType : u32 +{ + start_seq, + end_seq, + decode_au, + close +}; + +struct LpcmDecCmd +{ + be_t pcm_handle; + vm::bcptr au_start_addr; + be_t au_size; + u32 reserved1[2]; + CellAdecParamLpcm lpcm_param; + be_t type; + u32 reserved2; + + LpcmDecCmd() = default; // cellAdecOpen() + + LpcmDecCmd(LpcmDecCmdType&& type) // End sequence + : type(type) + { + } + + LpcmDecCmd(LpcmDecCmdType&& type, const CellAdecParamLpcm& lpcm_param) // Start sequence + : lpcm_param(lpcm_param), type(type) + { + } + + LpcmDecCmd(LpcmDecCmdType&& type, const s32& pcm_handle, const CellAdecAuInfo& au_info) // Decode au + : pcm_handle(pcm_handle), au_start_addr(au_info.startAddr), au_size(au_info.size), type(type) + { + } +}; + +CHECK_SIZE(LpcmDecCmd, 0x2c); + +struct LpcmDecContext +{ + AdecCmdQueue cmd_queue; + + be_t thread_id; // sys_ppu_thread_t + + be_t queue_size_mutex; // sys_mutex_t + be_t queue_size_cond; // sys_cond_t, unused + be_t unk_mutex; // sys_mutex_t, unused + be_t unk_cond; // sys_cond_t, unused + + be_t run_thread; + + AdecCb notify_au_done; + AdecCb notify_pcm_out; + AdecCb notify_error; + AdecCb notify_seq_done; + + be_t output_locked; + vm::bptr output; + + vm::bptr lpcm_param; + + vm::bcptr spurs_cmd_data; + + // HLE exclusive + lpcm_dec_state savestate; + u64 cmd_counter; // For debugging + + u8 reserved1[24]; // 36 bytes on LLE + + be_t output_mutex; // sys_mutex_t + be_t output_consumed; // sys_cond_t + + LpcmDecSemaphore cmd_available; + LpcmDecSemaphore reserved2; // Unused + + be_t queue_mutex; // sys_mutex_t + + be_t error_occurred; + + u8 spurs_stuff[32]; + + be_t spurs_queue_pop_mutex; + be_t spurs_queue_push_mutex; + + be_t using_existing_spurs_instance; + + be_t dvd_packing; + + be_t output_size; + + LpcmDecCmd cmd; // HLE exclusive, name of Spurs taskset (32 bytes) + CellSpursTaskLsPattern on LLE + + u8 more_spurs_stuff[10]; // 52 bytes on LLE + + void exec(ppu_thread& ppu); + + template + error_code send_command(ppu_thread& ppu, auto&&... args); + + inline error_code release_output(ppu_thread& ppu); +}; + +static_assert(std::is_standard_layout_v); +CHECK_SIZE_ALIGN(LpcmDecContext, 0x1c8, 8); + +constexpr s32 LPCM_DEC_OUTPUT_BUFFER_SIZE = 0x40000; + // CELP Excitation Mode enum CELP_ExcitationMode : s32 { diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index 8137e3b58f..2e31d37b6b 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -556,7 +556,7 @@ void cell_audio_thread::advance(u64 timestamp) m_dynamic_period = 0; // send aftermix event (normal audio event) - std::array, MAX_AUDIO_EVENT_QUEUES> queues; + std::array, MAX_AUDIO_EVENT_QUEUES> queues; u32 queue_count = 0; event_period++; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.h b/rpcs3/Emu/Cell/Modules/cellAudio.h index cab56aeef7..939b7f994c 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.h +++ b/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -400,7 +400,7 @@ public: u32 flags = 0; // iFlags u64 source = 0; // Event source u64 ack_timestamp = 0; // timestamp of last call of cellAudioSendAck - std::shared_ptr port{}; // Underlying event port + shared_ptr port{}; // Underlying event port }; std::vector keys{}; diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp index 89ab8ef9f9..64135ca5fa 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -784,26 +784,26 @@ s32 cellCameraIsAttached(s32 dev_num) if (g_cfg.io.camera == camera_handler::null) { - return false; + return 0; } auto& g_camera = g_fxo->get(); if (!g_camera.init) { - return false; + return 0; } if (!check_dev_num(dev_num)) { - return false; + return 0; } vm::var type; if (cellCameraGetType(dev_num, type) != CELL_OK) { - return false; + return 0; } std::lock_guard lock(g_camera.mutex); @@ -821,12 +821,12 @@ s32 cellCameraIsAttached(s32 dev_num) } } - return is_attached; + return is_attached ? 1 : 0; } s32 cellCameraIsOpen(s32 dev_num) { - cellCamera.notice("cellCameraIsOpen(dev_num=%d)", dev_num); + cellCamera.trace("cellCameraIsOpen(dev_num=%d)", dev_num); if (g_cfg.io.camera == camera_handler::null) { @@ -852,7 +852,7 @@ s32 cellCameraIsOpen(s32 dev_num) s32 cellCameraIsStarted(s32 dev_num) { - cellCamera.notice("cellCameraIsStarted(dev_num=%d)", dev_num); + cellCamera.trace("cellCameraIsStarted(dev_num=%d)", dev_num); if (g_cfg.io.camera == camera_handler::null) { diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.cpp b/rpcs3/Emu/Cell/Modules/cellDmux.cpp index 7850961aa9..5c94463ea3 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmux.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDmux.cpp @@ -1031,7 +1031,7 @@ error_code cellDmuxClose(u32 handle) { cellDmux.warning("cellDmuxClose(handle=0x%x)", handle); - const auto dmux = idm::get(handle); + const auto dmux = idm::get_unlocked(handle); if (!dmux) { @@ -1060,7 +1060,7 @@ error_code cellDmuxSetStream(u32 handle, u32 streamAddress, u32 streamSize, b8 d { cellDmux.trace("cellDmuxSetStream(handle=0x%x, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx)", handle, streamAddress, streamSize, discontinuity, userData); - const auto dmux = idm::get(handle); + const auto dmux = idm::get_unlocked(handle); if (!dmux) { @@ -1088,7 +1088,7 @@ error_code cellDmuxResetStream(u32 handle) { cellDmux.warning("cellDmuxResetStream(handle=0x%x)", handle); - const auto dmux = idm::get(handle); + const auto dmux = idm::get_unlocked(handle); if (!dmux) { @@ -1103,7 +1103,7 @@ error_code cellDmuxResetStreamAndWaitDone(u32 handle) { cellDmux.warning("cellDmuxResetStreamAndWaitDone(handle=0x%x)", handle); - const auto dmux = idm::get(handle); + const auto dmux = idm::get_unlocked(handle); if (!dmux) { @@ -1164,7 +1164,7 @@ error_code cellDmuxEnableEs(u32 handle, vm::cptr esFilterId { cellDmux.warning("cellDmuxEnableEs(handle=0x%x, esFilterId=*0x%x, esResourceInfo=*0x%x, esCb=*0x%x, esSpecificInfo=*0x%x, esHandle=*0x%x)", handle, esFilterId, esResourceInfo, esCb, esSpecificInfo, esHandle); - const auto dmux = idm::get(handle); + const auto dmux = idm::get_unlocked(handle); if (!dmux) { @@ -1194,7 +1194,7 @@ error_code cellDmuxDisableEs(u32 esHandle) { cellDmux.warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1213,7 +1213,7 @@ error_code cellDmuxResetEs(u32 esHandle) { cellDmux.trace("cellDmuxResetEs(esHandle=0x%x)", esHandle); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1232,7 +1232,7 @@ error_code cellDmuxGetAu(u32 esHandle, vm::ptr auInfo, vm::ptr auSpeci { cellDmux.trace("cellDmuxGetAu(esHandle=0x%x, auInfo=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfo, auSpecificInfo); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1255,7 +1255,7 @@ error_code cellDmuxPeekAu(u32 esHandle, vm::ptr auInfo, vm::ptr auSpec { cellDmux.trace("cellDmuxPeekAu(esHandle=0x%x, auInfo=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfo, auSpecificInfo); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1278,7 +1278,7 @@ error_code cellDmuxGetAuEx(u32 esHandle, vm::ptr auInfoEx, vm::ptr auS { cellDmux.trace("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfoEx, auSpecificInfo); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1301,7 +1301,7 @@ error_code cellDmuxPeekAuEx(u32 esHandle, vm::ptr auInfoEx, vm::ptr au { cellDmux.trace("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx=**0x%x, auSpecificInfo=**0x%x)", esHandle, auInfoEx, auSpecificInfo); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1324,7 +1324,7 @@ error_code cellDmuxReleaseAu(u32 esHandle) { cellDmux.trace("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { @@ -1342,7 +1342,7 @@ error_code cellDmuxFlushEs(u32 esHandle) { cellDmux.warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle); - const auto es = idm::get(esHandle); + const auto es = idm::get_unlocked(esHandle); if (!es) { diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index fcc0810b3e..bff73f530b 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -598,7 +598,7 @@ error_code cellFsSetIoBufferFromDefaultContainer(u32 fd, u32 buffer_size, u32 pa { cellFs.todo("cellFsSetIoBufferFromDefaultContainer(fd=%d, buffer_size=%d, page_type=%d)", fd, buffer_size, page_type); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -695,7 +695,7 @@ s32 cellFsStReadInit(u32 fd, vm::cptr ringbuf) return CELL_EINVAL; } - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -716,7 +716,7 @@ s32 cellFsStReadFinish(u32 fd) { cellFs.todo("cellFsStReadFinish(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -732,7 +732,7 @@ s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr ringbuf) { cellFs.todo("cellFsStReadGetRingBuf(fd=%d, ringbuf=*0x%x)", fd, ringbuf); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -748,7 +748,7 @@ s32 cellFsStReadGetStatus(u32 fd, vm::ptr status) { cellFs.todo("cellFsStReadGetRingBuf(fd=%d, status=*0x%x)", fd, status); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -764,7 +764,7 @@ s32 cellFsStReadGetRegid(u32 fd, vm::ptr regid) { cellFs.todo("cellFsStReadGetRingBuf(fd=%d, regid=*0x%x)", fd, regid); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -780,7 +780,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) { cellFs.todo("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -796,7 +796,7 @@ s32 cellFsStReadStop(u32 fd) { cellFs.todo("cellFsStReadStop(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -812,7 +812,7 @@ s32 cellFsStRead(u32 fd, vm::ptr buf, u64 size, vm::ptr rsize) { cellFs.todo("cellFsStRead(fd=%d, buf=*0x%x, size=0x%llx, rsize=*0x%x)", fd, buf, size, rsize); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -828,7 +828,7 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) { cellFs.todo("cellFsStReadGetCurrentAddr(fd=%d, addr=*0x%x, size=*0x%x)", fd, addr, size); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -844,7 +844,7 @@ s32 cellFsStReadPutCurrentAddr(u32 fd, vm::ptr addr, u64 size) { cellFs.todo("cellFsStReadPutCurrentAddr(fd=%d, addr=*0x%x, size=0x%llx)", fd, addr, size); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -860,7 +860,7 @@ s32 cellFsStReadWait(u32 fd, u64 size) { cellFs.todo("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -876,7 +876,7 @@ s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr { cellFs.todo("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func=*0x%x)", fd, size, func); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -908,7 +908,7 @@ struct fs_aio_thread : ppu_thread s32 error = CELL_EBADF; u64 result = 0; - const auto file = idm::get(aio->fd); + const auto file = idm::get_unlocked(aio->fd); if (!file || (type == 1 && file->flags & CELL_FS_O_WRONLY) || (type == 2 && !(file->flags & CELL_FS_O_ACCMODE))) { diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 4ddc29d639..6534d07677 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -961,7 +961,7 @@ error_code cellGameContentPermit(ppu_thread& ppu, vm::ptr> lv2_files; + std::vector> lv2_files; const std::string real_dir = vfs::get(dir) + "/"; diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 44606b7dd1..426d025950 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -455,7 +455,7 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr contex vm::var _tid; vm::var _name = vm::make_str("_gcm_intr_thread"); ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 0x10000, 0, 1, 0x4000, SYS_PPU_THREAD_CREATE_INTERRUPT, +_name); - render->intr_thread = idm::get>(static_cast(*_tid)); + render->intr_thread = idm::get_unlocked>(static_cast(*_tid)); render->intr_thread->state -= cpu_flag::stop; thread_ctrl::notify(*render->intr_thread); diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index df621efef3..f7d274c4d0 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -189,10 +189,12 @@ public: struct gem_color { - float r, g, b; + ENABLE_BITWISE_SERIALIZATION; + + f32 r, g, b; gem_color() : r(0.0f), g(0.0f), b(0.0f) {} - gem_color(float r_, float g_, float b_) + gem_color(f32 r_, f32 g_, f32 b_) { r = std::clamp(r_, 0.0f, 1.0f); g = std::clamp(g_, 0.0f, 1.0f); @@ -223,7 +225,7 @@ public: u32 ext_status = CELL_GEM_NO_EXTERNAL_PORT_DEVICE; // External port connection status u32 ext_id = 0; // External device ID (type). For example SHARP_SHOOTER_DEVICE_ID u32 port = 0; // Assigned port - bool enabled_magnetometer = false; // Whether the magnetometer is enabled (probably used for additional rotational precision) + bool enabled_magnetometer = true; // Whether the magnetometer is enabled (probably used for additional rotational precision) bool calibrated_magnetometer = false; // Whether the magnetometer is calibrated bool enabled_filtering = false; // Whether filtering is enabled bool enabled_tracking = false; // Whether tracking is enabled @@ -238,17 +240,16 @@ public: bool is_calibrating{false}; // Whether or not we are currently calibrating u64 calibration_start_us{0}; // The start timestamp of the calibration in microseconds + u64 calibration_status_flags = 0; // The calibration status flags static constexpr u64 calibration_time_us = 500000; // The calibration supposedly takes 0.5 seconds (500000 microseconds) - - ENABLE_BITWISE_SERIALIZATION; }; CellGemAttribute attribute = {}; CellGemVideoConvertAttribute vc_attribute = {}; s32 video_data_out_size = -1; std::vector video_data_in; - u64 status_flags = 0; + u64 runtime_status_flags = 0; // The runtime status flags bool enable_pitch_correction = false; u32 inertial_counter = 0; @@ -269,25 +270,60 @@ public: return controllers[gem_num].status == CELL_GEM_STATUS_READY; } - bool is_controller_calibrating(u32 gem_num) + void update_calibration_status() { - gem_controller& gem = controllers[gem_num]; + std::scoped_lock lock(mtx); - if (gem.is_calibrating) + for (u32 gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++) { - if ((get_guest_system_time() - gem.calibration_start_us) >= gem_controller::calibration_time_us) - { - gem.is_calibrating = false; - gem.calibration_start_us = 0; - gem.calibrated_magnetometer = true; - gem.enabled_tracking = true; - gem.hue = 1; + gem_controller& controller = controllers[gem_num]; + if (!controller.is_calibrating) continue; - status_flags = CELL_GEM_FLAG_CALIBRATION_SUCCEEDED | CELL_GEM_FLAG_CALIBRATION_OCCURRED; + bool controller_calibrated = true; + + // Request controller calibration + if (g_cfg.io.move == move_handler::real) + { + std::lock_guard pad_lock(pad::g_pad_mutex); + const auto handler = pad::get_current_handler(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + if (pad && pad->m_pad_handler == pad_handler::move) + { + if (!pad->move_data.calibration_requested || !pad->move_data.calibration_succeeded) + { + pad->move_data.calibration_requested = true; + controller_calibrated = false; + } + } + } + + // The calibration takes ~0.5 seconds on real hardware + if ((get_guest_system_time() - controller.calibration_start_us) < gem_controller::calibration_time_us) continue; + + if (!controller_calibrated) + { + cellGem.warning("Reached calibration timeout but ps move controller %d is still calibrating", gem_num); + } + + controller.is_calibrating = false; + controller.calibration_start_us = 0; + controller.calibration_status_flags = CELL_GEM_FLAG_CALIBRATION_SUCCEEDED | CELL_GEM_FLAG_CALIBRATION_OCCURRED; + controller.calibrated_magnetometer = true; + controller.enabled_tracking = true; + + // Reset controller calibration request + if (g_cfg.io.move == move_handler::real) + { + std::lock_guard pad_lock(pad::g_pad_mutex); + const auto handler = pad::get_current_handler(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + if (pad && pad->m_pad_handler == pad_handler::move) + { + pad->move_data.calibration_requested = false; + pad->move_data.calibration_succeeded = false; + } } } - - return gem.is_calibrating; } void reset_controller(u32 gem_num) @@ -297,6 +333,10 @@ public: return; } + gem_controller& controller = ::at32(controllers, gem_num); + controller = {}; + controller.sphere_rgb = gem_color::get_default_color(gem_num); + bool is_connected = false; switch (g_cfg.io.move) @@ -315,6 +355,7 @@ public: if (gem_num == i) { + pad->move_data.magnetometer_enabled = controller.enabled_magnetometer; is_connected = true; } } @@ -377,10 +418,6 @@ public: break; } - gem_controller& controller = ::at32(controllers, gem_num); - controller = {}; - controller.sphere_rgb = gem_color::get_default_color(gem_num); - // Assign status and port number if (is_connected) { @@ -389,20 +426,11 @@ public: } } + void paint_spheres(CellGemVideoConvertFormatEnum output_format, u32 width, u32 height, u8* video_data_out, u32 video_data_out_size); + gem_config_data() { - if (!g_cfg_gem_real.load()) - { - cellGem.notice("Could not load real gem config. Using defaults."); - } - - if (!g_cfg_gem_fake.load()) - { - cellGem.notice("Could not load fake gem config. Using defaults."); - } - - cellGem.notice("Real gem config=\n", g_cfg_gem_real.to_string()); - cellGem.notice("Fake gem config=\n", g_cfg_gem_fake.to_string()); + load_configs(); }; SAVESTATE_INIT_POS(15); @@ -416,19 +444,46 @@ public: return; } - [[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellGem); + const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellGem); - ar(attribute, vc_attribute, status_flags, enable_pitch_correction, inertial_counter, controllers - , connected_controllers, updating, camera_frame, memory_ptr, start_timestamp_us); + ar(attribute, vc_attribute, runtime_status_flags, enable_pitch_correction, inertial_counter); + + for (gem_controller& c : controllers) + { + ar(c.status, c.ext_status, c.ext_id, c.port, c.enabled_magnetometer, c.calibrated_magnetometer, c.enabled_filtering, c.enabled_tracking, c.enabled_LED, c.hue_set, c.rumble); + + // We need to add padding because we used bitwise serialization in version 1 + if (version < 2) + { + ar.add_padding(&gem_controller::rumble, &gem_controller::sphere_rgb); + } + + ar(c.sphere_rgb, c.hue, c.distance_mm, c.radius, c.radius_valid, c.is_calibrating); + + if (version < 2) + { + ar.add_padding(&gem_controller::is_calibrating, &gem_controller::calibration_start_us); + } + + ar(c.calibration_start_us); + + if (ar.is_writing() || version >= 2) + { + ar(c.calibration_status_flags); + } + } + + ar(connected_controllers, updating, camera_frame, memory_ptr, start_timestamp_us); } gem_config_data(utils::serial& ar) { save(ar); + load_configs(); + } - if (ar.is_writing()) - return; - + static void load_configs() + { if (!g_cfg_gem_real.load()) { cellGem.notice("Could not load real gem config. Using defaults."); @@ -447,7 +502,7 @@ public: extern std::pair get_video_resolution(const CellCameraInfoEx& info); extern u32 get_buffer_size_by_format(s32 format, s32 width, s32 height); -static inline int32_t cellGemGetVideoConvertSize(s32 output_format) +static inline s32 cellGemGetVideoConvertSize(s32 output_format) { switch (output_format) { @@ -474,6 +529,29 @@ static inline int32_t cellGemGetVideoConvertSize(s32 output_format) namespace gem { + struct gem_position + { + public: + void set_position(f32 x, f32 y) + { + std::lock_guard lock(m_mutex); + m_x = x; + m_y = y; + } + void get_position(f32& x, f32& y) + { + std::lock_guard lock(m_mutex); + x = m_x; + y = m_y; + } + private: + std::mutex m_mutex; + f32 m_x = 0.0f; + f32 m_y = 0.0f; + }; + + std::array positions {}; + bool convert_image_format(CellCameraFormat input_format, CellGemVideoConvertFormatEnum output_format, const std::vector& video_data_in, u32 width, u32 height, u8* video_data_out, u32 video_data_out_size) @@ -524,15 +602,15 @@ namespace gem u8* dst0 = dst_row; u8* dst1 = dst_row + out_pitch; - for (uint32_t x = 0; x < width - 1; x += 2, src0 += 2, src1 += 2, dst0 += 8, dst1 += 8) + for (u32 x = 0; x < width - 1; x += 2, src0 += 2, src1 += 2, dst0 += 8, dst1 += 8) { - const uint8_t b = src0[0]; - const uint8_t g0 = src0[1]; - const uint8_t g1 = src1[0]; - const uint8_t r = src1[1]; + const u8 b = src0[0]; + const u8 g0 = src0[1]; + const u8 g1 = src1[0]; + const u8 r = src1[1]; - const uint8_t top[4] = { r, g0, b, 255 }; - const uint8_t bottom[4] = { r, g1, b, 255 }; + const u8 top[4] = { r, g0, b, 255 }; + const u8 bottom[4] = { r, g1, b, 255 }; // Top-Left std::memcpy(dst0, top, 4); @@ -602,6 +680,101 @@ namespace gem } } +void gem_config_data::paint_spheres(CellGemVideoConvertFormatEnum output_format, u32 width, u32 height, u8* video_data_out, u32 video_data_out_size) +{ + if (!width || !height || !video_data_out || !video_data_out_size) + { + return; + } + + struct sphere_information + { + f32 radius = 0.0f; + s16 x = 0; + s16 y = 0; + u8 r = 0; + u8 g = 0; + u8 b = 0; + }; + + std::vector sphere_info; + { + reader_lock lock(mtx); + + for (u32 gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++) + { + const gem_config_data::gem_controller& controller = controllers[gem_num]; + if (!controller.radius_valid || controller.radius <= 0.0f) continue; + + f32 x, y; + ::at32(gem::positions, gem_num).get_position(x, y); + + const u8 r = static_cast(std::clamp(controller.sphere_rgb.r * 255.0f, 0.0f, 255.0f)); + const u8 g = static_cast(std::clamp(controller.sphere_rgb.g * 255.0f, 0.0f, 255.0f)); + const u8 b = static_cast(std::clamp(controller.sphere_rgb.b * 255.0f, 0.0f, 255.0f)); + + sphere_info.push_back({ controller.radius, static_cast(x), static_cast(y), r, g, b }); + } + } + + switch (output_format) + { + case CELL_GEM_RGBA_640x480: // RGBA output; 640*480*4-byte output buffer required + { + cellGem.trace("Painting spheres for CELL_GEM_RGBA_640x480"); + + const u32 out_pitch = width * 4; + + for (const sphere_information& info : sphere_info) + { + const s32 x_begin = std::max(0, static_cast(std::floor(info.x - info.radius))); + const s32 x_end = std::min(width, static_cast(std::ceil(info.x + info.radius))); + const s32 y_begin = std::max(0, static_cast(std::floor(info.y - info.radius))); + const s32 y_end = std::min(height, static_cast(std::ceil(info.y + info.radius))); + + for (s32 y = y_begin; y < y_end; y++) + { + u8* dst = video_data_out + y * out_pitch + x_begin * 4; + + for (s32 x = x_begin; x < x_end; x++, dst += 4) + { + const f32 distance = static_cast(std::sqrt(std::pow(info.x - x, 2) + std::pow(info.y - y, 2))); + if (distance > info.radius) continue; + + dst[0] = info.r; + dst[1] = info.g; + dst[2] = info.b; + dst[3] = 255; + } + } + } + + break; + } + case CELL_GEM_BAYER_RESTORED: // Bayer pattern output, 640x480, gamma and white balance applied, output buffer required + case CELL_GEM_RGBA_320x240: // RGBA output; 320*240*4-byte output buffer required + case CELL_GEM_YUV_640x480: // YUV output; 640*480+640*480+640*480-byte output buffer required (contiguous) + case CELL_GEM_YUV422_640x480: // YUV output; 640*480+320*480+320*480-byte output buffer required (contiguous) + case CELL_GEM_YUV411_640x480: // YUV411 output; 640*480+320*240+320*240-byte output buffer required (contiguous) + case CELL_GEM_BAYER_RESTORED_RGGB: // Restored Bayer output, 2x2 pixels rearranged into 320x240 RG1G2B + case CELL_GEM_BAYER_RESTORED_RASTERIZED: // Restored Bayer output, R,G1,G2,B rearranged into 4 contiguous 320x240 1-channel rasters + { + cellGem.trace("Unimplemented: painting spheres for %s", output_format); + break; + } + case CELL_GEM_NO_VIDEO_OUTPUT: // Disable video output + { + cellGem.trace("Ignoring painting spheres for CELL_GEM_NO_VIDEO_OUTPUT"); + break; + } + default: + { + cellGem.trace("Ignoring painting spheres for %d", static_cast(output_format)); + break; + } + } +} + void gem_config_data::operator()() { cellGem.notice("Starting thread"); @@ -610,6 +783,11 @@ void gem_config_data::operator()() { while (!video_conversion_in_progress && thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped()) { + if (state) + { + update_calibration_status(); + } + thread_ctrl::wait_for(1000); } @@ -635,6 +813,11 @@ void gem_config_data::operator()() if (gem::convert_image_format(shared_data.format, vc.output_format, video_data_in, shared_data.width, shared_data.height, vc_attribute.video_data_out ? vc_attribute.video_data_out.get_ptr() : nullptr, video_data_out_size)) { cellGem.trace("Converted video frame of format %s to %s", shared_data.format.load(), vc.output_format.get()); + + if (g_cfg.io.paint_move_spheres) + { + paint_spheres(vc.output_format, shared_data.width, shared_data.height, vc_attribute.video_data_out ? vc_attribute.video_data_out.get_ptr() : nullptr, video_data_out_size); + } } video_conversion_in_progress = false; @@ -710,7 +893,7 @@ public: { if (g_cfg.io.move != move_handler::real) { - return 1; // potentially true if less than 20 pixels have the hue + return true; // potentially true if less than 20 pixels have the hue } return hue < m_hues.size() && m_hues[hue] < 20; // potentially true if less than 20 pixels have the hue @@ -763,7 +946,7 @@ public: std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); auto& handlers = handler->get_handlers(); - if (auto it = handlers.find(pad_handler::move); it != handlers.end()) + if (auto it = handlers.find(pad_handler::move); it != handlers.end() && it->second) { for (auto& binding : it->second->bindings()) { @@ -774,12 +957,22 @@ public: if (gem_num < 0 || gem_num >= CELL_GEM_MAX_NUM) continue; - const cfg_ps_move* config = ::at32(g_cfg_move.move, gem_num); - binding.device->color_override_active = true; - binding.device->color_override.r = config->r.get(); - binding.device->color_override.g = config->g.get(); - binding.device->color_override.b = config->b.get(); + + if (g_cfg.io.allow_move_hue_set_by_game) + { + const auto& controller = gem.controllers[gem_num]; + binding.device->color_override.r = static_cast(std::clamp(controller.sphere_rgb.r * 255.0f, 0.0f, 255.0f)); + binding.device->color_override.g = static_cast(std::clamp(controller.sphere_rgb.g * 255.0f, 0.0f, 255.0f)); + binding.device->color_override.b = static_cast(std::clamp(controller.sphere_rgb.b * 255.0f, 0.0f, 255.0f)); + } + else + { + const cfg_ps_move* config = ::at32(g_cfg_move.move, gem_num); + binding.device->color_override.r = config->r.get(); + binding.device->color_override.g = config->g.get(); + binding.device->color_override.b = config->b.get(); + } } } } @@ -791,13 +984,13 @@ public: const cfg_ps_move* config = g_cfg_move.move[gem_num]; m_tracker.set_active(gem_num, controller.enabled_tracking && controller.status == CELL_GEM_STATUS_READY); - m_tracker.set_hue(gem_num, config->hue); + m_tracker.set_hue(gem_num, g_cfg.io.allow_move_hue_set_by_game ? controller.hue : config->hue); m_tracker.set_hue_threshold(gem_num, config->hue_threshold); m_tracker.set_saturation_threshold(gem_num, config->saturation_threshold); } - m_tracker.set_min_radius(static_cast(g_cfg_move.min_radius.get() / g_cfg_move.min_radius.max)); - m_tracker.set_max_radius(static_cast(g_cfg_move.max_radius.get() / g_cfg_move.max_radius.max)); + m_tracker.set_min_radius(static_cast(g_cfg_move.min_radius) / 100.0f); + m_tracker.set_max_radius(static_cast(g_cfg_move.max_radius) / 100.0f); // Process camera image m_tracker.process_image(); @@ -902,6 +1095,11 @@ static inline void pos_to_gem_image_state(u32 gem_num, const gem_config::gem_con { draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max); } + + if (g_cfg.io.paint_move_spheres) + { + ::at32(gem::positions, gem_num).set_position(image_x, image_y); + } } static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr& gem_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max, const ps_move_data& move_data) @@ -946,19 +1144,20 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con // Calculate orientation if (g_cfg.io.move == move_handler::real) { - gem_state->quat[0] = move_data.quaternion[1]; // x - gem_state->quat[1] = move_data.quaternion[2]; // y - gem_state->quat[2] = move_data.quaternion[3]; // z - gem_state->quat[3] = move_data.quaternion[0]; // w + gem_state->quat[0] = move_data.quaternion[0]; // x + gem_state->quat[1] = move_data.quaternion[1]; // y + gem_state->quat[2] = move_data.quaternion[2]; // z + gem_state->quat[3] = move_data.quaternion[3]; // w } else { static constexpr f32 PI = 3.14159265f; const auto degree_to_rad = [](f32 degree) -> f32 { return degree * PI / 180.0f; }; - static constexpr f32 CONE = 10.0f / 2.0f; - const f32 roll = -degree_to_rad((image_y - half_height) / half_height * CONE); // This is actually the pitch - const f32 pitch = -degree_to_rad((image_x - half_width) / half_width * CONE); // This is actually the yaw + const f32 max_angle_per_side_h = g_cfg.io.fake_move_rotation_cone_h / 2.0f; + const f32 max_angle_per_side_v = g_cfg.io.fake_move_rotation_cone_v / 2.0f; + const f32 roll = -degree_to_rad((image_y - half_height) / half_height * max_angle_per_side_v); // This is actually the pitch + const f32 pitch = -degree_to_rad((image_x - half_width) / half_width * max_angle_per_side_h); // This is actually the yaw const f32 yaw = degree_to_rad(0.0f); const f32 cr = std::cos(roll * 0.5f); const f32 sr = std::sin(roll * 0.5f); @@ -982,6 +1181,11 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con { draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max); } + + if (g_cfg.io.paint_move_spheres) + { + ::at32(gem::positions, gem_num).set_position(image_x, image_y); + } } extern bool is_input_allowed(); @@ -1430,13 +1634,15 @@ error_code cellGemCalibrate(u32 gem_num) return CELL_GEM_ERROR_INVALID_PARAMETER; } - if (gem.is_controller_calibrating(gem_num)) + auto& controller = gem.controllers[gem_num]; + + if (controller.is_calibrating) { return CELL_EBUSY; } - gem.controllers[gem_num].is_calibrating = true; - gem.controllers[gem_num].calibration_start_us = get_guest_system_time(); + controller.is_calibrating = true; + controller.calibration_start_us = get_guest_system_time(); return CELL_OK; } @@ -1459,7 +1665,7 @@ error_code cellGemClearStatusFlags(u32 gem_num, u64 mask) return CELL_GEM_ERROR_INVALID_PARAMETER; } - gem.status_flags &= ~mask; + gem.controllers[gem_num].calibration_status_flags &= ~mask; return CELL_OK; } @@ -1563,13 +1769,28 @@ error_code cellGemEnableMagnetometer(u32 gem_num, u32 enable) return CELL_GEM_NOT_CONNECTED; } + auto& controller = gem.controllers[gem_num]; + // NOTE: RE doesn't show this check but it is mentioned in the docs, so I'll leave it here for now. - //if (!gem.controllers[gem_num].calibrated_magnetometer) + //if (!controller.calibrated_magnetometer) //{ // return CELL_GEM_NOT_CALIBRATED; //} - gem.controllers[gem_num].enabled_magnetometer = !!enable; + controller.enabled_magnetometer = !!enable; + + if (g_cfg.io.move == move_handler::real) + { + std::lock_guard lock(pad::g_pad_mutex); + + const auto handler = pad::get_current_handler(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + + if (pad && pad->m_pad_handler == pad_handler::move) + { + pad->move_data.magnetometer_enabled = controller.enabled_magnetometer; + } + } return CELL_OK; } @@ -1597,12 +1818,27 @@ error_code cellGemEnableMagnetometer2(u32 gem_num, u32 enable) return CELL_GEM_NOT_CONNECTED; } - if (!gem.controllers[gem_num].calibrated_magnetometer) + auto& controller = gem.controllers[gem_num]; + + if (!controller.calibrated_magnetometer) { return CELL_GEM_NOT_CALIBRATED; } - gem.controllers[gem_num].enabled_magnetometer = !!enable; + controller.enabled_magnetometer = !!enable; + + if (g_cfg.io.move == move_handler::real) + { + std::lock_guard lock(pad::g_pad_mutex); + + const auto handler = pad::get_current_handler(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + + if (pad && pad->m_pad_handler == pad_handler::move) + { + pad->move_data.magnetometer_enabled = controller.enabled_magnetometer; + } + } return CELL_OK; } @@ -1656,7 +1892,7 @@ error_code cellGemFilterState(u32 gem_num, u32 enable) return CELL_OK; } -error_code cellGemForceRGB(u32 gem_num, float r, float g, float b) +error_code cellGemForceRGB(u32 gem_num, f32 r, f32 g, f32 b) { cellGem.todo("cellGemForceRGB(gem_num=%d, r=%f, g=%f, b=%f)", gem_num, r, g, b); @@ -1680,8 +1916,13 @@ error_code cellGemForceRGB(u32 gem_num, float r, float g, float b) // color = color * (2.f / sum) //} - gem.controllers[gem_num].sphere_rgb = gem_config::gem_color(r, g, b); - gem.controllers[gem_num].enabled_tracking = false; + auto& controller = gem.controllers[gem_num]; + + controller.sphere_rgb = gem_config::gem_color(r, g, b); + controller.enabled_tracking = false; + + const auto [h, s, v] = ps_move_tracker::rgb_to_hsv(r, g, b); + controller.hue = h; return CELL_OK; } @@ -1752,9 +1993,9 @@ error_code cellGemGetCameraState(vm::ptr camera_state) // TODO: use correct camera settings camera_state->exposure = 0; camera_state->exposure_time = 1.0f / 60.0f; - camera_state->gain = 1.0; - camera_state->pitch_angle = 0.0; - camera_state->pitch_angle_estimate = 0.0; + camera_state->gain = 1.0f; + camera_state->pitch_angle = 0.0f; + camera_state->pitch_angle_estimate = 0.0f; return CELL_OK; } @@ -2059,7 +2300,7 @@ error_code cellGemGetMemorySize(s32 max_connect) return not_an_error(GemGetMemorySize(max_connect)); } -error_code cellGemGetRGB(u32 gem_num, vm::ptr r, vm::ptr g, vm::ptr b) +error_code cellGemGetRGB(u32 gem_num, vm::ptr r, vm::ptr g, vm::ptr b) { cellGem.todo("cellGemGetRGB(gem_num=%d, r=*0x%x, g=*0x%x, b=*0x%x)", gem_num, r, g, b); @@ -2209,7 +2450,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr flags) return CELL_GEM_ERROR_INVALID_PARAMETER; } - *flags = gem.status_flags; + *flags = gem.runtime_status_flags | gem.controllers[gem_num].calibration_status_flags; return CELL_OK; } @@ -2374,7 +2615,7 @@ error_code cellGemInit(ppu_thread& ppu, vm::cptr attribute) gem.updating = false; gem.camera_frame = 0; - gem.status_flags = 0; + gem.runtime_status_flags = 0; gem.attribute = *attribute; for (int gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++) @@ -2406,13 +2647,15 @@ error_code cellGemInvalidateCalibration(s32 gem_num) return CELL_GEM_ERROR_INVALID_PARAMETER; } - gem.controllers[gem_num].calibrated_magnetometer = false; + auto& controller = gem.controllers[gem_num]; // TODO: does this really stop an ongoing calibration ? - gem.controllers[gem_num].is_calibrating = false; - gem.controllers[gem_num].calibration_start_us = 0; - - // TODO: gem.status_flags (probably not changed) + controller.calibrated_magnetometer = false; + controller.is_calibrating = false; + controller.calibration_start_us = 0; + controller.calibration_status_flags = 0; + controller.hue_set = false; + controller.enabled_tracking = false; return CELL_OK; } @@ -2640,6 +2883,25 @@ error_code cellGemSetRumble(u32 gem_num, u8 rumble) gem.controllers[gem_num].rumble = rumble; + // Set actual device rumble + if (g_cfg.io.move == move_handler::real) + { + std::lock_guard pad_lock(pad::g_pad_mutex); + const auto handler = pad::get_current_handler(); + auto& handlers = handler->get_handlers(); + if (auto it = handlers.find(pad_handler::move); it != handlers.end() && it->second) + { + const u32 pad_index = pad_num(gem_num); + for (const auto& binding : it->second->bindings()) + { + if (!binding.device || binding.device->player_id != pad_index) continue; + + handler->SetRumble(pad_index, rumble, rumble > 0); + break; + } + } + } + return CELL_OK; } @@ -2668,7 +2930,7 @@ error_code cellGemSetYaw(u32 gem_num, vm::ptr z_direction) error_code cellGemTrackHues(vm::cptr req_hues, vm::ptr res_hues) { - cellGem.todo("cellGemTrackHues(req_hues=*0x%x, res_hues=*0x%x)", req_hues, res_hues); + cellGem.todo("cellGemTrackHues(req_hues=%s, res_hues=*0x%x)", req_hues ? fmt::format("*0x%x [%d, %d, %d, %d]", req_hues, req_hues[0], req_hues[1], req_hues[2], req_hues[3]) : "*0x0", res_hues); auto& gem = g_fxo->get(); @@ -2692,8 +2954,6 @@ error_code cellGemTrackHues(vm::cptr req_hues, vm::ptr res_hues) gem.controllers[i].enabled_LED = true; gem.controllers[i].hue_set = true; - // TODO: set hue based on tracker data - switch (i) { default: @@ -2711,6 +2971,9 @@ error_code cellGemTrackHues(vm::cptr req_hues, vm::ptr res_hues) break; } + const auto [r, g, b] = ps_move_tracker::hsv_to_rgb(gem.controllers[i].hue, 1.0f, 1.0f); + gem.controllers[i].sphere_rgb = gem_config::gem_color(r / 255.0f, g / 255.0f, b / 255.0f); + if (res_hues) { res_hues[i] = gem.controllers[i].hue; @@ -2739,7 +3002,8 @@ error_code cellGemTrackHues(vm::cptr req_hues, vm::ptr res_hues) gem.controllers[i].hue_set = true; gem.controllers[i].hue = req_hues[i]; - // TODO: set hue of tracker + const auto [r, g, b] = ps_move_tracker::hsv_to_rgb(gem.controllers[i].hue, 1.0f, 1.0f); + gem.controllers[i].sphere_rgb = gem_config::gem_color(r / 255.0f, g / 255.0f, b / 255.0f); if (res_hues) { diff --git a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp index 09d7edf8d2..80242686cb 100644 --- a/rpcs3/Emu/Cell/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp @@ -273,7 +273,7 @@ error_code cellGifDecReadHeader(vm::ptr mainHandle, vm::ptrfd; + const u32 fd = subHandle->fd; CellGifDecInfo& current_info = subHandle->info; // Write the header to buffer @@ -288,7 +288,7 @@ error_code cellGifDecReadHeader(vm::ptr mainHandle, vm::ptr(fd); + auto file = idm::get_unlocked(fd); file->file.seek(0); file->file.read(buffer, sizeof(buffer)); break; @@ -302,7 +302,7 @@ error_code cellGifDecReadHeader(vm::ptr mainHandle, vm::ptr> 7; @@ -500,7 +500,7 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr(fd); + auto file = idm::get_unlocked(fd); file->file.seek(0); file->file.read(gif.get(), fileSize); break; @@ -520,8 +520,8 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr(dataCtrlParam->outputBytesPerLine); - const char nComponents = 4; - uint image_size = width * height * nComponents; + constexpr char nComponents = 4; + const u32 image_size = width * height * nComponents; switch(current_outParam.outputColorSpace) { @@ -541,9 +541,8 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr width * nComponents) // Check if we need padding @@ -579,9 +578,8 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr out, u32 outSize, vm::cptr in for (u32 pos = 0; rindex >= 0; rindex--, pos++) { - char c1 = in[pos]; + const char c1 = in[pos]; if (false) // DAT[c1] == '\x03') // TODO { @@ -529,7 +529,7 @@ error_code cellHttpUtilEscapeUri(vm::ptr out, u32 outSize, vm::cptr in return CELL_HTTP_UTIL_ERROR_NO_MEMORY; } - const char* chars = "0123456789ABCDEF"; + constexpr const char* chars = "0123456789ABCDEF"; out[out_pos++] = '%'; // 0x25 out[out_pos++] = chars[c1 >> 4]; out[out_pos++] = chars[c1 & 0xf]; @@ -618,7 +618,7 @@ error_code cellHttpUtilFormUrlEncode(vm::ptr out, u32 outSize, vm::cptr= 0; rindex--, pos++) { - char c1 = in[pos]; + const char c1 = in[pos]; if (c1 == ' ') { @@ -645,7 +645,7 @@ error_code cellHttpUtilFormUrlEncode(vm::ptr out, u32 outSize, vm::cptr> 4]; out[out_pos++] = chars[c1 & 0xf]; @@ -707,7 +707,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr out, u32 size, vm::cptr i for (s32 index = 0, pos = 0;; index++) { size_needed = index + 1; - char c1 = in[pos++]; + const char c1 = in[pos++]; if (!c1) { @@ -731,7 +731,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr out, u32 size, vm::cptr i const auto check_char = [](b8 c) { - u32 utmp = static_cast(c); + const u32 utmp = static_cast(c); s32 stmp = utmp - 48; if (static_cast(c - 48) > 9) { diff --git a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp index d1a5ac002d..124531826d 100644 --- a/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp @@ -76,7 +76,7 @@ error_code cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptrfileName.get_ptr()); + const std::string real_path = vfs::get(src->fileName.get_ptr()); fs::file file_s(real_path); if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE; @@ -103,7 +103,7 @@ error_code cellJpgDecClose(u32 mainHandle, u32 subHandle) { cellJpgDec.warning("cellJpgDecOpen(mainHandle=0x%x, subHandle=0x%x)", mainHandle, subHandle); - const auto subHandle_data = idm::get(subHandle); + const auto subHandle_data = idm::get_unlocked(subHandle); if (!subHandle_data) { @@ -120,15 +120,15 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr(subHandle); + const auto subHandle_data = idm::get_unlocked(subHandle); if (!subHandle_data) { return CELL_JPGDEC_ERROR_FATAL; } - const u32& fd = subHandle_data->fd; - const u64& fileSize = subHandle_data->fileSize; + const u32 fd = subHandle_data->fd; + const u64 fileSize = subHandle_data->fileSize; CellJpgDecInfo& current_info = subHandle_data->info; // Write the header to buffer @@ -142,7 +142,7 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr(fd); + auto file = idm::get_unlocked(fd); file->file.seek(0); file->file.read(buffer.get(), fileSize); break; @@ -158,12 +158,12 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr= fileSize) + if (i >= fileSize) return CELL_JPGDEC_ERROR_HEADER; - u16 block_length = buffer[i] * 0xFF + buffer[i+1]; + u16 block_length = buffer[i] * 0xFF + buffer[i + 1]; - while(true) + while (true) { i += block_length; // Increase the file index to get to the next block if (i >= fileSize || // Check to protect against segmentation faults @@ -172,15 +172,15 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr data, dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_STOP; - const auto subHandle_data = idm::get(subHandle); + const auto subHandle_data = idm::get_unlocked(subHandle); if (!subHandle_data) { @@ -223,7 +223,7 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, case CELL_JPGDEC_FILE: { - auto file = idm::get(fd); + auto file = idm::get_unlocked(fd); file->file.seek(0); file->file.read(jpg.get(), fileSize); break; @@ -267,12 +267,11 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, { memcpy(data.get_ptr(), image.get(), image_size); } + break; } - break; - case CELL_JPG_ARGB: { - const int nComponents = 4; + constexpr int nComponents = 4; image_size *= nComponents; if (bytesPerLine > width * nComponents || flip) //check if we need padding { @@ -307,16 +306,15 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, } std::memcpy(data.get_ptr(), img.get(), image_size); } + break; } - break; - case CELL_JPG_GRAYSCALE: case CELL_JPG_YCbCr: case CELL_JPG_UPSAMPLE_ONLY: case CELL_JPG_GRAYSCALE_TO_ALPHA_RGBA: case CELL_JPG_GRAYSCALE_TO_ALPHA_ARGB: cellJpgDec.error("cellJpgDecDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace); - break; + break; default: return CELL_JPGDEC_ERROR_ARG; @@ -324,7 +322,7 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_FINISH; - if(dataCtrlParam->outputBytesPerLine) + if (dataCtrlParam->outputBytesPerLine) dataOutInfo->outputLines = static_cast(image_size / dataCtrlParam->outputBytesPerLine); return CELL_OK; @@ -340,7 +338,7 @@ error_code cellJpgDecSetParameter(u32 mainHandle, u32 subHandle, vm::cptr(subHandle); + const auto subHandle_data = idm::get_unlocked(subHandle); if (!subHandle_data) { diff --git a/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp index d83939bcff..843a0adc24 100644 --- a/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp @@ -144,9 +144,9 @@ error_code cellPhotoDecodeFromFile(vm::cptr srcHddDir, vm::cptr srcH const std::string vpath = fmt::format("%s/%s", srcHddDir.get_ptr(), srcHddFile.get_ptr()); const std::string path = vfs::get(vpath); - if (!vpath.starts_with("/dev_hdd0") && !vpath.starts_with("/dev_hdd1")) + if (!vpath.starts_with("/dev_hdd0") && !vpath.starts_with("/dev_hdd1") && !vpath.starts_with("/dev_bdvd")) { - cellPhotoDecode.error("Source '%s' is not inside dev_hdd0 or dev_hdd1", vpath); + cellPhotoDecode.error("Source '%s' is not inside dev_hdd0 or dev_hdd1 or dev_bdvd", vpath); return CELL_PHOTO_DECODE_ERROR_ACCESS_ERROR; // TODO: is this correct? } diff --git a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp index d792987251..cfb75b611a 100644 --- a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -93,7 +93,7 @@ void pngDecReadBuffer(png_structp png_ptr, png_bytep out, png_size_t length) if (buffer.file) { // Get the file - auto file = idm::get(buffer.fd); + auto file = idm::get_unlocked(buffer.fd); // Read the data file->file.read(out, length); diff --git a/rpcs3/Emu/Cell/Modules/cellSearch.cpp b/rpcs3/Emu/Cell/Modules/cellSearch.cpp index 3e0e0abbbc..bcc0151764 100644 --- a/rpcs3/Emu/Cell/Modules/cellSearch.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSearch.cpp @@ -94,11 +94,11 @@ struct search_content_t ENABLE_BITWISE_SERIALIZATION; }; -using content_id_type = std::pair>; +using content_id_type = std::pair>; struct content_id_map { - std::unordered_map> map; + std::unordered_map> map; shared_mutex mutex; @@ -539,7 +539,7 @@ error_code cellSearchStartListSearch(CellSearchListSearchType type, CellSearchSo sysutil_register_cb([=, &content_map = g_fxo->get(), &search](ppu_thread& ppu) -> s32 { - auto curr_search = idm::get(id); + auto curr_search = idm::get_unlocked(id); vm::var resultParam; resultParam->searchId = id; resultParam->resultNum = 0; // Set again later @@ -613,7 +613,7 @@ error_code cellSearchStartListSearch(CellSearchListSearchType type, CellSearchSo auto found = content_map.map.find(hash); if (found == content_map.map.end()) // content isn't yet being tracked { - std::shared_ptr curr_find = std::make_shared(); + shared_ptr curr_find = make_shared(); if (item_path.length() > CELL_SEARCH_PATH_LEN_MAX) { // TODO: Create mapping which will be resolved to an actual hard link in VFS by cellSearchPrepareFile @@ -800,7 +800,7 @@ error_code cellSearchStartContentSearchInList(vm::cptr list sysutil_register_cb([=, list_path = std::string(content_info->infoPath.contentPath), &search, &content_map](ppu_thread& ppu) -> s32 { - auto curr_search = idm::get(id); + auto curr_search = idm::get_unlocked(id); vm::var resultParam; resultParam->searchId = id; resultParam->resultNum = 0; // Set again later @@ -855,7 +855,7 @@ error_code cellSearchStartContentSearchInList(vm::cptr list auto found = content_map.map.find(hash); if (found == content_map.map.end()) // content isn't yet being tracked { - std::shared_ptr curr_find = std::make_shared(); + shared_ptr curr_find = make_shared(); if (item_path.length() > CELL_SEARCH_PATH_LEN_MAX) { // Create mapping which will be resolved to an actual hard link in VFS by cellSearchPrepareFile @@ -1060,7 +1060,7 @@ error_code cellSearchStartContentSearch(CellSearchContentSearchType type, CellSe sysutil_register_cb([=, &content_map = g_fxo->get(), &search](ppu_thread& ppu) -> s32 { - auto curr_search = idm::get(id); + auto curr_search = idm::get_unlocked(id); vm::var resultParam; resultParam->searchId = id; resultParam->resultNum = 0; // Set again later @@ -1096,7 +1096,7 @@ error_code cellSearchStartContentSearch(CellSearchContentSearchType type, CellSe auto found = content_map.map.find(hash); if (found == content_map.map.end()) // content isn't yet being tracked { - std::shared_ptr curr_find = std::make_shared(); + shared_ptr curr_find = make_shared(); if (item_path.length() > CELL_SEARCH_PATH_LEN_MAX) { // Create mapping which will be resolved to an actual hard link in VFS by cellSearchPrepareFile @@ -1372,7 +1372,7 @@ error_code cellSearchGetContentInfoByOffset(CellSearchId searchId, s32 offset, v std::memset(outContentId->data + 4, -1, CELL_SEARCH_CONTENT_ID_SIZE - 4); } - const auto searchObject = idm::get(searchId); + const auto searchObject = idm::get_unlocked(searchId); if (!searchObject) { @@ -1518,7 +1518,7 @@ error_code cellSearchGetOffsetByContentId(CellSearchId searchId, vm::cptr(searchId); + const auto searchObject = idm::get_unlocked(searchId); if (!searchObject) { @@ -1568,7 +1568,7 @@ error_code cellSearchGetContentIdByOffset(CellSearchId searchId, s32 offset, vm: std::memset(outContentId->data + 4, -1, CELL_SEARCH_CONTENT_ID_SIZE - 4); } - const auto searchObject = idm::get(searchId); + const auto searchObject = idm::get_unlocked(searchId); if (!searchObject) { @@ -1663,7 +1663,7 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptrdata, 0, 4); - const auto searchObject = idm::get(searchId); + const auto searchObject = idm::get_unlocked(searchId); if (!searchObject) { @@ -1690,17 +1690,17 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr std::shared_ptr + const auto get_random_content = [&searchObject, &first_content]() -> shared_ptr { if (searchObject->content_ids.size() == 1) { return first_content; } + std::vector result; std::sample(searchObject->content_ids.begin(), searchObject->content_ids.end(), std::back_inserter(result), 1, std::mt19937{std::random_device{}()}); ensure(result.size() == 1); - std::shared_ptr content = result[0].second; - ensure(!!content); + shared_ptr content = ensure(result[0].second); return content; }; @@ -1736,7 +1736,7 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr content = get_random_content(); + shared_ptr content = get_random_content(); context.playlist.push_back(content->infoPath.contentPath); cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning random track: Type=0x%x, Path=%s", content_hash, +content->type, context.playlist.back()); } @@ -1757,7 +1757,7 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr content = get_random_content(); + shared_ptr content = get_random_content(); context.playlist.push_back(content->infoPath.contentPath); cellSearch.notice("cellSearchGetMusicSelectionContext(): Assigning random track: Type=0x%x, Path=%s", +content->type, context.playlist.back()); } @@ -2044,7 +2044,7 @@ error_code cellSearchCancel(CellSearchId searchId) { cellSearch.todo("cellSearchCancel(searchId=0x%x)", searchId); - const auto searchObject = idm::get(searchId); + const auto searchObject = idm::get_unlocked(searchId); if (!searchObject) { @@ -2075,7 +2075,7 @@ error_code cellSearchEnd(CellSearchId searchId) return error; } - const auto searchObject = idm::get(searchId); + const auto searchObject = idm::get_unlocked(searchId); if (!searchObject) { @@ -2120,7 +2120,7 @@ error_code music_selection_context::find_content_id(vm::ptr // Search for the content that matches our current selection auto& content_map = g_fxo->get(); - std::shared_ptr found_content; + shared_ptr found_content; u64 hash = 0; for (const std::string& track : playlist) @@ -2187,7 +2187,7 @@ error_code music_selection_context::find_content_id(vm::ptr } // TODO: check for actual content inside the directory - std::shared_ptr curr_find = std::make_shared(); + shared_ptr curr_find = make_shared(); curr_find->type = CELL_SEARCH_CONTENTTYPE_MUSICLIST; curr_find->repeat_mode = repeat_mode; curr_find->context_option = context_option; @@ -2243,7 +2243,7 @@ error_code music_selection_context::find_content_id(vm::ptr continue; } - std::shared_ptr curr_find = std::make_shared(); + shared_ptr curr_find = make_shared(); curr_find->type = CELL_SEARCH_CONTENTTYPE_MUSIC; curr_find->repeat_mode = repeat_mode; curr_find->context_option = context_option; diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index 3d5c535058..8f3469e031 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -1265,7 +1265,7 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr spurs, u32 revision, } // entry point cannot be initialized immediately because SPU LS will be rewritten by sys_spu_thread_group_start() - //idm::get>(spurs->spus[num])->custom_task = [entry = spurs->spuImg.entry_point](spu_thread& spu) + //idm::get_unlocked>(spurs->spus[num])->custom_task = [entry = spurs->spuImg.entry_point](spu_thread& spu) { // Disabled //spu.RegisterHleFunction(entry, spursKernelEntry); diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp index f559aeebff..435fa1636d 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -622,7 +622,7 @@ bool spursKernel2SelectWorkload(spu_thread& spu) void spursKernelDispatchWorkload(spu_thread& spu, u64 widAndPollStatus) { const auto ctxt = spu._ptr(0x100); - auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + const bool isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; auto pollStatus = static_cast(widAndPollStatus); auto wid = static_cast(widAndPollStatus >> 32); @@ -674,7 +674,7 @@ void spursKernelDispatchWorkload(spu_thread& spu, u64 widAndPollStatus) bool spursKernelWorkloadExit(spu_thread& spu) { const auto ctxt = spu._ptr(0x100); - auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + const bool isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; // Select next workload to run spu.gpr[3].clear(); @@ -701,7 +701,7 @@ bool spursKernelEntry(spu_thread& spu) ctxt->spuNum = spu.gpr[3]._u32[3]; ctxt->spurs.set(spu.gpr[4]._u64[1]); - auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + const bool isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; // Initialise the SPURS context to its initial values ctxt->dmaTagId = CELL_SPURS_KERNEL_DMA_TAG_ID; @@ -785,8 +785,8 @@ void spursSysServiceIdleHandler(spu_thread& spu, SpursKernelContext* ctxt) } } - bool allSpusIdle = nIdlingSpus == spurs->nSpus ? true : false; - bool exitIfNoWork = spurs->flags1 & SF1_EXIT_IF_NO_WORK ? true : false; + const bool allSpusIdle = nIdlingSpus == spurs->nSpus; + const bool exitIfNoWork = spurs->flags1 & SF1_EXIT_IF_NO_WORK ? true : false; shouldExit = allSpusIdle && exitIfNoWork; // Check if any workloads can be scheduled @@ -843,7 +843,7 @@ void spursSysServiceIdleHandler(spu_thread& spu, SpursKernelContext* ctxt) } } - bool spuIdling = spurs->spuIdling & (1 << ctxt->spuNum) ? true : false; + const bool spuIdling = spurs->spuIdling & (1 << ctxt->spuNum) ? true : false; if (foundReadyWorkload && shouldExit == false) { spurs->spuIdling &= ~(1 << ctxt->spuNum); diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp index 39d5cee45d..7ba9644d15 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -659,7 +659,7 @@ extern bool check_if_vdec_contexts_exist() extern void vdecEntry(ppu_thread& ppu, u32 vid) { - idm::get(vid)->exec(ppu, vid); + idm::get_unlocked(vid)->exec(ppu, vid); ppu.state += cpu_flag::exit; } @@ -886,7 +886,7 @@ static error_code vdecOpen(ppu_thread& ppu, T type, U res, vm::cptr } // Create decoder context - std::shared_ptr vdec; + shared_ptr vdec; if (std::unique_lock lock{g_fxo->get(), std::try_to_lock}) { @@ -909,7 +909,7 @@ static error_code vdecOpen(ppu_thread& ppu, T type, U res, vm::cptr ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 0x10000, vid, +res->ppuThreadPriority, +res->ppuThreadStackSize, SYS_PPU_THREAD_CREATE_INTERRUPT, +_name); *handle = vid; - const auto thrd = idm::get>(static_cast(*_tid)); + const auto thrd = idm::get_unlocked>(static_cast(*_tid)); thrd->cmd_list ({ @@ -949,7 +949,7 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle) return {}; } - auto vdec = idm::get(handle); + auto vdec = idm::get_unlocked(handle); if (!vdec) { @@ -1003,7 +1003,7 @@ error_code cellVdecStartSeq(ppu_thread& ppu, u32 handle) cellVdec.warning("cellVdecStartSeq(handle=0x%x)", handle); - const auto vdec = idm::get(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec) { @@ -1055,7 +1055,7 @@ error_code cellVdecEndSeq(ppu_thread& ppu, u32 handle) cellVdec.warning("cellVdecEndSeq(handle=0x%x)", handle); - const auto vdec = idm::get(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec) { @@ -1088,7 +1088,7 @@ error_code cellVdecDecodeAu(ppu_thread& ppu, u32 handle, CellVdecDecodeMode mode cellVdec.trace("cellVdecDecodeAu(handle=0x%x, mode=%d, auInfo=*0x%x)", handle, +mode, auInfo); - const auto vdec = idm::get(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec || !auInfo || !auInfo->size || !auInfo->startAddr) { @@ -1136,7 +1136,7 @@ error_code cellVdecDecodeAuEx2(ppu_thread& ppu, u32 handle, CellVdecDecodeMode m cellVdec.todo("cellVdecDecodeAuEx2(handle=0x%x, mode=%d, auInfo=*0x%x)", handle, +mode, auInfo); - const auto vdec = idm::get(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec || !auInfo || !auInfo->size || !auInfo->startAddr) { @@ -1192,7 +1192,7 @@ error_code cellVdecGetPictureExt(ppu_thread& ppu, u32 handle, vm::cptr(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec || !format) { @@ -1245,7 +1245,7 @@ error_code cellVdecGetPictureExt(ppu_thread& ppu, u32 handle, vm::cptr>(vdec->ppu_tid); + auto vdec_ppu = idm::get_unlocked>(vdec->ppu_tid); if (vdec_ppu) thread_ctrl::notify(*vdec_ppu); } @@ -1354,7 +1354,7 @@ error_code cellVdecGetPicItem(ppu_thread& ppu, u32 handle, vm::pptr(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec || !picItem) { @@ -1596,7 +1596,7 @@ error_code cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frameRateCode) { cellVdec.trace("cellVdecSetFrameRate(handle=0x%x, frameRateCode=0x%x)", handle, +frameRateCode); - const auto vdec = idm::get(handle); + const auto vdec = idm::get_unlocked(handle); // 0x80 seems like a common prefix if (!vdec || (frameRateCode & 0xf8) != 0x80) @@ -1659,7 +1659,7 @@ error_code cellVdecSetPts(u32 handle, vm::ptr unk) { cellVdec.error("cellVdecSetPts(handle=0x%x, unk=*0x%x)", handle, unk); - const auto vdec = idm::get(handle); + const auto vdec = idm::get_unlocked(handle); if (!vdec || !unk) { diff --git a/rpcs3/Emu/Cell/Modules/cellVpost.cpp b/rpcs3/Emu/Cell/Modules/cellVpost.cpp index 514aad9f7b..773bb96783 100644 --- a/rpcs3/Emu/Cell/Modules/cellVpost.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVpost.cpp @@ -205,7 +205,7 @@ error_code cellVpostClose(u32 handle) { cellVpost.warning("cellVpostClose(handle=0x%x)", handle); - const auto vpost = idm::get(handle); + const auto vpost = idm::get_unlocked(handle); if (!vpost) { @@ -220,7 +220,7 @@ error_code cellVpostExec(u32 handle, vm::cptr inPicBuff, vm::cptr(handle); + const auto vpost = idm::get_unlocked(handle); if (!vpost) { diff --git a/rpcs3/Emu/Cell/Modules/libmixer.cpp b/rpcs3/Emu/Cell/Modules/libmixer.cpp index c9a6f6dca9..e92b5c6cf4 100644 --- a/rpcs3/Emu/Cell/Modules/libmixer.cpp +++ b/rpcs3/Emu/Cell/Modules/libmixer.cpp @@ -510,7 +510,7 @@ s32 cellSurMixerCreate(vm::cptr config) libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); - //auto thread = idm::make_ptr("Surmixer Thread"); + //auto thread = idm::make_ptr>("Surmixer Thread"); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp index cb1cd0aa29..55b8847934 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -652,7 +652,7 @@ error_code npDrmIsAvailable(vm::cptr k_licensee_addr, vm::cptr drm_pat std::string enc_drm_path; ensure(vm::read_string(drm_path.addr(), 0x100, enc_drm_path, true), "Secret access violation"); - sceNp.warning(u8"npDrmIsAvailable(): drm_path=“%s”", enc_drm_path); + sceNp.warning("npDrmIsAvailable(): drm_path=\"%s\"", enc_drm_path); auto& npdrmkeys = g_fxo->get(); @@ -5347,7 +5347,7 @@ error_code sceNpScoreCreateTransactionCtx(s32 titleCtxId) return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto score = idm::get(titleCtxId); + auto score = idm::get_unlocked(titleCtxId); if (!score) { @@ -5399,24 +5399,12 @@ error_code sceNpScoreSetTimeout(s32 ctxId, usecond_t timeout) return SCE_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; } - const u32 idm_id = static_cast(ctxId); - - if (idm_id >= score_transaction_ctx::id_base && idm_id < (score_transaction_ctx::id_base + score_transaction_ctx::id_count)) + if (auto trans = idm::get_unlocked(ctxId)) { - auto trans = idm::get(ctxId); - if (!trans) - { - return SCE_NP_COMMUNITY_ERROR_INVALID_ID; - } trans->timeout = timeout; } - else if (idm_id >= score_ctx::id_base && idm_id < (score_ctx::id_base + score_ctx::id_count)) + else if (auto score = idm::get_unlocked(ctxId)) { - auto score = idm::get(ctxId); - if (!ctxId) - { - return SCE_NP_COMMUNITY_ERROR_INVALID_ID; - } score->timeout = timeout; } else @@ -5443,23 +5431,17 @@ error_code sceNpScoreSetPlayerCharacterId(s32 ctxId, SceNpScorePcId pcId) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - if (static_cast(ctxId) >= score_transaction_ctx::id_base) + if (auto trans = idm::get_unlocked(ctxId)) { - auto trans = idm::get(ctxId); - if (!trans) - { - return SCE_NP_COMMUNITY_ERROR_INVALID_ID; - } trans->pcId = pcId; } + else if (auto score = idm::get_unlocked(ctxId)) + { + score->pcId = pcId; + } else { - auto score = idm::get(ctxId); - if (!ctxId) - { - return SCE_NP_COMMUNITY_ERROR_INVALID_ID; - } - score->pcId = pcId; + return SCE_NP_COMMUNITY_ERROR_INVALID_ID; } return CELL_OK; @@ -5476,7 +5458,7 @@ error_code sceNpScoreWaitAsync(s32 transId, vm::ptr result) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - auto trans = idm::get(transId); + auto trans = idm::get_unlocked(transId); if (!trans) { return SCE_NP_COMMUNITY_ERROR_INVALID_ID; @@ -5498,7 +5480,7 @@ error_code sceNpScorePollAsync(s32 transId, vm::ptr result) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - auto trans = idm::get(transId); + auto trans = idm::get_unlocked(transId); if (!trans) { return SCE_NP_COMMUNITY_ERROR_INVALID_ID; @@ -5515,9 +5497,9 @@ error_code sceNpScorePollAsync(s32 transId, vm::ptr result) return CELL_OK; } -std::pair, std::shared_ptr> get_score_transaction_context(s32 transId, bool reset_transaction = true) +std::pair, shared_ptr> get_score_transaction_context(s32 transId, bool reset_transaction = true) { - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -6217,7 +6199,7 @@ error_code sceNpScoreAbortTransaction(s32 transId) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - auto trans = idm::get(transId); + auto trans = idm::get_unlocked(transId); if (!trans) { return SCE_NP_COMMUNITY_ERROR_INVALID_ID; diff --git a/rpcs3/Emu/Cell/Modules/sceNp.h b/rpcs3/Emu/Cell/Modules/sceNp.h index 1adffccc5f..e6a1bdc7ea 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.h +++ b/rpcs3/Emu/Cell/Modules/sceNp.h @@ -1837,7 +1837,7 @@ public: virtual ~RecvMessageDialogBase() = default; virtual error_code Exec(SceNpBasicMessageMainType type, SceNpBasicMessageRecvOptions options, SceNpBasicMessageRecvAction& recv_result, u64& chosen_msg_id) = 0; - virtual void callback_handler(const std::shared_ptr> new_msg, u64 msg_id) = 0; + virtual void callback_handler(const shared_ptr> new_msg, u64 msg_id) = 0; protected: std::shared_ptr m_rpcn; diff --git a/rpcs3/Emu/Cell/Modules/sceNpSns.cpp b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp index 8de5e689c2..7a77d6c281 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpSns.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp @@ -139,7 +139,7 @@ error_code sceNpSnsFbAbortHandle(u32 handle) return SCE_NP_SNS_ERROR_INVALID_ARGUMENT; } - const auto sfh = idm::get(handle); + const auto sfh = idm::get_unlocked(handle); if (!sfh) { @@ -172,7 +172,7 @@ error_code sceNpSnsFbGetAccessToken(u32 handle, vm::cptr(handle); + const auto sfh = idm::get_unlocked(handle); if (!sfh) { @@ -200,7 +200,7 @@ s32 sceNpSnsFbStreamPublish(u32 handle) // add more arguments return SCE_NP_SNS_ERROR_INVALID_ARGUMENT; } - const auto sfh = idm::get(handle); + const auto sfh = idm::get_unlocked(handle); if (!sfh) { @@ -258,7 +258,7 @@ s32 sceNpSnsFbLoadThrottle(u32 handle) return SCE_NP_SNS_ERROR_INVALID_ARGUMENT; } - const auto sfh = idm::get(handle); + const auto sfh = idm::get_unlocked(handle); if (!sfh) { @@ -299,7 +299,7 @@ error_code sceNpSnsFbGetLongAccessToken(u32 handle, vm::cptr(handle); + const auto sfh = idm::get_unlocked(handle); if (!sfh) { diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 15a0cc6679..e7e9d308a0 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -123,7 +123,7 @@ struct sce_np_trophy_manager return res; } - ctxt = idm::check(context); + ctxt = idm::check_unlocked(context); if (!ctxt) { @@ -144,7 +144,7 @@ struct sce_np_trophy_manager return res; } - const auto hndl = idm::check(handle); + const auto hndl = idm::check_unlocked(handle); if (!hndl) { @@ -409,7 +409,7 @@ error_code sceNpTrophyAbortHandle(u32 handle) return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; } - const auto hndl = idm::check(handle); + const auto hndl = idm::check_unlocked(handle); if (!hndl) { @@ -552,7 +552,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, } const auto [ctxt, error] = trophy_manager.get_context_ex(context, handle, true); - const auto handle_ptr = idm::get(handle); + const auto handle_ptr = idm::get_unlocked(handle); if (error) { @@ -641,7 +641,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; } - if (handle_ptr.get() != idm::check(handle)) + if (handle_ptr.get() != idm::check_unlocked(handle)) { on_error(); return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; @@ -716,7 +716,6 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, // Create a counter which is destroyed after the function ends const auto queued = std::make_shared>(0); - std::weak_ptr> wkptr = queued; for (auto status : statuses) { @@ -724,12 +723,11 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, *queued += status.second; for (s32 completed = 0; completed <= status.second; completed++) { - sysutil_register_cb([statusCb, status, context, completed, arg, wkptr](ppu_thread& cb_ppu) -> s32 + sysutil_register_cb([statusCb, status, context, completed, arg, queued](ppu_thread& cb_ppu) -> s32 { // TODO: it is possible that we need to check the return value here as well. statusCb(cb_ppu, context, status.first, completed, status.second, arg); - const auto queued = wkptr.lock(); if (queued && (*queued)-- == 1) { queued->notify_one(); diff --git a/rpcs3/Emu/Cell/Modules/sceNpTus.cpp b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp index 77057a1ad7..ee82e1093e 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTus.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp @@ -133,7 +133,7 @@ error_code sceNpTusCreateTransactionCtx(s32 titleCtxId) return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto tus = idm::get(titleCtxId); + auto tus = idm::get_unlocked(titleCtxId); if (!tus) { @@ -185,24 +185,12 @@ error_code sceNpTusSetTimeout(s32 ctxId, u32 timeout) return SCE_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; } - const u32 idm_id = static_cast(ctxId); - - if (idm_id >= tus_transaction_ctx::id_base && idm_id < (tus_transaction_ctx::id_base + tus_transaction_ctx::id_count)) + if (auto trans = idm::get_unlocked(ctxId)) { - auto trans = idm::get(ctxId); - if (!trans) - { - return SCE_NP_COMMUNITY_ERROR_INVALID_ID; - } trans->timeout = timeout; } - else if (idm_id >= tus_ctx::id_base && idm_id < (tus_ctx::id_base + tus_ctx::id_count)) + else if (auto tus = idm::get_unlocked(ctxId)) { - auto tus = idm::get(ctxId); - if (!ctxId) - { - return SCE_NP_COMMUNITY_ERROR_INVALID_ID; - } tus->timeout = timeout; } else @@ -224,7 +212,7 @@ error_code sceNpTusAbortTransaction(s32 transId) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - auto trans = idm::get(transId); + auto trans = idm::get_unlocked(transId); if (!trans) { return SCE_NP_COMMUNITY_ERROR_INVALID_ID; @@ -246,7 +234,7 @@ error_code sceNpTusWaitAsync(s32 transId, vm::ptr result) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - auto trans = idm::get(transId); + auto trans = idm::get_unlocked(transId); if (!trans) { return SCE_NP_COMMUNITY_ERROR_INVALID_ID; @@ -268,7 +256,7 @@ error_code sceNpTusPollAsync(s32 transId, vm::ptr result) return SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED; } - auto trans = idm::get(transId); + auto trans = idm::get_unlocked(transId); if (!trans) { return SCE_NP_COMMUNITY_ERROR_INVALID_ID; @@ -326,7 +314,7 @@ error_code scenp_tus_set_multislot_variable(s32 transId, T targetNpId, vm::cptr< return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -413,7 +401,7 @@ error_code scenp_tus_get_multislot_variable(s32 transId, T targetNpId, vm::cptr< return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -500,7 +488,7 @@ error_code scenp_tus_get_multiuser_variable(s32 transId, T targetNpIdArray, SceN return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -599,7 +587,7 @@ error_code scenp_tus_get_friends_variable(s32 transId, SceNpTusSlotId slotId, s3 return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -659,7 +647,7 @@ error_code scenp_tus_add_and_get_variable(s32 transId, T targetNpId, SceNpTusSlo return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -736,7 +724,7 @@ error_code scenp_tus_try_and_set_variable(s32 transId, T targetNpId, SceNpTusSlo return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -813,7 +801,7 @@ error_code scenp_tus_delete_multislot_variable(s32 transId, T targetNpId, vm::cp return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -885,7 +873,7 @@ error_code scenp_tus_set_data(s32 transId, T targetNpId, SceNpTusSlotId slotId, return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -957,7 +945,7 @@ error_code scenp_tus_get_data(s32 transId, T targetNpId, SceNpTusSlotId slotId, return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -1044,7 +1032,7 @@ error_code scenp_tus_get_multislot_data_status(s32 transId, T targetNpId, vm::cp return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -1131,7 +1119,7 @@ error_code scenp_tus_get_multiuser_data_status(s32 transId, T targetNpIdArray, S return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -1230,7 +1218,7 @@ error_code scenp_tus_get_friends_data_status(s32 transId, SceNpTusSlotId slotId, return SCE_NP_COMMUNITY_ERROR_INVALID_ONLINE_ID; } - auto trans_ctx = idm::get(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -1295,7 +1283,7 @@ error_code scenp_tus_delete_multislot_data(s32 transId, T targetNpId, vm::cptr(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -1337,7 +1325,7 @@ error_code sceNpTusDeleteMultiSlotDataVUserAsync(s32 transId, vm::cptr& trans, vm::ptr dataStatus) +void scenp_tss_no_file(const shared_ptr& trans, vm::ptr dataStatus) { // TSS are files stored on PSN by developers, no dumps available atm std::memset(dataStatus.get_ptr(), 0, sizeof(SceNpTssDataStatus)); @@ -1365,7 +1353,7 @@ error_code sceNpTssGetData(s32 transId, SceNpTssSlotId slotId, vm::ptr(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { @@ -1398,7 +1386,7 @@ error_code sceNpTssGetDataAsync(s32 transId, SceNpTssSlotId slotId, vm::ptr(transId); + auto trans_ctx = idm::get_unlocked(transId); if (!trans_ctx) { diff --git a/rpcs3/Emu/Cell/Modules/sys_io_.cpp b/rpcs3/Emu/Cell/Modules/sys_io_.cpp index e0505f4c41..5f767ebae4 100644 --- a/rpcs3/Emu/Cell/Modules/sys_io_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_io_.cpp @@ -51,7 +51,7 @@ void config_event_entry(ppu_thread& ppu) } const u32 queue_id = cfg.queue_id; - auto queue = idm::get(queue_id); + auto queue = idm::get_unlocked(queue_id); while (queue && sys_event_queue_receive(ppu, queue_id, vm::null, 0) == CELL_OK) { @@ -81,7 +81,7 @@ void config_event_entry(ppu_thread& ppu) if (!queue->exists) { // Exit condition - queue = nullptr; + queue = null_ptr; break; } @@ -134,7 +134,7 @@ extern void send_sys_io_connect_event(usz index, u32 state) if (cfg.init_ctr) { - if (auto port = idm::get(cfg.queue_id)) + if (auto port = idm::get_unlocked(cfg.queue_id)) { port->send(0, 1, index, state); } diff --git a/rpcs3/Emu/Cell/Modules/sys_mempool.cpp b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp index ad70cc173e..b7ffa72984 100644 --- a/rpcs3/Emu/Cell/Modules/sys_mempool.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp @@ -60,7 +60,7 @@ error_code sys_mempool_create(ppu_thread& ppu, vm::ptr mempool, v auto id = idm::make(); *mempool = id; - auto memory_pool = idm::get(id); + auto memory_pool = idm::get_unlocked(id); memory_pool->chunk = chunk; memory_pool->chunk_size = chunk_size; @@ -114,7 +114,7 @@ void sys_mempool_destroy(ppu_thread& ppu, sys_mempool_t mempool) { sysPrxForUser.warning("sys_mempool_destroy(mempool=%d)", mempool); - auto memory_pool = idm::get(mempool); + auto memory_pool = idm::get_unlocked(mempool); if (memory_pool) { u32 condid = memory_pool->condid; @@ -136,7 +136,7 @@ error_code sys_mempool_free_block(ppu_thread& ppu, sys_mempool_t mempool, vm::pt { sysPrxForUser.warning("sys_mempool_free_block(mempool=%d, block=*0x%x)", mempool, block); - auto memory_pool = idm::get(mempool); + auto memory_pool = idm::get_unlocked(mempool); if (!memory_pool) { return CELL_EINVAL; @@ -160,7 +160,7 @@ u64 sys_mempool_get_count(ppu_thread& ppu, sys_mempool_t mempool) { sysPrxForUser.warning("sys_mempool_get_count(mempool=%d)", mempool); - auto memory_pool = idm::get(mempool); + auto memory_pool = idm::get_unlocked(mempool); if (!memory_pool) { return CELL_EINVAL; @@ -175,7 +175,7 @@ vm::ptr sys_mempool_allocate_block(ppu_thread& ppu, sys_mempool_t mempool) { sysPrxForUser.warning("sys_mempool_allocate_block(mempool=%d)", mempool); - auto memory_pool = idm::get(mempool); + auto memory_pool = idm::get_unlocked(mempool); if (!memory_pool) { // if the memory pool gets deleted-- is null, clearly it's impossible to allocate memory. return vm::null; @@ -185,7 +185,7 @@ vm::ptr sys_mempool_allocate_block(ppu_thread& ppu, sys_mempool_t mempool) while (memory_pool->free_blocks.empty()) // while is to guard against spurious wakeups { sys_cond_wait(ppu, memory_pool->condid, 0); - memory_pool = idm::get(mempool); + memory_pool = idm::get_unlocked(mempool); if (!memory_pool) // in case spurious wake up was from delete, don't die by accessing a freed pool. { // No need to unlock as if the pool is freed, the lock was freed as well. return vm::null; @@ -202,7 +202,7 @@ vm::ptr sys_mempool_try_allocate_block(ppu_thread& ppu, sys_mempool_t memp { sysPrxForUser.warning("sys_mempool_try_allocate_block(mempool=%d)", mempool); - auto memory_pool = idm::get(mempool); + auto memory_pool = idm::get_unlocked(mempool); if (!memory_pool || memory_pool->free_blocks.empty()) { diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 8d948cc972..1bab12a109 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "PPUAnalyser.h" +#include "lv2/sys_sync.h" + #include "PPUOpcodes.h" #include "PPUThread.h" @@ -37,7 +39,8 @@ void fmt_class_string>::format(std::string& out, u64 arg) format_bitset(out, arg, "[", ",", "]", &fmt_class_string::format); } -void ppu_module::validate(u32 reloc) +template <> +void ppu_module::validate(u32 reloc) { // Load custom PRX configuration if available if (fs::file yml{path + ".yml"}) @@ -529,7 +532,8 @@ namespace ppu_patterns }; } -bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::vector& applied, const std::vector& exported_funcs, std::function check_aborted) +template <> +bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::vector& applied, const std::vector& exported_funcs, std::function check_aborted) { if (segs.empty()) { diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index 287418e802..9d6f4ef9ed 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -72,8 +72,11 @@ struct ppu_segment }; // PPU Module Information -struct ppu_module +template +struct ppu_module : public Type { + using Type::Type; + ppu_module() noexcept = default; ppu_module(const ppu_module&) = delete; @@ -177,11 +180,16 @@ struct ppu_module } }; -struct main_ppu_module : public ppu_module +template +struct main_ppu_module : public ppu_module { u32 elf_entry{}; u32 seg0_code_end{}; std::vector applied_patches; + + // Disable inherited savestate ordering + void save(utils::serial&) = delete; + static constexpr double savestate_init_pos = double{}; }; // Aux diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index b82b6f5b29..d26f060b7d 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -576,7 +576,7 @@ extern const std::unordered_map& get_exported_function_na } // Resolve relocations for variable/function linkage. -static void ppu_patch_refs(const ppu_module& _module, std::vector* out_relocs, u32 fref, u32 faddr) +static void ppu_patch_refs(const ppu_module& _module, std::vector* out_relocs, u32 fref, u32 faddr) { struct ref_t { @@ -704,7 +704,7 @@ extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib) } // Load and register exports; return special exports found (nameless module) -static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false, std::vector* funcs = nullptr, std::basic_string* loaded_flags = nullptr) +static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false, std::vector* funcs = nullptr, std::basic_string* loaded_flags = nullptr) { std::unordered_map result; @@ -803,7 +803,7 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, const auto fnids = +lib.nids; const auto faddrs = +lib.addrs; - u32 previous_rtoc = umax; + u64 previous_rtoc = umax; // Get functions for (u32 i = 0, end = lib.num_func; i < end; i++) @@ -816,21 +816,22 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, { if (previous_rtoc == fdata.rtoc) { - ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x [at:0x%x] rtoc=same", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, fdata.addr); + // Shortened printing, replacement string is 10 characters as 0x%08x + ppu_loader.notice("**** %s export: (0x%08x) at 0x%07x [at:0x%07x, rtoc:same-above]: %s", module_name, fnid, faddr, fdata.addr, ppu_get_function_name(module_name, fnid)); } else { previous_rtoc = fdata.rtoc; - ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x [at:0x%x] rtoc=0x%x", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, fdata.addr, fdata.rtoc); + ppu_loader.notice("**** %s export: (0x%08x) at 0x%07x [at:0x%07x, rtoc:0x%08x]: %s", module_name, fnid, faddr, fdata.addr, fdata.rtoc, ppu_get_function_name(module_name, fnid)); } } else if (fptr) { - ppu_loader.error("**** %s export: [%s] (0x%08x) at 0x%x [Invalid Function Address: 0x%x!]", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, fdata.addr); + ppu_loader.error("**** %s export: (0x%08x) at 0x%07x [Invalid Function Address: 0x%07x!]: '%s'", module_name, fnid, faddr, fdata.addr, ppu_get_function_name(module_name, fnid)); } else { - ppu_loader.warning("**** %s export: [%s] (0x%08x) at 0x%x [Illegal Descriptor Address!]", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr); + ppu_loader.warning("**** %s export: (0x%08x) at 0x%07x [Illegal Descriptor Address!]: '%s'", module_name, fnid, faddr, ppu_get_function_name(module_name, fnid)); } if (funcs) @@ -938,7 +939,7 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, return result; } -static auto ppu_load_imports(const ppu_module& _module, std::vector& relocs, ppu_linkage_info* link, u32 imports_start, u32 imports_end) +static auto ppu_load_imports(const ppu_module& _module, std::vector& relocs, ppu_linkage_info* link, u32 imports_start, u32 imports_end) { std::unordered_map result; @@ -1030,10 +1031,10 @@ static auto ppu_load_imports(const ppu_module& _module, std::vector& // For _sys_prx_register_module void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 exports_start, u32 exports_size, std::basic_string& loaded_flags) { - auto& _main = g_fxo->get(); + auto& _main = g_fxo->get>(); auto& link = g_fxo->get(); - ppu_module vm_all_fake_module{}; + ppu_module vm_all_fake_module{}; vm_all_fake_module.segs.emplace_back(ppu_segment{0x10000, 0 - 0x10000u, 1 /*LOAD*/, 0, 0 - 0x1000u, vm::base(0x10000)}); vm_all_fake_module.addr_to_seg_index.emplace(0x10000, 0); @@ -1130,7 +1131,7 @@ void init_ppu_functions(utils::serial* ar, bool full = false) } } -static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu_segment& seg) +static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu_segment& seg) { if (!seg.size) { @@ -1139,7 +1140,7 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu_segment& const bool is_firmware = mod.path.starts_with(vfs::get("/dev_flash/")); - const auto _main = g_fxo->try_get(); + const auto _main = g_fxo->try_get>(); const std::string_view seg_view{ensure(mod.get_ptr(seg.addr)), seg.size}; @@ -1430,10 +1431,10 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu_segment& } } -void try_spawn_ppu_if_exclusive_program(const ppu_module& m) +void try_spawn_ppu_if_exclusive_program(const ppu_module& m) { // If only PRX/OVL has been loaded at Emu.BootGame(), launch a single PPU thread so its memory can be viewed - if (Emu.IsReady() && g_fxo->get().segs.empty() && !Emu.DeserialManager()) + if (Emu.IsReady() && g_fxo->get>().segs.empty() && !Emu.DeserialManager()) { ppu_thread_params p { @@ -1521,15 +1522,15 @@ const char* get_prx_name_by_cia(u32 addr) return nullptr; } -std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar) +shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar) { if (elf != elf_error::ok) { - return nullptr; + return null_ptr; } // Create new PRX object - const auto prx = !ar && !virtual_load ? idm::make_ptr() : std::make_shared(); + const auto prx = !ar && !virtual_load ? idm::make_ptr() : make_shared(); // Access linkage information object auto& link = g_fxo->get(); @@ -2054,7 +2055,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str init_ppu_functions(ar, false); // Set for delayed initialization in ppu_initialize() - auto& _main = g_fxo->get(); + auto& _main = g_fxo->get>(); // Access linkage information object auto& link = g_fxo->get(); @@ -2080,7 +2081,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str struct on_fatal_error { - ppu_module& _main; + ppu_module& _main; bool errored = true; ~on_fatal_error() @@ -2498,7 +2499,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str } // Initialize process - std::vector> loaded_modules; + std::vector> loaded_modules; // Module list to load at startup std::set load_libs; @@ -2778,11 +2779,11 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str return true; } -std::pair, CellError> ppu_load_overlay(const ppu_exec_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar) +std::pair, CellError> ppu_load_overlay(const ppu_exec_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar) { if (elf != elf_error::ok) { - return {nullptr, CELL_ENOENT}; + return {null_ptr, CELL_ENOENT}; } // Access linkage information object @@ -2804,12 +2805,12 @@ std::pair, CellError> ppu_load_overlay(const ppu_ex if (!r.valid() || !r.inside(addr_range::start_length(0x30000000, 0x10000000))) { // TODO: Check error and if there's a better way to error check - return {nullptr, CELL_ENOEXEC}; + return {null_ptr, CELL_ENOEXEC}; } } } - std::shared_ptr ovlm = std::make_shared(); + shared_ptr ovlm = make_shared(); // Set path (TODO) ovlm->name = path.substr(path.find_last_of('/') + 1); @@ -2859,7 +2860,7 @@ std::pair, CellError> ppu_load_overlay(const ppu_ex if (!vm::check_addr(addr, vm::page_readable, size)) { ppu_loader.error("ppu_load_overlay(): Archived PPU overlay memory has not been found! (addr=0x%x, memsz=0x%x)", addr, size); - return {nullptr, CELL_EABORT}; + return {null_ptr, CELL_EABORT}; } } else if (!vm::get(vm::any, 0x30000000)->falloc(addr, size)) @@ -2873,7 +2874,7 @@ std::pair, CellError> ppu_load_overlay(const ppu_ex } // TODO: Check error code, maybe disallow more than one overlay instance completely - return {nullptr, CELL_EBUSY}; + return {null_ptr, CELL_EBUSY}; } // Store only LOAD segments (TODO) @@ -3088,7 +3089,7 @@ std::pair, CellError> ppu_load_overlay(const ppu_ex return !!(cpu->state & cpu_flag::exit); })) { - return {nullptr, CellError{CELL_CANCEL + 0u}}; + return {null_ptr, CellError{CELL_CANCEL + 0u}}; } // Validate analyser results (not required) @@ -3105,11 +3106,11 @@ std::pair, CellError> ppu_load_overlay(const ppu_ex bool ppu_load_rel_exec(const ppu_rel_object& elf) { - ppu_module relm{}; + ppu_module relm{}; struct on_fatal_error { - ppu_module& relm; + ppu_module& relm; bool errored = true; ~on_fatal_error() diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 50fdca7643..8001b95ac4 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -174,13 +174,13 @@ bool serialize(utils::serial& ar, typename ppu_thread::cr_b } extern void ppu_initialize(); -extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false); -extern bool ppu_initialize(const ppu_module& info, bool check_only = false, u64 file_size = 0); -static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name, const ppu_module& whole_module); +extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false); +extern bool ppu_initialize(const ppu_module& info, bool check_only = false, u64 file_size = 0); +static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name, const ppu_module& whole_module); extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr); -extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* = nullptr); +extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* = nullptr); extern void ppu_unload_prx(const lv2_prx&); -extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 file_offset, utils::serial* = nullptr); +extern shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 file_offset, utils::serial* = nullptr); extern void ppu_execute_syscall(ppu_thread& ppu, u64 code); static void ppu_break(ppu_thread&, ppu_opcode_t, be_t*, ppu_intrp_func*); @@ -550,7 +550,7 @@ u32 ppu_read_mmio_aware_u32(u8* vm_base, u32 eal) if (eal >= RAW_SPU_BASE_ADDR) { // RawSPU MMIO - auto thread = idm::get>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); + auto thread = idm::get_unlocked>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); if (!thread) { @@ -578,7 +578,7 @@ void ppu_write_mmio_aware_u32(u8* vm_base, u32 eal, u32 value) if (eal >= RAW_SPU_BASE_ADDR) { // RawSPU MMIO - auto thread = idm::get>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); + auto thread = idm::get_unlocked>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); if (!thread) { @@ -3450,7 +3450,7 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value) { if (count > 20000 && g_cfg.core.perf_report) [[unlikely]] { - perf_log.warning(u8"STCX: took too long: %.3fµs (%u c)", count / (utils::get_tsc_freq() / 1000'000.), count); + perf_log.warning("STCX: took too long: %.3fus (%u c)", count / (utils::get_tsc_freq() / 1000'000.), count); } break; @@ -3837,7 +3837,7 @@ extern fs::file make_file_view(fs::file&& _file, u64 offset, u64 max_size = umax return file; } -extern void ppu_finalize(const ppu_module& info, bool force_mem_release) +extern void ppu_finalize(const ppu_module& info, bool force_mem_release) { if (info.segs.empty()) { @@ -3885,7 +3885,7 @@ extern void ppu_finalize(const ppu_module& info, bool force_mem_release) #endif } -extern void ppu_precompile(std::vector& dir_queue, std::vector* loaded_modules) +extern void ppu_precompile(std::vector& dir_queue, std::vector*>* loaded_modules) { if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm) { @@ -3978,7 +3978,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vectorbegin(), loaded_modules->end(), [&](ppu_module* obj) + if (std::any_of(loaded_modules->begin(), loaded_modules->end(), [&](ppu_module* obj) { return obj->name == entry.name; })) @@ -4311,7 +4311,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vectorget()); + auto main_module = std::move(g_fxo->get>()); for (; slice; slice.pop_front(), g_progr_fdone++) { @@ -4348,7 +4348,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vectorget(); + main_ppu_module& _main = g_fxo->get>(); _main = {}; auto current_cache = std::move(g_fxo->get()); @@ -4393,7 +4393,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vectorget() = std::move(main_module); + g_fxo->get>() = std::move(main_module); g_fxo->get().collect_funcs_to_precompile = true; Emu.ConfigurePPUCache(); }); @@ -4403,7 +4403,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vectoris_init()) + if (!g_fxo->is_init>()) { return; } @@ -4413,7 +4413,7 @@ extern void ppu_initialize() return; } - auto& _main = g_fxo->get(); + auto& _main = g_fxo->get>(); std::optional progress_dialog(std::in_place, get_localized_string(localized_string_id::PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE)); @@ -4436,7 +4436,7 @@ extern void ppu_initialize() compile_main = ppu_initialize(_main, true); } - std::vector module_list; + std::vector*> module_list; const std::string firmware_sprx_path = vfs::get("/dev_flash/sys/external/"); @@ -4541,7 +4541,7 @@ extern void ppu_initialize() } } -bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) +bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) { if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm) { @@ -4668,7 +4668,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) const u32 reloc = info.relocs.empty() ? 0 : ::at32(info.segs, 0).addr; // Info sent to threads - std::vector> workload; + std::vector>> workload; // Info to load to main JIT instance (true - compiled) std::vector> link_workload; @@ -4733,7 +4733,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) } // Copy module information (TODO: optimize) - ppu_module part; + ppu_module part; part.copy_part(info); part.funcs.reserve(16000); @@ -5035,15 +5035,15 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) struct thread_op { atomic_t& work_cv; - std::vector>& workload; - const ppu_module& main_module; + std::vector>>& workload; + const ppu_module& main_module; const std::string& cache_path; const cpu_thread* cpu; std::unique_lock core_lock; - thread_op(atomic_t& work_cv, std::vector>& workload - , const cpu_thread* cpu, const ppu_module& main_module, const std::string& cache_path, decltype(jit_core_allocator::sem)& sem) noexcept + thread_op(atomic_t& work_cv, std::vector>>& workload + , const cpu_thread* cpu, const ppu_module& main_module, const std::string& cache_path, decltype(jit_core_allocator::sem)& sem) noexcept : work_cv(work_cv) , workload(workload) @@ -5257,7 +5257,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_size) #endif } -static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name, const ppu_module& whole_module) +static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name, const ppu_module& whole_module) { #ifdef LLVM_AVAILABLE using namespace llvm; diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index c2102af38f..edbb4f515a 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -3,6 +3,7 @@ #include "Emu/system_config.h" #include "Emu/Cell/Common.h" +#include "Emu/Cell/lv2/sys_sync.h" #include "PPUTranslator.h" #include "PPUThread.h" #include "SPUThread.h" @@ -28,7 +29,7 @@ const ppu_decoder s_ppu_decoder; extern const ppu_decoder g_ppu_itype; extern const ppu_decoder g_ppu_iname; -PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_module& info, ExecutionEngine& engine) +PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_module& info, ExecutionEngine& engine) : cpu_translator(_module, false) , m_info(info) , m_pure_attr() @@ -322,7 +323,7 @@ Function* PPUTranslator::Translate(const ppu_function& info) return m_function; } -Function* PPUTranslator::GetSymbolResolver(const ppu_module& info) +Function* PPUTranslator::GetSymbolResolver(const ppu_module& info) { m_function = cast(m_module->getOrInsertFunction("__resolve_symbols", FunctionType::get(get_type(), { get_type(), get_type() }, false)).getCallee()); diff --git a/rpcs3/Emu/Cell/PPUTranslator.h b/rpcs3/Emu/Cell/PPUTranslator.h index a71e42a033..010945656e 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.h +++ b/rpcs3/Emu/Cell/PPUTranslator.h @@ -8,10 +8,15 @@ #include "util/types.hpp" +template +struct ppu_module; + +struct lv2_obj; + class PPUTranslator final : public cpu_translator { // PPU Module - const ppu_module& m_info; + const ppu_module& m_info; // Relevant relocations std::map m_relocs; @@ -331,7 +336,7 @@ public: // Handle compilation errors void CompilationError(const std::string& error); - PPUTranslator(llvm::LLVMContext& context, llvm::Module* _module, const ppu_module& info, llvm::ExecutionEngine& engine); + PPUTranslator(llvm::LLVMContext& context, llvm::Module* _module, const ppu_module& info, llvm::ExecutionEngine& engine); ~PPUTranslator(); // Get thread context struct type @@ -339,7 +344,7 @@ public: // Parses PPU opcodes and translate them into LLVM IR llvm::Function* Translate(const ppu_function& info); - llvm::Function* GetSymbolResolver(const ppu_module& info); + llvm::Function* GetSymbolResolver(const ppu_module& info); void MFVSCR(ppu_opcode_t op); void MTVSCR(ppu_opcode_t op); diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index fcc21c09ae..4fae99e344 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -4666,35 +4666,44 @@ public: return zshuffle(std::forward(a), 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); } + template + static llvm_calli rotqbybi(T&& a, U&& b) + { + return {"spu_rotqbybi", {std::forward(a), std::forward(b)}}; + } + void ROTQBYBI(spu_opcode_t op) { - const auto a = get_vr(op.ra); - - // Data with swapped endian from a load instruction - if (auto [ok, as] = match_expr(a, byteswap(match())); ok) + register_intrinsic("spu_rotqbybi", [&](llvm::CallInst* ci) { - const auto sc = build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - const auto sh = sc + (splat_scalar(get_vr(op.rb)) >> 3); + const auto a = value(ci->getOperand(0)); + const auto b = value(ci->getOperand(1)); + + // Data with swapped endian from a load instruction + if (auto [ok, as] = match_expr(a, byteswap(match())); ok) + { + const auto sc = build(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + const auto sh = sc + (splat_scalar(b) >> 3); + + if (m_use_avx512_icl) + { + return eval(vpermb(as, sh)); + } + + return eval(pshufb(as, (sh & 0xf))); + } + const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const auto sh = sc - (splat_scalar(b) >> 3); if (m_use_avx512_icl) { - set_vr(op.rt, vpermb(as, sh)); - return; + return eval(vpermb(a, sh)); } - set_vr(op.rt, pshufb(as, (sh & 0xf))); - return; - } - const auto sc = build(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - const auto sh = sc - (splat_scalar(get_vr(op.rb)) >> 3); + return eval(pshufb(a, (sh & 0xf))); + }); - if (m_use_avx512_icl) - { - set_vr(op.rt, vpermb(a, sh)); - return; - } - - set_vr(op.rt, pshufb(a, (sh & 0xf))); + set_vr(op.rt, rotqbybi(get_vr(op.ra), get_vr(op.rb))); } void ROTQMBYBI(spu_opcode_t op) @@ -4813,6 +4822,39 @@ public: void ROTQBI(spu_opcode_t op) { const auto a = get_vr(op.ra); + const auto ax = get_vr(op.ra); + const auto bx = get_vr(op.rb); + + // Combined bit and bytes shift + if (auto [ok, v0, v1] = match_expr(ax, rotqbybi(match(), match())); ok && v1.eq(bx)) + { + const auto b32 = get_vr(op.rb); + + // Is the rotate less than 31 bits? + if (auto k = get_known_bits(b32); (k.Zero & 0x60) == 0x60u) + { + const auto b = splat_scalar(get_vr(op.rb)); + set_vr(op.rt, fshl(bitcast(v0), zshuffle(bitcast(v0), 3, 0, 1, 2), b)); + return; + } + + // Inverted shift count + if (auto [ok1, v10, v11] = match_expr(b32, match() - match()); ok1) + { + if (auto [ok2, data] = get_const_vector(v10.value, m_pos); ok2) + { + if ((data & v128::from32p(0x7f)) == v128{}) + { + if (auto k = get_known_bits(v11); (k.Zero & 0x60) == 0x60u) + { + set_vr(op.rt, fshr(zshuffle(bitcast(v0), 1, 2, 3, 0), bitcast(v0), splat_scalar(bitcast(v11)))); + return; + } + } + } + } + } + const auto b = splat_scalar(get_vr(op.rb) & 0x7); set_vr(op.rt, fshl(a, zshuffle(a, 3, 0, 1, 2), b)); } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 21a739664e..456c9894be 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2415,7 +2415,7 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* if (eal < SYS_SPU_THREAD_BASE_LOW) { // RawSPU MMIO - auto thread = idm::get>(find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); + auto thread = idm::get_unlocked>(find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET)); if (!thread) { @@ -3837,7 +3837,7 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) if (count2 > 20000 && g_cfg.core.perf_report) [[unlikely]] { - perf_log.warning(u8"PUTLLC: took too long: %.3fµs (%u c) (addr=0x%x) (S)", count2 / (utils::get_tsc_freq() / 1000'000.), count2, addr); + perf_log.warning("PUTLLC: took too long: %.3fus (%u c) (addr=0x%x) (S)", count2 / (utils::get_tsc_freq() / 1000'000.), count2, addr); } if (ok) @@ -3872,7 +3872,7 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) { if (count > 20000 && g_cfg.core.perf_report) [[unlikely]] { - perf_log.warning(u8"PUTLLC: took too long: %.3fµs (%u c) (addr = 0x%x)", count / (utils::get_tsc_freq() / 1000'000.), count, addr); + perf_log.warning("PUTLLC: took too long: %.3fus (%u c) (addr = 0x%x)", count / (utils::get_tsc_freq() / 1000'000.), count, addr); } break; @@ -4087,7 +4087,7 @@ void do_cell_atomic_128_store(u32 addr, const void* to_write) if (result > 20000 && g_cfg.core.perf_report) [[unlikely]] { - perf_log.warning(u8"STORE128: took too long: %.3fµs (%u c) (addr=0x%x)", result / (utils::get_tsc_freq() / 1000'000.), result, addr); + perf_log.warning("STORE128: took too long: %.3fus (%u c) (addr=0x%x)", result / (utils::get_tsc_freq() / 1000'000.), result, addr); } static_cast(cpu->test_stopped()); @@ -6007,7 +6007,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value) spu_function_logger logger(*this, "sys_spu_thread_send_event"); - std::shared_ptr queue; + shared_ptr queue; { std::lock_guard lock(group->mutex); @@ -6059,7 +6059,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value) spu_function_logger logger(*this, "sys_spu_thread_throw_event"); - std::shared_ptr queue; + shared_ptr queue; { std::lock_guard lock{group->mutex}; queue = this->spup[spup]; @@ -6447,7 +6447,7 @@ bool spu_thread::stop_and_signal(u32 code) return true; } - auto get_queue = [this](u32 spuq) -> const std::shared_ptr& + auto get_queue = [this](u32 spuq) -> const shared_ptr& { for (auto& v : this->spuq) { @@ -6460,7 +6460,7 @@ bool spu_thread::stop_and_signal(u32 code) } } - static const std::shared_ptr empty; + static const shared_ptr empty; return empty; }; @@ -6523,7 +6523,7 @@ bool spu_thread::stop_and_signal(u32 code) spu_function_logger logger(*this, "sys_spu_thread_receive_event"); - std::shared_ptr queue; + shared_ptr queue; while (true) { @@ -6665,7 +6665,7 @@ bool spu_thread::stop_and_signal(u32 code) spu_log.trace("sys_spu_thread_tryreceive_event(spuq=0x%x)", spuq); - std::shared_ptr queue; + shared_ptr queue; reader_lock{group->mutex}, queue = get_queue(spuq); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 2d91563a14..c895e09211 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -453,7 +453,7 @@ struct spu_int_ctrl_t atomic_t mask; atomic_t stat; - std::shared_ptr tag; + shared_ptr tag; void set(u64 ints); @@ -755,8 +755,8 @@ public: atomic_t status_npc{}; std::array int_ctrl{}; // SPU Class 0, 1, 2 Interrupt Management - std::array>, 32> spuq{}; // Event Queue Keys for SPU Thread - std::shared_ptr spup[64]; // SPU Ports + std::array>, 32> spuq{}; // Event Queue Keys for SPU Thread + shared_ptr spup[64]; // SPU Ports spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits) atomic_t last_exit_status; // Value to be written in exit_status after checking group termination lv2_spu_group* const group; // SPU Thread Group (access by the spu threads in the group only! From other threads obtain a shared pointer to group using group ID) diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp index 765948a908..bcfe83aed3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -14,11 +14,21 @@ LOG_CHANNEL(sys_cond); -lv2_cond::lv2_cond(utils::serial& ar) +lv2_cond::lv2_cond(utils::serial& ar) noexcept : key(ar) , name(ar) , mtx_id(ar) - , mutex(idm::get_unlocked(mtx_id)) // May be nullptr + , mutex(idm::check_unlocked(mtx_id)) + , _mutex(idm::get_unlocked(mtx_id)) // May be nullptr +{ +} + +lv2_cond::lv2_cond(u64 key, u64 name, u32 mtx_id, shared_ptr mutex0) noexcept + : key(key) + , name(name) + , mtx_id(mtx_id) + , mutex(static_cast(mutex0.get())) + , _mutex(mutex0) { } @@ -49,7 +59,7 @@ CellError lv2_cond::on_id_create() { if (!mutex) { - mutex = ensure(idm::get_unlocked(mtx_id)); + _mutex = static_cast>(ensure(idm::get_unlocked(mtx_id))); } // Defer function @@ -59,10 +69,9 @@ CellError lv2_cond::on_id_create() return {}; } -std::shared_ptr lv2_cond::load(utils::serial& ar) +std::function lv2_cond::load(utils::serial& ar) { - auto cond = std::make_shared(ar); - return lv2_obj::load(cond->key, cond); + return load_func(make_shared(ar)); } void lv2_cond::save(utils::serial& ar) @@ -76,7 +85,7 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr cond_id, u32 mutex_id, sys_cond.trace("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr); - auto mutex = idm::get(mutex_id); + auto mutex = idm::get_unlocked(mutex_id); if (!mutex) { @@ -94,7 +103,7 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr cond_id, u32 mutex_id, if (const auto error = lv2_obj::create(_attr.pshared, ipc_key, _attr.flags, [&] { - return std::make_shared( + return make_single( ipc_key, _attr.name_u64, mutex_id, diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h index 54613250ed..60e7c24e61 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -26,19 +26,14 @@ struct lv2_cond final : lv2_obj const u64 name; const u32 mtx_id; - std::shared_ptr mutex; // Associated Mutex + lv2_mutex* mutex; // Associated Mutex + shared_ptr _mutex; ppu_thread* sq{}; - lv2_cond(u64 key, u64 name, u32 mtx_id, std::shared_ptr mutex) - : key(key) - , name(name) - , mtx_id(mtx_id) - , mutex(std::move(mutex)) - { - } + lv2_cond(u64 key, u64 name, u32 mtx_id, shared_ptr mutex0) noexcept; - lv2_cond(utils::serial& ar); - static std::shared_ptr load(utils::serial& ar); + lv2_cond(utils::serial& ar) noexcept; + static std::function load(utils::serial& ar); void save(utils::serial& ar); CellError on_id_create(); diff --git a/rpcs3/Emu/Cell/lv2/sys_config.cpp b/rpcs3/Emu/Cell/lv2/sys_config.cpp index 629beb6d23..c39444ccd0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_config.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_config.cpp @@ -101,18 +101,37 @@ void lv2_config::initialize() lv2_config_service::create(SYS_CONFIG_SERVICE_PADMANAGER2, 0, 1, 0, hid_info, 0x1a)->notify(); } -void lv2_config::add_service_event(const std::shared_ptr& event) +void lv2_config::add_service_event(shared_ptr event) { std::lock_guard lock(m_mutex); - events.emplace(event->id, event); + events.emplace(event->id, std::move(event)); } void lv2_config::remove_service_event(u32 id) { + shared_ptr ptr; + std::lock_guard lock(m_mutex); - events.erase(id); + + if (auto it = events.find(id); it != events.end()) + { + ptr = std::move(it->second); + events.erase(it); + } } +lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept +{ + if (s == thread_state::finished) + { + if (auto global = g_fxo->try_get()) + { + global->remove_service_event(id); + } + } + + return *this; +} // LV2 Config Service Listener bool lv2_config_service_listener::check_service(const lv2_config_service& service) const @@ -140,13 +159,13 @@ bool lv2_config_service_listener::check_service(const lv2_config_service& servic return true; } -bool lv2_config_service_listener::notify(const std::shared_ptr& event) +bool lv2_config_service_listener::notify(const shared_ptr& event) { service_events.emplace_back(event); return event->notify(); } -bool lv2_config_service_listener::notify(const std::shared_ptr& service) +bool lv2_config_service_listener::notify(const shared_ptr& service) { if (!check_service(*service)) return false; @@ -158,7 +177,7 @@ bool lv2_config_service_listener::notify(const std::shared_ptr> services; + std::vector> services; // Grab all events idm::select([&](u32 /*id*/, lv2_config_service& service) @@ -170,7 +189,7 @@ void lv2_config_service_listener::notify_all() }); // Sort services by timestamp - sort(services.begin(), services.end(), [](const std::shared_ptr& s1, const std::shared_ptr& s2) + sort(services.begin(), services.end(), [](const shared_ptr& s1, const shared_ptr& s2) { return s1->timestamp < s2->timestamp; }); @@ -198,9 +217,9 @@ void lv2_config_service::unregister() void lv2_config_service::notify() const { - std::vector> listeners; + std::vector> listeners; - auto sptr = wkptr.lock(); + const shared_ptr sptr = get_shared_ptr(); idm::select([&](u32 /*id*/, lv2_config_service_listener& listener) { @@ -210,13 +229,14 @@ void lv2_config_service::notify() const for (auto& listener : listeners) { - listener->notify(this->get_shared_ptr()); + listener->notify(sptr); } } bool lv2_config_service_event::notify() const { - const auto _handle = handle.lock(); + const auto _handle = handle; + if (!_handle) { return false; @@ -259,7 +279,7 @@ error_code sys_config_open(u32 equeue_hdl, vm::ptr out_config_hdl) sys_config.trace("sys_config_open(equeue_hdl=0x%x, out_config_hdl=*0x%x)", equeue_hdl, out_config_hdl); // Find queue with the given ID - const auto queue = idm::get(equeue_hdl); + const auto queue = idm::get_unlocked(equeue_hdl); if (!queue) { return CELL_ESRCH; @@ -303,7 +323,7 @@ error_code sys_config_get_service_event(u32 config_hdl, u32 event_id, vm::ptr(config_hdl); + const auto cfg = idm::get_unlocked(config_hdl); if (!cfg) { return CELL_ESRCH; @@ -335,7 +355,7 @@ error_code sys_config_add_service_listener(u32 config_hdl, sys_config_service_id sys_config.trace("sys_config_add_service_listener(config_hdl=0x%x, service_id=0x%llx, min_verbosity=0x%llx, in=*0x%x, size=%lld, type=0x%llx, out_listener_hdl=*0x%x)", config_hdl, service_id, min_verbosity, in, size, type, out_listener_hdl); // Find sys_config handle object with the given ID - auto cfg = idm::get(config_hdl); + auto cfg = idm::get_unlocked(config_hdl); if (!cfg) { return CELL_ESRCH; @@ -383,7 +403,7 @@ error_code sys_config_register_service(u32 config_hdl, sys_config_service_id ser sys_config.trace("sys_config_register_service(config_hdl=0x%x, service_id=0x%llx, user_id=0x%llx, verbosity=0x%llx, data_but=*0x%llx, size=%lld, out_service_hdl=*0x%llx)", config_hdl, service_id, user_id, verbosity, data_buf, size, out_service_hdl); // Find sys_config handle object with the given ID - const auto cfg = idm::get(config_hdl); + const auto cfg = idm::get_unlocked(config_hdl); if (!cfg) { return CELL_ESRCH; diff --git a/rpcs3/Emu/Cell/lv2/sys_config.h b/rpcs3/Emu/Cell/lv2/sys_config.h index 36a2b3993d..3915dfc8cb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_config.h +++ b/rpcs3/Emu/Cell/lv2/sys_config.h @@ -3,6 +3,9 @@ #include #include +#include "util/atomic.hpp" +#include "util/shared_ptr.hpp" + /* * sys_config is a "subscription-based data storage API" @@ -133,30 +136,30 @@ class lv2_config shared_mutex m_mutex; // Map of LV2 Service Events - std::unordered_map> events; + std::unordered_map> events; public: void initialize(); // Service Events - void add_service_event(const std::shared_ptr& event); + void add_service_event(shared_ptr event); void remove_service_event(u32 id); - std::shared_ptr find_event(u32 id) + shared_ptr find_event(u32 id) { reader_lock lock(m_mutex); const auto it = events.find(id); if (it == events.cend()) - return nullptr; + return null_ptr; - if (auto event = it->second.lock()) + if (it->second) { - return event; + return it->second; } - return nullptr; + return null_ptr; } }; @@ -175,33 +178,35 @@ private: u32 idm_id; // queue for service/io event notifications - const std::weak_ptr queue; + const shared_ptr queue; bool send_queue_event(u64 source, u64 d1, u64 d2, u64 d3) const { - if (auto sptr = queue.lock()) + if (auto sptr = queue) { return sptr->send(source, d1, d2, d3) == 0; } + return false; } public: // Constructors (should not be used directly) - lv2_config_handle(std::weak_ptr&& _queue) + lv2_config_handle(shared_ptr _queue) noexcept : queue(std::move(_queue)) - {} + { + } // Factory template - static std::shared_ptr create(Args&&... args) + static shared_ptr create(Args&&... args) { if (auto cfg = idm::make_ptr(std::forward(args)...)) { cfg->idm_id = idm::last_id(); return cfg; } - return nullptr; + return null_ptr; } // Notify event queue for this handle @@ -225,7 +230,6 @@ public: private: // IDM data u32 idm_id; - std::weak_ptr wkptr; // Whether this service is currently registered or not bool registered = true; @@ -240,27 +244,27 @@ public: const std::vector data; // Constructors (should not be used directly) - lv2_config_service(sys_config_service_id _id, u64 _user_id, u64 _verbosity, u32 _padding, const u8 _data[], usz size) + lv2_config_service(sys_config_service_id _id, u64 _user_id, u64 _verbosity, u32 _padding, const u8* _data, usz size) noexcept : timestamp(get_system_time()) , id(_id) , user_id(_user_id) , verbosity(_verbosity) , padding(_padding) , data(&_data[0], &_data[size]) - {} + { + } // Factory template - static std::shared_ptr create(Args&&... args) + static shared_ptr create(Args&&... args) { if (auto service = idm::make_ptr(std::forward(args)...)) { - service->wkptr = service; service->idm_id = idm::last_id(); return service; } - return nullptr; + return null_ptr; } // Registration @@ -272,7 +276,7 @@ public: // Utilities usz get_size() const { return sizeof(sys_config_service_event_t)-1 + data.size(); } - std::shared_ptr get_shared_ptr () const { return wkptr.lock(); } + shared_ptr get_shared_ptr () const { return idm::get_unlocked(idm_id); } u32 get_id() const { return idm_id; } }; @@ -290,14 +294,13 @@ public: private: // IDM data u32 idm_id; - std::weak_ptr wkptr; // The service listener owns the service events - service events will not be freed as long as their corresponding listener exists // This has been confirmed to be the case in realhw - std::vector> service_events; - std::weak_ptr handle; + std::vector> service_events; + shared_ptr handle; - bool notify(const std::shared_ptr& event); + bool notify(const shared_ptr& event); public: const sys_config_service_id service_id; @@ -307,8 +310,8 @@ public: const std::vector data; // Constructors (should not be used directly) - lv2_config_service_listener(std::shared_ptr& _handle, sys_config_service_id _service_id, u64 _min_verbosity, sys_config_service_listener_type _type, const u8 _data[], usz size) - : handle(_handle) + lv2_config_service_listener(shared_ptr _handle, sys_config_service_id _service_id, u64 _min_verbosity, sys_config_service_listener_type _type, const u8* _data, usz size) noexcept + : handle(std::move(_handle)) , service_id(_service_id) , min_verbosity(_min_verbosity) , type(_type) @@ -317,30 +320,29 @@ public: // Factory template - static std::shared_ptr create(Args&&... args) + static shared_ptr create(Args&&... args) { if (auto listener = idm::make_ptr(std::forward(args)...)) { - listener->wkptr = listener; listener->idm_id = idm::last_id(); return listener; } - return nullptr; + return null_ptr; } // Check whether service matches bool check_service(const lv2_config_service& service) const; // Register new event, and notify queue - bool notify(const std::shared_ptr& service); + bool notify(const shared_ptr& service); // (Re-)notify about all still-registered past events void notify_all(); // Utilities u32 get_id() const { return idm_id; } - std::shared_ptr get_shared_ptr() const { return wkptr.lock(); } + shared_ptr get_shared_ptr() const { return idm::get_unlocked(idm_id); } }; /* @@ -363,30 +365,24 @@ public: // Note: Events hold a shared_ptr to their corresponding service - services only get freed once there are no more pending service events // This has been confirmed to be the case in realhw - const std::weak_ptr handle; - const std::shared_ptr service; + const shared_ptr handle; + const shared_ptr service; const lv2_config_service_listener& listener; // Constructors (should not be used directly) - lv2_config_service_event(const std::weak_ptr& _handle, const std::shared_ptr& _service, const lv2_config_service_listener& _listener) - : id(get_next_id()) - , handle(_handle) - , service(_service) - , listener(_listener) - {} - - lv2_config_service_event(const std::weak_ptr&& _handle, const std::shared_ptr&& _service, const lv2_config_service_listener& _listener) + lv2_config_service_event(shared_ptr _handle, shared_ptr _service, const lv2_config_service_listener& _listener) noexcept : id(get_next_id()) , handle(std::move(_handle)) , service(std::move(_service)) , listener(_listener) - {} + { + } // Factory template - static std::shared_ptr create(Args&&... args) + static shared_ptr create(Args&&... args) { - auto ev = std::make_shared(std::forward(args)...); + auto ev = make_shared(std::forward(args)...); g_fxo->get().add_service_event(ev); @@ -394,13 +390,9 @@ public: } // Destructor - ~lv2_config_service_event() - { - if (auto global = g_fxo->try_get()) - { - global->remove_service_event(id); - } - } + lv2_config_service_event& operator=(thread_state s) noexcept; + + ~lv2_config_service_event() noexcept = default; // Notify queue that this event exists bool notify() const; diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index 81f4ff65b0..0428fd0f11 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -35,10 +35,10 @@ lv2_event_queue::lv2_event_queue(utils::serial& ar) noexcept ar(events); } -std::shared_ptr lv2_event_queue::load(utils::serial& ar) +std::function lv2_event_queue::load(utils::serial& ar) { - auto queue = std::make_shared(ar); - return lv2_obj::load(queue->key, queue); + auto queue = make_shared(ar); + return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast*>(storage) = ptr; }; } void lv2_event_queue::save(utils::serial& ar) @@ -57,13 +57,13 @@ void lv2_event_queue::save_ptr(utils::serial& ar, lv2_event_queue* q) ar(q->id); } -std::shared_ptr lv2_event_queue::load_ptr(utils::serial& ar, std::shared_ptr& queue, std::string_view msg) +shared_ptr lv2_event_queue::load_ptr(utils::serial& ar, shared_ptr& queue, std::string_view msg) { const u32 id = ar.pop(); if (!id) { - return nullptr; + return {}; } if (auto q = idm::get_unlocked(id)) @@ -89,7 +89,7 @@ std::shared_ptr lv2_event_queue::load_ptr(utils::serial& ar, st }); // Null until resolved - return nullptr; + return {}; } lv2_event_port::lv2_event_port(utils::serial& ar) @@ -106,7 +106,7 @@ void lv2_event_port::save(utils::serial& ar) lv2_event_queue::save_ptr(ar, queue.get()); } -std::shared_ptr lv2_event_queue::find(u64 ipc_key) +shared_ptr lv2_event_queue::find(u64 ipc_key) { if (ipc_key == SYS_EVENT_QUEUE_LOCAL) { @@ -238,7 +238,7 @@ error_code sys_event_queue_create(cpu_thread& cpu, vm::ptr equeue_id, vm::p if (const auto error = lv2_obj::create(pshared, ipc_key, flags, [&]() { - return std::make_shared(protocol, type, size, name, ipc_key); + return make_shared(protocol, type, size, name, ipc_key); })) { return error; @@ -394,7 +394,7 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr(equeue_id); + const auto queue = idm::get_unlocked(equeue_id); if (!queue) { diff --git a/rpcs3/Emu/Cell/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h index 506a45e7a0..6c43798a30 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -100,10 +100,10 @@ struct lv2_event_queue final : public lv2_obj lv2_event_queue(u32 protocol, s32 type, s32 size, u64 name, u64 ipc_key) noexcept; lv2_event_queue(utils::serial& ar) noexcept; - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); static void save_ptr(utils::serial&, lv2_event_queue*); - static std::shared_ptr load_ptr(utils::serial& ar, std::shared_ptr& queue, std::string_view msg = {}); + static shared_ptr load_ptr(utils::serial& ar, shared_ptr& queue, std::string_view msg = {}); CellError send(lv2_event event, bool* notified_thread = nullptr, lv2_event_port* port = nullptr); @@ -113,7 +113,7 @@ struct lv2_event_queue final : public lv2_obj } // Get event queue by its global key - static std::shared_ptr find(u64 ipc_key); + static shared_ptr find(u64 ipc_key); }; struct lv2_event_port final : lv2_obj @@ -124,7 +124,7 @@ struct lv2_event_port final : lv2_obj const u64 name; // Event source (generated from id and process id if not set) atomic_t is_busy = 0; // Counts threads waiting on event sending - std::shared_ptr queue; // Event queue this port is connected to + shared_ptr queue; // Event queue this port is connected to lv2_event_port(s32 type, u64 name) : type(type) diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index c5e3ee9781..6c630e9261 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -22,10 +22,9 @@ lv2_event_flag::lv2_event_flag(utils::serial& ar) ar(pattern); } -std::shared_ptr lv2_event_flag::load(utils::serial& ar) +std::function lv2_event_flag::load(utils::serial& ar) { - auto eflag = std::make_shared(ar); - return lv2_obj::load(eflag->key, eflag); + return load_func(make_shared(ar)); } void lv2_event_flag::save(utils::serial& ar) @@ -66,7 +65,7 @@ error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr id, vm::ptr(_attr.pshared, ipc_key, _attr.flags, [&] { - return std::make_shared( + return make_shared( _attr.protocol, ipc_key, _attr.type, @@ -330,7 +329,7 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn) // Warning: may be called from SPU thread. sys_event_flag.trace("sys_event_flag_set(id=0x%x, bitptn=0x%llx)", id, bitptn); - const auto flag = idm::get(id); + const auto flag = idm::get_unlocked(id); if (!flag) { @@ -502,7 +501,7 @@ error_code sys_event_flag_cancel(ppu_thread& ppu, u32 id, vm::ptr num) if (num) *num = 0; - const auto flag = idm::get(id); + const auto flag = idm::get_unlocked(id); if (!flag) { diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.h b/rpcs3/Emu/Cell/lv2/sys_event_flag.h index 6af8887b99..652ae95947 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.h +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.h @@ -54,7 +54,7 @@ struct lv2_event_flag final : lv2_obj } lv2_event_flag(utils::serial& ar); - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); // Check mode arg diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 29401b922b..3cb8e8eb2f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -79,7 +79,7 @@ void fmt_class_string::format(std::string& out, u64 arg) const usz pos = file.file ? file.file.pos() : umax; const usz size = file.file ? file.file.size() : umax; - fmt::append(out, u8"%s, “%s”, Mode: 0x%x, Flags: 0x%x, Pos/Size: %s/%s (0x%x/0x%x)", file.type, file.name.data(), file.mode, file.flags, get_size(pos), get_size(size), pos, size); + fmt::append(out, u8"%s, '%s', Mode: 0x%x, Flags: 0x%x, Pos/Size: %s/%s (0x%x/0x%x)", file.type, file.name.data(), file.mode, file.flags, get_size(pos), get_size(size), pos, size); } template<> @@ -87,7 +87,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { const auto& dir = get_object(arg); - fmt::append(out, u8"Directory, “%s”, Entries: %u/%u", dir.name.data(), std::min(dir.pos, dir.entries.size()), dir.entries.size()); + fmt::append(out, u8"Directory, '%s', Entries: %u/%u", dir.name.data(), std::min(dir.pos, dir.entries.size()), dir.entries.size()); } bool has_fs_write_rights(std::string_view vpath) @@ -615,11 +615,11 @@ void loaded_npdrm_keys::save(utils::serial& ar) struct lv2_file::file_view : fs::file_base { - const std::shared_ptr m_file; + const shared_ptr m_file; const u64 m_off; u64 m_pos; - explicit file_view(const std::shared_ptr& _file, u64 offset) + explicit file_view(const shared_ptr& _file, u64 offset) : m_file(_file) , m_off(offset) , m_pos(0) @@ -699,7 +699,7 @@ struct lv2_file::file_view : fs::file_base } }; -fs::file lv2_file::make_view(const std::shared_ptr& _file, u64 offset) +fs::file lv2_file::make_view(const shared_ptr& _file, u64 offset) { fs::file result; result.reset(std::make_unique(_file, offset)); @@ -745,7 +745,7 @@ error_code sys_fs_test(ppu_thread&, u32 arg1, u32 arg2, vm::ptr arg3, u32 a return CELL_EFAULT; } - const auto file = idm::get(*arg3); + const auto file = idm::get_unlocked(*arg3); if (!file) { @@ -1059,16 +1059,16 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr path, s32 flags, vm::ptr< return {g_fxo->get().lookup(vpath) == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, error, path}; } - if (const u32 id = idm::import([&ppath = ppath, &file = file, mode, flags, &real = real, &type = type]() -> std::shared_ptr + if (const u32 id = idm::import([&ppath = ppath, &file = file, mode, flags, &real = real, &type = type]() -> shared_ptr { - std::shared_ptr result; + shared_ptr result; if (type >= lv2_file_type::sdata && !g_fxo->get().npdrm_fds.try_inc(16)) { return result; } - result = std::make_shared(ppath, std::move(file), mode, flags, real, type); + result = stx::make_shared(ppath, std::move(file), mode, flags, real, type); sys_fs.warning("sys_fs_open(): fd=%u, %s", idm::last_id(), *result); return result; })) @@ -1100,7 +1100,7 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr buf, u64 nbytes, v return CELL_EFAULT; } - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file || (nbytes && file->flags & CELL_FS_O_WRONLY)) { @@ -1169,7 +1169,7 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr buf, u64 nbytes, return CELL_EFAULT; } - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file || (nbytes && !(file->flags & CELL_FS_O_ACCMODE))) { @@ -1239,7 +1239,7 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd) ppu.state += cpu_flag::wait; lv2_obj::sleep(ppu); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -1279,7 +1279,7 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd) auto& default_container = g_fxo->get(); std::lock_guard lock(default_container.mutex); - if (auto ct = idm::get(file->ct_id)) + if (auto ct = idm::get_unlocked(file->ct_id)) { ct->free(file->ct_used); if (default_container.id == file->ct_id) @@ -1442,7 +1442,7 @@ error_code sys_fs_readdir(ppu_thread& ppu, u32 fd, vm::ptr dir, vm return CELL_EFAULT; } - const auto directory = idm::get(fd); + const auto directory = idm::get_unlocked(fd); if (!directory) { @@ -1614,7 +1614,7 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr sb) sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -1960,7 +1960,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 return CELL_EINVAL; } - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -2056,7 +2056,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 return CELL_EINVAL; } - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -2081,14 +2081,14 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 fs::file stream; stream.reset(std::move(sdata_file)); - if (const u32 id = idm::import([&file = *file, &stream = stream]() -> std::shared_ptr + if (const u32 id = idm::import([&file = *file, &stream = stream]() -> shared_ptr { if (!g_fxo->get().npdrm_fds.try_inc(16)) { - return nullptr; + return null_ptr; } - return std::make_shared(file, std::move(stream), file.mode, CELL_FS_O_RDONLY, file.real_path, lv2_file_type::sdata); + return stx::make_shared(file, std::move(stream), file.mode, CELL_FS_O_RDONLY, file.real_path, lv2_file_type::sdata); })) { arg->out_code = CELL_OK; @@ -2198,13 +2198,13 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 return CELL_OK; } - auto file = idm::get(fd); + auto file = idm::get_unlocked(fd); if (!file) { return CELL_EBADF; } - if (auto ct = idm::get(file->ct_id)) + if (auto ct = idm::get_unlocked(file->ct_id)) { ct->free(file->ct_used); if (default_container.id == file->ct_id) @@ -2427,7 +2427,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 return CELL_EINVAL; } - const auto directory = idm::get(fd); + const auto directory = idm::get_unlocked(fd); if (!directory) { @@ -2566,14 +2566,14 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 return result.error; } - if (const u32 id = idm::import([&]() -> std::shared_ptr + if (const u32 id = idm::import([&]() -> shared_ptr { if (!g_fxo->get().npdrm_fds.try_inc(16)) { - return nullptr; + return null_ptr; } - return std::make_shared(result.ppath, std::move(result.file), 0, 0, std::move(result.real_path), lv2_file_type::sdata); + return stx::make_shared(result.ppath, std::move(result.file), 0, 0, std::move(result.real_path), lv2_file_type::sdata); })) { arg->out_code = CELL_OK; @@ -2597,7 +2597,7 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -2643,7 +2643,7 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd) sys_fs.trace("sys_fs_fdadasync(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file || !(file->flags & CELL_FS_O_ACCMODE)) { @@ -2668,7 +2668,7 @@ error_code sys_fs_fsync(ppu_thread& ppu, u32 fd) sys_fs.trace("sys_fs_fsync(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file || !(file->flags & CELL_FS_O_ACCMODE)) { @@ -2692,7 +2692,7 @@ error_code sys_fs_fget_block_size(ppu_thread& ppu, u32 fd, vm::ptr sector_s sys_fs.warning("sys_fs_fget_block_size(fd=%d, sector_size=*0x%x, block_size=*0x%x, arg4=*0x%x, out_flags=*0x%x)", fd, sector_size, block_size, arg4, out_flags); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -2819,7 +2819,7 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size) sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file || !(file->flags & CELL_FS_O_ACCMODE)) { @@ -3089,7 +3089,7 @@ error_code sys_fs_lsn_get_cda_size(ppu_thread&, u32 fd, vm::ptr ptr) { sys_fs.warning("sys_fs_lsn_get_cda_size(fd=%d, ptr=*0x%x)", fd, ptr); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -3112,7 +3112,7 @@ error_code sys_fs_lsn_lock(ppu_thread&, u32 fd) { sys_fs.trace("sys_fs_lsn_lock(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -3134,7 +3134,7 @@ error_code sys_fs_lsn_unlock(ppu_thread&, u32 fd) { sys_fs.trace("sys_fs_lsn_unlock(fd=%d)", fd); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index d6acb6361b..825140d7ab 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -360,7 +360,7 @@ struct lv2_file final : lv2_fs_object struct file_view; // Make file view from lv2_file object (for MSELF support) - static fs::file make_view(const std::shared_ptr& _file, u64 offset); + static fs::file make_view(const shared_ptr& _file, u64 offset); }; struct lv2_dir final : lv2_fs_object diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index 800f2f85b9..3109f042f9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -12,13 +12,13 @@ LOG_CHANNEL(sys_interrupt); lv2_int_tag::lv2_int_tag() noexcept - : lv2_obj{1} + : lv2_obj(1) , id(idm::last_id()) { } lv2_int_tag::lv2_int_tag(utils::serial& ar) noexcept - : lv2_obj{1} + : lv2_obj(1) , id(idm::last_id()) , handler([&]() { @@ -44,8 +44,8 @@ void lv2_int_tag::save(utils::serial& ar) ar(lv2_obj::check(handler) ? handler->id : 0); } -lv2_int_serv::lv2_int_serv(const std::shared_ptr>& thread, u64 arg1, u64 arg2) noexcept - : lv2_obj{1} +lv2_int_serv::lv2_int_serv(shared_ptr> thread, u64 arg1, u64 arg2) noexcept + : lv2_obj(1) , id(idm::last_id()) , thread(thread) , arg1(arg1) @@ -54,7 +54,7 @@ lv2_int_serv::lv2_int_serv(const std::shared_ptr>& thre } lv2_int_serv::lv2_int_serv(utils::serial& ar) noexcept - : lv2_obj{1} + : lv2_obj(1) , id(idm::last_id()) , thread(idm::get_unlocked>(ar)) , arg1(ar) @@ -96,7 +96,7 @@ void lv2_int_serv::join() const thread->cmd_notify.notify_one(); (*thread)(); - idm::remove_verify>(thread->id, static_cast>>(thread)); + idm::remove_verify>(thread->id, thread); } error_code sys_interrupt_tag_destroy(ppu_thread& ppu, u32 intrtag) @@ -139,7 +139,7 @@ error_code _sys_interrupt_thread_establish(ppu_thread& ppu, vm::ptr ih, u32 const u32 id = idm::import([&]() { - std::shared_ptr result; + shared_ptr result; // Get interrupt tag const auto tag = idm::check_unlocked(intrtag); @@ -173,7 +173,7 @@ error_code _sys_interrupt_thread_establish(ppu_thread& ppu, vm::ptr ih, u32 return result; } - result = std::make_shared(it, arg1, arg2); + result = make_shared(it, arg1, arg2); tag->handler = result; it->cmd_list @@ -251,7 +251,7 @@ void ppu_interrupt_thread_entry(ppu_thread& ppu, ppu_opcode_t, be_t*, struc { while (true) { - std::shared_ptr serv = nullptr; + shared_ptr serv = null_ptr; // Loop endlessly trying to invoke an interrupt if required idm::select>([&](u32, spu_thread& spu) diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.h b/rpcs3/Emu/Cell/lv2/sys_interrupt.h index 9fe4dc9d39..f32517e9a4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.h +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.h @@ -11,7 +11,7 @@ struct lv2_int_tag final : public lv2_obj static const u32 id_base = 0x0a000000; const u32 id; - std::shared_ptr handler; + shared_ptr handler; lv2_int_tag() noexcept; lv2_int_tag(utils::serial& ar) noexcept; @@ -23,11 +23,11 @@ struct lv2_int_serv final : public lv2_obj static const u32 id_base = 0x0b000000; const u32 id; - const std::shared_ptr> thread; + const shared_ptr> thread; const u64 arg1; const u64 arg2; - lv2_int_serv(const std::shared_ptr>& thread, u64 arg1, u64 arg2) noexcept; + lv2_int_serv(shared_ptr> thread, u64 arg1, u64 arg2) noexcept; lv2_int_serv(utils::serial& ar) noexcept; void save(utils::serial& ar); diff --git a/rpcs3/Emu/Cell/lv2/sys_io.cpp b/rpcs3/Emu/Cell/lv2/sys_io.cpp index 5a11bb261f..b1cec87a47 100644 --- a/rpcs3/Emu/Cell/lv2/sys_io.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_io.cpp @@ -43,7 +43,7 @@ error_code sys_io_buffer_allocate(u32 handle, vm::ptr block) return CELL_EFAULT; } - if (auto io = idm::get(handle)) + if (auto io = idm::get_unlocked(handle)) { // no idea what we actually need to allocate if (u32 addr = vm::alloc(io->block_count * io->block_size, vm::main)) @@ -62,7 +62,7 @@ error_code sys_io_buffer_free(u32 handle, u32 block) { sys_io.todo("sys_io_buffer_free(handle=0x%x, block=0x%x)", handle, block); - const auto io = idm::get(handle); + const auto io = idm::get_unlocked(handle); if (!io) { diff --git a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp index 6ffd9b29e6..75835ffa24 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp @@ -64,7 +64,7 @@ error_code _sys_lwcond_destroy(ppu_thread& ppu, u32 lwcond_id) sys_lwcond.trace("_sys_lwcond_destroy(lwcond_id=0x%x)", lwcond_id); - std::shared_ptr _cond; + shared_ptr _cond; while (true) { @@ -440,7 +440,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id ppu.gpr[3] = CELL_OK; - std::shared_ptr mutex; + shared_ptr mutex; auto& sstate = *ppu.optional_savestate_state; diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 7df939b738..a56bffedca 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -56,7 +56,7 @@ error_code _sys_lwmutex_destroy(ppu_thread& ppu, u32 lwmutex_id) sys_lwmutex.trace("_sys_lwmutex_destroy(lwmutex_id=0x%x)", lwmutex_id); - std::shared_ptr _mutex; + shared_ptr _mutex; while (true) { diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index 41b24d79f8..de5590426e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -28,10 +28,13 @@ lv2_memory_container::lv2_memory_container(utils::serial& ar, bool from_idm) noe { } -std::shared_ptr lv2_memory_container::load(utils::serial& ar) +std::function lv2_memory_container::load(utils::serial& ar) { // Use idm::last_id() only for the instances at IDM - return std::make_shared(stx::exact_t(ar), true); + return [ptr = make_shared(stx::exact_t(ar), true)](void* storage) + { + *static_cast*>(storage) = ptr; + }; } void lv2_memory_container::save(utils::serial& ar) @@ -43,7 +46,7 @@ lv2_memory_container* lv2_memory_container::search(u32 id) { if (id != SYS_MEMORY_CONTAINER_ID_INVALID) { - return idm::check(id); + return idm::check_unlocked(id); } return &g_fxo->get(); @@ -397,7 +400,7 @@ error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr(cid); + const auto ct = idm::get_unlocked(cid); if (!ct) { diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index 5184aeed43..c2ca046bcc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -74,7 +74,7 @@ struct lv2_memory_container lv2_memory_container(u32 size, bool from_idm = false) noexcept; lv2_memory_container(utils::serial& ar, bool from_idm = false) noexcept; - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); static lv2_memory_container* search(u32 id); diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 6a7058267b..d134102a73 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -82,13 +82,13 @@ CellError lv2_memory::on_id_create() return {}; } -std::shared_ptr lv2_memory::load(utils::serial& ar) +std::function lv2_memory::load(utils::serial& ar) { - auto mem = std::make_shared(ar); + auto mem = make_shared(ar); mem->exists++; // Disable on_id_create() - std::shared_ptr ptr = lv2_obj::load(mem->key, mem, +mem->pshared); + auto func = load_func(mem, +mem->pshared); mem->exists--; - return ptr; + return func; } void lv2_memory::save(utils::serial& ar) @@ -128,7 +128,7 @@ error_code create_lv2_shm(bool pshared, u64 ipc_key, u64 size, u32 align, u64 fl if (auto error = lv2_obj::create(_pshared, ipc_key, exclusive ? SYS_SYNC_NEWLY_CREATED : SYS_SYNC_NOT_CARE, [&]() { - return std::make_shared( + return make_shared( static_cast(size), align, flags, @@ -294,7 +294,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6 } } - const auto ct = idm::get(cid); + const auto ct = idm::get_unlocked(cid); if (!ct) { @@ -491,7 +491,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread& ppu } } - const auto ct = idm::get(cid); + const auto ct = idm::get_unlocked(cid); if (!ct) { @@ -797,7 +797,7 @@ error_code sys_mmapper_enable_page_fault_notification(ppu_thread& ppu, u32 start // TODO: Check memory region's flags to make sure the memory can be used for page faults. - auto queue = idm::get(event_queue_id); + auto queue = idm::get_unlocked(event_queue_id); if (!queue) { // Can't connect the queue if it doesn't exist. diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h index 3a1211ea58..544ff91ee8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -31,7 +31,7 @@ struct lv2_memory : lv2_obj lv2_memory(u32 size, u32 align, u64 flags, u64 key, bool pshared, lv2_memory_container* ct); lv2_memory(utils::serial& ar); - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); CellError on_id_create(); diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index efd0f1c374..c8ac190c25 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -25,10 +25,9 @@ lv2_mutex::lv2_mutex(utils::serial& ar) control.raw().owner >>= 1; } -std::shared_ptr lv2_mutex::load(utils::serial& ar) +std::function lv2_mutex::load(utils::serial& ar) { - auto mtx = std::make_shared(ar); - return lv2_obj::load(mtx->key, mtx); + return load_func(make_shared(ar)); } void lv2_mutex::save(utils::serial& ar) @@ -88,7 +87,7 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr mutex_id, vm::ptr(_attr.pshared, _attr.ipc_key, _attr.flags, [&]() { - return std::make_shared( + return make_shared( _attr.protocol, _attr.recursive, _attr.adaptive, diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h index 75f43514e6..f82f913399 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -58,7 +58,7 @@ struct lv2_mutex final : lv2_obj } lv2_mutex(utils::serial& ar); - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); template diff --git a/rpcs3/Emu/Cell/lv2/sys_net.cpp b/rpcs3/Emu/Cell/lv2/sys_net.cpp index efac7556d1..97d40d6d47 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -266,25 +266,25 @@ lv2_socket::lv2_socket(utils::serial& ar, lv2_socket_type _type) ar(last_bound_addr); } -std::shared_ptr lv2_socket::load(utils::serial& ar) +std::function lv2_socket::load(utils::serial& ar) { const lv2_socket_type type{ar}; - std::shared_ptr sock_lv2; + shared_ptr sock_lv2; switch (type) { case SYS_NET_SOCK_STREAM: case SYS_NET_SOCK_DGRAM: { - auto lv2_native = std::make_shared(ar, type); + auto lv2_native = make_shared(ar, type); ensure(lv2_native->create_socket() >= 0); sock_lv2 = std::move(lv2_native); break; } - case SYS_NET_SOCK_RAW: sock_lv2 = std::make_shared(ar, type); break; - case SYS_NET_SOCK_DGRAM_P2P: sock_lv2 = std::make_shared(ar, type); break; - case SYS_NET_SOCK_STREAM_P2P: sock_lv2 = std::make_shared(ar, type); break; + case SYS_NET_SOCK_RAW: sock_lv2 = make_shared(ar, type); break; + case SYS_NET_SOCK_DGRAM_P2P: sock_lv2 = make_shared(ar, type); break; + case SYS_NET_SOCK_STREAM_P2P: sock_lv2 = make_shared(ar, type); break; } if (std::memcmp(&sock_lv2->last_bound_addr, std::array{}.data(), 16)) @@ -293,7 +293,7 @@ std::shared_ptr lv2_socket::load(utils::serial& ar) sock_lv2->bind(sock_lv2->last_bound_addr); } - return sock_lv2; + return [ptr = sock_lv2](void* storage) { *static_cast*>(storage) = ptr; };; } void lv2_socket::save(utils::serial& ar, bool save_only_this_class) @@ -352,7 +352,7 @@ error_code sys_net_bnet_accept(ppu_thread& ppu, s32 s, vm::ptr s32 result = 0; sys_net_sockaddr sn_addr{}; - std::shared_ptr new_socket{}; + shared_ptr new_socket{}; const auto sock = idm::check(s, [&, notify = lv2_obj::notify_all_t()](lv2_socket& sock) { @@ -465,7 +465,7 @@ error_code sys_net_bnet_bind(ppu_thread& ppu, s32 s, vm::cptr return -SYS_NET_EINVAL; } - if (!idm::check(s)) + if (!idm::check_unlocked(s)) { return -SYS_NET_EBADF; } @@ -514,7 +514,7 @@ error_code sys_net_bnet_connect(ppu_thread& ppu, s32 s, vm::ptr(s)) + if (!idm::check_unlocked(s)) { return -SYS_NET_EBADF; } @@ -1194,14 +1194,14 @@ error_code sys_net_bnet_socket(ppu_thread& ppu, lv2_socket_family family, lv2_so return -SYS_NET_EPROTONOSUPPORT; } - std::shared_ptr sock_lv2; + shared_ptr sock_lv2; switch (type) { case SYS_NET_SOCK_STREAM: case SYS_NET_SOCK_DGRAM: { - auto lv2_native = std::make_shared(family, type, protocol); + auto lv2_native = make_shared(family, type, protocol); if (s32 result = lv2_native->create_socket(); result < 0) { return sys_net_error{result}; @@ -1210,9 +1210,9 @@ error_code sys_net_bnet_socket(ppu_thread& ppu, lv2_socket_family family, lv2_so sock_lv2 = std::move(lv2_native); break; } - case SYS_NET_SOCK_RAW: sock_lv2 = std::make_shared(family, type, protocol); break; - case SYS_NET_SOCK_DGRAM_P2P: sock_lv2 = std::make_shared(family, type, protocol); break; - case SYS_NET_SOCK_STREAM_P2P: sock_lv2 = std::make_shared(family, type, protocol); break; + case SYS_NET_SOCK_RAW: sock_lv2 = make_shared(family, type, protocol); break; + case SYS_NET_SOCK_DGRAM_P2P: sock_lv2 = make_shared(family, type, protocol); break; + case SYS_NET_SOCK_STREAM_P2P: sock_lv2 = make_shared(family, type, protocol); break; } const s32 s = idm::import_existing(sock_lv2); @@ -1775,7 +1775,7 @@ error_code sys_net_abort(ppu_thread& ppu, s32 type, u64 arg, s32 flags) { std::lock_guard nw_lock(g_fxo->get().mutex_thread_loop); - const auto sock = idm::get(static_cast(arg)); + const auto sock = idm::get_unlocked(static_cast(arg)); if (!sock) { diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp index 02f5b2c697..d95c6935fc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.cpp @@ -64,7 +64,7 @@ void lv2_socket::set_poll_event(bs_t event) events += event; } -void lv2_socket::poll_queue(std::shared_ptr ppu, bs_t event, std::function)> poll_cb) +void lv2_socket::poll_queue(shared_ptr ppu, bs_t event, std::function)> poll_cb) { set_poll_event(event); queue.emplace_back(std::move(ppu), poll_cb); @@ -175,3 +175,17 @@ void lv2_socket::queue_wake(ppu_thread* ppu) break; } } + +lv2_socket& lv2_socket::operator=(thread_state s) noexcept +{ + if (s == thread_state::finished) + { + close(); + } + + return *this; +} + +lv2_socket::~lv2_socket() noexcept +{ +} diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h index 8cc84b729a..f0e3b61d00 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket.h @@ -27,6 +27,8 @@ using socket_type = uptr; using socket_type = int; #endif +enum class thread_state : u32; + class lv2_socket { public: @@ -60,16 +62,17 @@ public: lv2_socket(lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol); lv2_socket(utils::serial&) {} lv2_socket(utils::serial&, lv2_socket_type type); - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial&, bool save_only_this_class = false); - virtual ~lv2_socket() = default; + virtual ~lv2_socket() noexcept; + lv2_socket& operator=(thread_state s) noexcept; std::unique_lock lock(); void set_lv2_id(u32 id); bs_t get_events() const; void set_poll_event(bs_t event); - void poll_queue(std::shared_ptr ppu, bs_t event, std::function)> poll_cb); + void poll_queue(shared_ptr ppu, bs_t event, std::function)> poll_cb); u32 clear_queue(ppu_thread*); void handle_events(const pollfd& native_fd, bool unset_connecting = false); void queue_wake(ppu_thread* ppu); @@ -85,7 +88,7 @@ public: #endif public: - virtual std::tuple, sys_net_sockaddr> accept(bool is_lock = true) = 0; + virtual std::tuple, sys_net_sockaddr> accept(bool is_lock = true) = 0; virtual s32 bind(const sys_net_sockaddr& addr) = 0; virtual std::optional connect(const sys_net_sockaddr& addr) = 0; @@ -133,7 +136,7 @@ protected: atomic_bs_t events{}; // Event processing workload (pair of thread id and the processing function) - std::vector, std::function)>>> queue; + std::vector, std::function)>>> queue; // Socket options value keepers // Non-blocking IO option diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp index a6abc1d055..d0a735b178 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.cpp @@ -57,17 +57,9 @@ void lv2_socket_native::save(utils::serial& ar) ar(is_socket_connected()); } -lv2_socket_native::~lv2_socket_native() +lv2_socket_native::~lv2_socket_native() noexcept { - std::lock_guard lock(mutex); - if (socket) - { -#ifdef _WIN32 - ::closesocket(socket); -#else - ::close(socket); -#endif - } + lv2_socket_native::close(); } s32 lv2_socket_native::create_socket() @@ -106,7 +98,7 @@ void lv2_socket_native::set_socket(socket_type socket, lv2_socket_family family, set_non_blocking(); } -std::tuple, sys_net_sockaddr> lv2_socket_native::accept(bool is_lock) +std::tuple, sys_net_sockaddr> lv2_socket_native::accept(bool is_lock) { std::unique_lock lock(mutex, std::defer_lock); @@ -127,7 +119,7 @@ std::tuple, sys_net_sockaddr> lv2_socket_ if (native_socket != invalid_socket) { - auto newsock = std::make_shared(family, type, protocol); + auto newsock = make_single(family, type, protocol); newsock->set_socket(native_socket, family, type, protocol); // Sockets inherit non blocking behaviour from their parent @@ -274,7 +266,7 @@ std::optional lv2_socket_native::connect(const sys_net_sockaddr& addr) #ifdef _WIN32 connecting = true; #endif - this->poll_queue(nullptr, lv2_socket::poll_t::write, [this](bs_t events) -> bool + this->poll_queue(null_ptr, lv2_socket::poll_t::write, [this](bs_t events) -> bool { if (events & lv2_socket::poll_t::write) { @@ -1114,10 +1106,12 @@ void lv2_socket_native::close() socket = {}; } - auto& dnshook = g_fxo->get(); - dnshook.remove_dns_spy(lv2_id); + if (auto dnshook = g_fxo->try_get()) + { + dnshook->remove_dns_spy(lv2_id); + } - if (bound_port) + if (bound_port && g_fxo->is_init>()) { auto& nph = g_fxo->get>(); nph.upnp_remove_port_mapping(bound_port, type == SYS_NET_SOCK_STREAM ? "TCP" : "UDP"); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h index 0ecfdf7278..808529356a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_native.h @@ -30,13 +30,15 @@ class lv2_socket_native final : public lv2_socket { public: + static constexpr u32 id_type = 1; + lv2_socket_native(lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol); lv2_socket_native(utils::serial& ar, lv2_socket_type type); + ~lv2_socket_native() noexcept override; void save(utils::serial& ar); - ~lv2_socket_native(); s32 create_socket(); - std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; + std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; s32 bind(const sys_net_sockaddr& addr) override; std::optional connect(const sys_net_sockaddr& addr) override; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp index ecda6ded37..8614d37205 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.cpp @@ -72,7 +72,7 @@ void lv2_socket_p2p::handle_new_data(sys_net_sockaddr_in_p2p p2p_addr, std::vect } } -std::tuple, sys_net_sockaddr> lv2_socket_p2p::accept([[maybe_unused]] bool is_lock) +std::tuple, sys_net_sockaddr> lv2_socket_p2p::accept([[maybe_unused]] bool is_lock) { sys_net.fatal("[P2P] accept() called on a P2P socket"); return {}; @@ -330,9 +330,14 @@ void lv2_socket_p2p::close() return; } - auto& nc = g_fxo->get(); + if (g_fxo->is_init()) { + auto& nc = g_fxo->get(); std::lock_guard lock(nc.list_p2p_ports_mutex); + + if (!nc.list_p2p_ports.contains(port)) + return; + auto& p2p_port = ::at32(nc.list_p2p_ports, port); { std::lock_guard lock(p2p_port.bound_p2p_vports_mutex); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.h index 110c3404e0..b8fadb3d53 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2p.h @@ -9,7 +9,7 @@ public: lv2_socket_p2p(utils::serial& ar, lv2_socket_type type); void save(utils::serial& ar); - std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; + std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; s32 bind(const sys_net_sockaddr& addr) override; std::optional connect(const sys_net_sockaddr& addr) override; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp index e692dea8dd..d6c98b670a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp @@ -467,7 +467,7 @@ bool lv2_socket_p2ps::handle_listening(p2ps_encapsulated_tcp* tcp_header, [[mayb const u16 new_op_vport = tcp_header->src_port; const u64 new_cur_seq = send_hdr.seq + 1; const u64 new_data_beg_seq = send_hdr.ack; - auto sock_lv2 = std::make_shared(socket, port, vport, new_op_addr, new_op_port, new_op_vport, new_cur_seq, new_data_beg_seq, so_nbio); + auto sock_lv2 = make_shared(socket, port, vport, new_op_addr, new_op_port, new_op_vport, new_cur_seq, new_data_beg_seq, so_nbio); const s32 new_sock_id = idm::import_existing(sock_lv2); sock_lv2->set_lv2_id(new_sock_id); const u64 key_connected = (reinterpret_cast(op_addr)->sin_addr.s_addr) | (static_cast(tcp_header->src_port) << 48) | (static_cast(tcp_header->dst_port) << 32); @@ -600,7 +600,7 @@ std::pair lv2_socket_p2ps::getpeername() return {CELL_OK, res}; } -std::tuple, sys_net_sockaddr> lv2_socket_p2ps::accept(bool is_lock) +std::tuple, sys_net_sockaddr> lv2_socket_p2ps::accept(bool is_lock) { std::unique_lock lock(mutex, std::defer_lock); @@ -944,8 +944,9 @@ void lv2_socket_p2ps::close() return; } - auto& nc = g_fxo->get(); + if (g_fxo->is_init()) { + auto& nc = g_fxo->get(); std::lock_guard lock(nc.list_p2p_ports_mutex); auto& p2p_port = ::at32(nc.list_p2p_ports, port); { @@ -973,8 +974,10 @@ void lv2_socket_p2ps::close() } } - auto& tcpm = g_fxo->get>(); - tcpm.clear_all_messages(lv2_id); + if (const auto tcpm = g_fxo->try_get>()) + { + tcpm->clear_all_messages(lv2_id); + } } s32 lv2_socket_p2ps::shutdown([[maybe_unused]] s32 how) diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h index 6d1333eb58..8158138936 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h @@ -58,6 +58,8 @@ std::vector generate_u2s_packet(const p2ps_encapsulated_tcp& header, const u class lv2_socket_p2ps final : public lv2_socket_p2p { public: + static constexpr u32 id_type = 2; + lv2_socket_p2ps(lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol); lv2_socket_p2ps(socket_type socket, u16 port, u16 vport, u32 op_addr, u16 op_port, u16 op_vport, u64 cur_seq, u64 data_beg_seq, s32 so_nbio); lv2_socket_p2ps(utils::serial& ar, lv2_socket_type type); @@ -70,7 +72,7 @@ public: void send_u2s_packet(std::vector data, const ::sockaddr_in* dst, u64 seq, bool require_ack); void close_stream(); - std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; + std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; s32 bind(const sys_net_sockaddr& addr) override; std::optional connect(const sys_net_sockaddr& addr) override; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.cpp index 2d9bfcff85..6e74bd512f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.cpp @@ -36,7 +36,7 @@ void lv2_socket_raw::save(utils::serial& ar) lv2_socket::save(ar, true); } -std::tuple, sys_net_sockaddr> lv2_socket_raw::accept([[maybe_unused]] bool is_lock) +std::tuple, sys_net_sockaddr> lv2_socket_raw::accept([[maybe_unused]] bool is_lock) { sys_net.fatal("[RAW] accept() called on a RAW socket"); return {}; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.h index 2071fe3155..01b7255884 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_raw.h @@ -5,11 +5,13 @@ class lv2_socket_raw final : public lv2_socket { public: + static constexpr u32 id_type = 1; + lv2_socket_raw(lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol); lv2_socket_raw(utils::serial& ar, lv2_socket_type type); void save(utils::serial& ar); - std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; + std::tuple, sys_net_sockaddr> accept(bool is_lock = true) override; s32 bind(const sys_net_sockaddr& addr) override; std::optional connect(const sys_net_sockaddr& addr) override; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp index aaf79d4f41..84e90e53fe 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp @@ -138,7 +138,7 @@ void p2p_thread::bind_sce_np_port() void network_thread::operator()() { - std::vector> socklist; + std::vector> socklist; socklist.reserve(lv2_socket::id_count); { diff --git a/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp b/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp index 78970bee2c..574d670978 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/nt_p2p_port.cpp @@ -135,11 +135,11 @@ bool nt_p2p_port::handle_connected(s32 sock_id, p2ps_encapsulated_tcp* tcp_heade bool nt_p2p_port::handle_listening(s32 sock_id, p2ps_encapsulated_tcp* tcp_header, u8* data, ::sockaddr_storage* op_addr) { - auto sock = idm::get(sock_id); + auto sock = idm::get_unlocked(sock_id); if (!sock) return false; - auto& sock_p2ps = reinterpret_cast(*sock.get()); + auto& sock_p2ps = reinterpret_cast(*sock); return sock_p2ps.handle_listening(tcp_header, data, op_addr); } diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp index 7a9cb08bf4..99b5981795 100644 --- a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp @@ -13,10 +13,10 @@ #include "sys_overlay.h" #include "sys_fs.h" -extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar = nullptr); +extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar = nullptr); -extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); -extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false); +extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); +extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false); LOG_CHANNEL(sys_overlay); @@ -68,7 +68,7 @@ static error_code overlay_load_module(vm::ptr ovlmid, const std::string& vp ppu_initialize(*ovlm); - sys_overlay.success(u8"Loaded overlay: “%s” (id=0x%x)", vpath, idm::last_id()); + sys_overlay.success("Loaded overlay: \"%s\" (id=0x%x)", vpath, idm::last_id()); *ovlmid = idm::last_id(); *entry = ovlm->entry; @@ -78,7 +78,7 @@ static error_code overlay_load_module(vm::ptr ovlmid, const std::string& vp fs::file make_file_view(fs::file&& file, u64 offset, u64 size); -std::shared_ptr lv2_overlay::load(utils::serial& ar) +std::function lv2_overlay::load(utils::serial& ar) { const std::string vpath = ar.pop(); const std::string path = vfs::get(vpath); @@ -86,7 +86,7 @@ std::shared_ptr lv2_overlay::load(utils::serial& ar) sys_overlay.success("lv2_overlay::load(): vpath='%s', path='%s', offset=0x%x", vpath, path, offset); - std::shared_ptr ovlm; + shared_ptr ovlm; fs::file file{path.substr(0, path.size() - (offset ? fmt::format("_x%x", offset).size() : 0))}; @@ -110,7 +110,10 @@ std::shared_ptr lv2_overlay::load(utils::serial& ar) sys_overlay.error("lv2_overlay::load(): Failed to find file. (vpath='%s', offset=0x%x)", vpath, offset); } - return ovlm; + return [ovlm](void* storage) + { + *static_cast*>(storage) = ovlm; + }; } void lv2_overlay::save(utils::serial& ar) @@ -156,7 +159,7 @@ error_code sys_overlay_load_module_by_fd(vm::ptr ovlmid, u32 fd, u64 offset return CELL_EINVAL; } - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.h b/rpcs3/Emu/Cell/lv2/sys_overlay.h index 1636ac38e0..ef1c1ffbd7 100644 --- a/rpcs3/Emu/Cell/lv2/sys_overlay.h +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.h @@ -5,7 +5,7 @@ #include "sys_sync.h" #include -struct lv2_overlay final : lv2_obj, ppu_module +struct lv2_overlay final : ppu_module { static const u32 id_base = 0x25000000; @@ -15,7 +15,7 @@ struct lv2_overlay final : lv2_obj, ppu_module lv2_overlay() = default; lv2_overlay(utils::serial&){} - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); }; diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 064cceb728..94153404fe 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -22,9 +22,9 @@ LOG_CHANNEL(sys_ppu_thread); // Simple structure to cleanup previous thread, because can't remove its own thread struct ppu_thread_cleaner { - std::shared_ptr old; + shared_ptr> old; - std::shared_ptr clean(std::shared_ptr ptr) + shared_ptr> clean(shared_ptr> ptr) { return std::exchange(old, std::move(ptr)); } @@ -86,7 +86,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode) ppu_join_status old_status; // Avoid cases where cleaning causes the destructor to be called inside IDM lock scope (for performance) - std::shared_ptr old_ppu; + shared_ptr> old_ppu; { lv2_obj::notify_all_t notify; lv2_obj::prepare_for_sleep(ppu); @@ -115,7 +115,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode) if (old_status != ppu_join_status::joinable) { // Remove self ID from IDM, move owning ptr - old_ppu = g_fxo->get().clean(std::move(idm::find_unlocked>(ppu.id)->second)); + old_ppu = g_fxo->get().clean(idm::withdraw>(ppu.id, 0, std::false_type{})); } // Get writers mask (wait for all current writers to quit) @@ -147,7 +147,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode) if (old_ppu) { // It is detached from IDM now so join must be done explicitly now - *static_cast*>(old_ppu.get()) = thread_state::finished; + *old_ppu = thread_state::finished; } // Need to wait until the current writers finish @@ -435,7 +435,7 @@ error_code sys_ppu_thread_stop(ppu_thread& ppu, u32 thread_id) return CELL_ENOSYS; } - const auto thread = idm::check>(thread_id); + const auto thread = idm::check>(thread_id, [](named_thread&) {}); if (!thread) { @@ -529,7 +529,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, vm::p p.arg0 = arg; p.arg1 = unk; - return std::make_shared>(p, ppu_name, prio, 1 - static_cast(flags & 3)); + return stx::make_shared>(p, ppu_name, prio, 1 - static_cast(flags & 3)); }); if (!tid) @@ -539,7 +539,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, vm::p return CELL_EAGAIN; } - sys_ppu_thread.warning(u8"_sys_ppu_thread_create(): Thread “%s” created (id=0x%x, func=*0x%x, rtoc=0x%x, user-tls=0x%x)", ppu_name, tid, entry.addr, entry.rtoc, tls); + sys_ppu_thread.warning("_sys_ppu_thread_create(): Thread \"%s\" created (id=0x%x, func=*0x%x, rtoc=0x%x, user-tls=0x%x)", ppu_name, tid, entry.addr, entry.rtoc, tls); ppu.check_state(); *thread_id = tid; @@ -594,7 +594,7 @@ error_code sys_ppu_thread_rename(ppu_thread& ppu, u32 thread_id, vm::cptr sys_ppu_thread.warning("sys_ppu_thread_rename(thread_id=0x%x, name=*0x%x)", thread_id, name); - const auto thread = idm::get>(thread_id); + const auto thread = idm::get_unlocked>(thread_id); if (!thread) { @@ -618,7 +618,7 @@ error_code sys_ppu_thread_rename(ppu_thread& ppu, u32 thread_id, vm::cptr auto _name = make_single(std::move(out_str)); // thread_ctrl name is not changed (TODO) - sys_ppu_thread.warning(u8"sys_ppu_thread_rename(): Thread renamed to “%s”", *_name); + sys_ppu_thread.warning("sys_ppu_thread_rename(): Thread renamed to \"%s\"", *_name); thread->ppu_tname.store(std::move(_name)); thread_ctrl::set_name(*thread, thread->thread_name); // TODO: Currently sets debugger thread name only for local thread @@ -631,7 +631,7 @@ error_code sys_ppu_thread_recover_page_fault(ppu_thread& ppu, u32 thread_id) sys_ppu_thread.warning("sys_ppu_thread_recover_page_fault(thread_id=0x%x)", thread_id); - const auto thread = idm::get>(thread_id); + const auto thread = idm::get_unlocked>(thread_id); if (!thread) { @@ -647,7 +647,7 @@ error_code sys_ppu_thread_get_page_fault_context(ppu_thread& ppu, u32 thread_id, sys_ppu_thread.todo("sys_ppu_thread_get_page_fault_context(thread_id=0x%x, ctxt=*0x%x)", thread_id, ctxt); - const auto thread = idm::get>(thread_id); + const auto thread = idm::get_unlocked>(thread_id); if (!thread) { diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 57b0241b70..8038ffc248 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -231,7 +231,7 @@ CellError process_is_spu_lock_line_reservation_address(u32 addr, u64 flags) return CELL_EPERM; default: { - if (auto vm0 = idm::get(sys_vm_t::find_id(addr))) + if (auto vm0 = idm::get_unlocked(sys_vm_t::find_id(addr))) { // sys_vm area was not covering the address specified but made a reservation on the entire 256mb region if (vm0->addr + vm0->size - 1 < addr) @@ -433,16 +433,29 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector& argv, std::vector< using namespace id_manager; - auto func = [is_real_reboot, old_size = g_fxo->get().size, vec = (reader_lock{g_mutex}, g_fxo->get>().vec)](u32 sdk_suggested_mem) mutable + shared_ptr idm_capture = make_shared(); + + if (!is_real_reboot) + { + reader_lock rlock{id_manager::g_mutex}; + g_fxo->get>().save(*idm_capture); + stx::serial_breathe_and_tag(*idm_capture, "id_map", false); + } + + idm_capture->set_reading_state(); + + auto func = [is_real_reboot, old_size = g_fxo->get().size, idm_capture](u32 sdk_suggested_mem) mutable { if (is_real_reboot) { // Do not save containers on actual reboot - vec.clear(); + ensure(g_fxo->init>()); + } + else + { + // Save LV2 memory containers + ensure(g_fxo->init>(*idm_capture)); } - - // Save LV2 memory containers - ensure(g_fxo->init>())->vec = std::move(vec); // Empty the containers, accumulate their total size u32 total_size = 0; diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 49b5839cfa..42903d7454 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -17,12 +17,12 @@ #include "sys_memory.h" #include -extern void dump_executable(std::span data, const ppu_module* _module, std::string_view title_id); +extern void dump_executable(std::span data, const ppu_module* _module, std::string_view title_id); -extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64, utils::serial* = nullptr); +extern shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64, utils::serial* = nullptr); extern void ppu_unload_prx(const lv2_prx& prx); -extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); -extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false); +extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); +extern void ppu_finalize(const ppu_module& info, bool force_mem_release = false); extern void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 exports_start, u32 exports_size, std::basic_string& loaded_flags); LOG_CHANNEL(sys_prx); @@ -35,7 +35,7 @@ extern const std::map g_prx_list { "libaacenc_spurs.sprx", 0 }, { "libac3dec.sprx", 0 }, { "libac3dec2.sprx", 0 }, - { "libadec.sprx", 0 }, + { "libadec.sprx", 1 }, { "libadec2.sprx", 0 }, { "libadec_internal.sprx", 0 }, { "libad_async.sprx", 0 }, @@ -235,7 +235,7 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptrname = std::move(name); prx->path = std::move(path); - sys_prx.warning(u8"Ignored module: “%s” (id=0x%x)", vpath, idm::last_id()); + sys_prx.warning("Ignored module: \"%s\" (id=0x%x)", vpath, idm::last_id()); return not_an_error(idm::last_id()); }; @@ -253,7 +253,7 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr lv2_prx::load(utils::serial& ar) +std::function lv2_prx::load(utils::serial& ar) { [[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(lv2_prx_overlay); @@ -316,11 +316,11 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) usz seg_count = 0; ar.deserialize_vle(seg_count); - std::shared_ptr prx; + shared_ptr prx; auto hle_load = [&]() { - prx = std::make_shared(); + prx = make_shared(); prx->path = path; prx->name = path.substr(path.find_last_of(fs::delim) + 1); }; @@ -337,7 +337,7 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) { u128 klic = g_fxo->get().last_key(); file = make_file_view(std::move(file), offset, umax); - prx = ppu_load_prx(ppu_prx_object{ decrypt_self(std::move(file), reinterpret_cast(&klic)) }, false, path, 0, &ar); + prx = ppu_load_prx(ppu_prx_object{decrypt_self(std::move(file), reinterpret_cast(&klic))}, false, path, 0, &ar); prx->m_loaded_flags = std::move(loaded_flags); prx->m_external_loaded_flags = std::move(external_flags); @@ -369,7 +369,11 @@ std::shared_ptr lv2_prx::load(utils::serial& ar) } prx->state = state; - return prx; + + return [prx](void* storage) + { + *static_cast*>(storage) = prx; + }; } void lv2_prx::save(utils::serial& ar) @@ -407,7 +411,7 @@ error_code _sys_prx_load_module_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u64 f sys_prx.warning("_sys_prx_load_module_by_fd(fd=%d, offset=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, flags, pOpt); - const auto file = idm::get(fd); + const auto file = idm::get_unlocked(fd); if (!file) { @@ -519,7 +523,7 @@ error_code _sys_prx_start_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr(id); + const auto prx = idm::get_unlocked(id); if (!prx) { @@ -600,7 +604,7 @@ error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr(id); + const auto prx = idm::get_unlocked(id); if (!prx) { @@ -1013,7 +1017,7 @@ error_code _sys_prx_get_module_info(ppu_thread& ppu, u32 id, u64 flags, vm::ptr< sys_prx.warning("_sys_prx_get_module_info(id=0x%x, flags=%d, pOpt=*0x%x)", id, flags, pOpt); - const auto prx = idm::get(id); + const auto prx = idm::get_unlocked(id); if (!pOpt) { diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h index 328d67cc6e..af0539ecc0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -172,7 +172,7 @@ enum : u32 PRX_STATE_DESTROYED, // Last state, the module cannot be restarted }; -struct lv2_prx final : lv2_obj, ppu_module +struct lv2_prx final : ppu_module { static const u32 id_base = 0x23000000; @@ -204,7 +204,7 @@ struct lv2_prx final : lv2_obj, ppu_module lv2_prx() noexcept = default; lv2_prx(utils::serial&) {} - static std::shared_ptr load(utils::serial&); + static std::function load(utils::serial&); void save(utils::serial& ar); }; diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index f2d1b33815..896dd0b00c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -425,7 +425,7 @@ error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u32 io, u32 ea return CELL_EINVAL; } - if ((addr == ea || !(addr % 0x1000'0000)) && idm::check(sys_vm_t::find_id(addr))) + if ((addr == ea || !(addr % 0x1000'0000)) && idm::check_unlocked(sys_vm_t::find_id(addr))) { // Virtual memory is disallowed return CELL_EINVAL; diff --git a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp index 197a9027bb..c391602bc3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp @@ -164,7 +164,7 @@ error_code sys_rsxaudio_initialize(vm::ptr handle) return CELL_ENOMEM; } - const auto rsxaudio_obj = idm::get(id); + const auto rsxaudio_obj = idm::get_unlocked(id); std::lock_guard lock(rsxaudio_obj->mutex); rsxaudio_obj->shmem = vm::addr_t{vm::alloc(sizeof(rsxaudio_shmem), vm::main)}; @@ -201,7 +201,7 @@ error_code sys_rsxaudio_finalize(u32 handle) { sys_rsxaudio.trace("sys_rsxaudio_finalize(handle=0x%x)", handle); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -219,7 +219,7 @@ error_code sys_rsxaudio_finalize(u32 handle) { std::lock_guard ra_obj_lock{rsxaudio_thread.rsxaudio_obj_upd_m}; - rsxaudio_thread.rsxaudio_obj_ptr = {}; + rsxaudio_thread.rsxaudio_obj_ptr = null_ptr; } rsxaudio_obj->init = false; @@ -235,7 +235,7 @@ error_code sys_rsxaudio_import_shared_memory(u32 handle, vm::ptr addr) { sys_rsxaudio.trace("sys_rsxaudio_import_shared_memory(handle=0x%x, addr=*0x%x)", handle, addr); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -264,7 +264,7 @@ error_code sys_rsxaudio_unimport_shared_memory(u32 handle, vm::ptr addr /* { sys_rsxaudio.trace("sys_rsxaudio_unimport_shared_memory(handle=0x%x, addr=*0x%x)", handle, addr); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -287,7 +287,7 @@ error_code sys_rsxaudio_create_connection(u32 handle) { sys_rsxaudio.trace("sys_rsxaudio_create_connection(handle=0x%x)", handle); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -305,15 +305,15 @@ error_code sys_rsxaudio_create_connection(u32 handle) const error_code port_create_status = [&]() -> error_code { - if (auto queue1 = idm::get(sh_page->ctrl.event_queue_1_id)) + if (auto queue1 = idm::get_unlocked(sh_page->ctrl.event_queue_1_id)) { rsxaudio_obj->event_queue[0] = queue1; - if (auto queue2 = idm::get(sh_page->ctrl.event_queue_2_id)) + if (auto queue2 = idm::get_unlocked(sh_page->ctrl.event_queue_2_id)) { rsxaudio_obj->event_queue[1] = queue2; - if (auto queue3 = idm::get(sh_page->ctrl.event_queue_3_id)) + if (auto queue3 = idm::get_unlocked(sh_page->ctrl.event_queue_3_id)) { rsxaudio_obj->event_queue[2] = queue3; @@ -350,7 +350,7 @@ error_code sys_rsxaudio_close_connection(u32 handle) { sys_rsxaudio.trace("sys_rsxaudio_close_connection(handle=0x%x)", handle); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -367,7 +367,7 @@ error_code sys_rsxaudio_close_connection(u32 handle) { auto& rsxaudio_thread = g_fxo->get(); std::lock_guard ra_obj_lock{rsxaudio_thread.rsxaudio_obj_upd_m}; - rsxaudio_thread.rsxaudio_obj_ptr = {}; + rsxaudio_thread.rsxaudio_obj_ptr = null_ptr; } for (u32 q_idx = 0; q_idx < SYS_RSXAUDIO_PORT_CNT; q_idx++) @@ -382,7 +382,7 @@ error_code sys_rsxaudio_prepare_process(u32 handle) { sys_rsxaudio.trace("sys_rsxaudio_prepare_process(handle=0x%x)", handle); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -413,7 +413,7 @@ error_code sys_rsxaudio_start_process(u32 handle) { sys_rsxaudio.trace("sys_rsxaudio_start_process(handle=0x%x)", handle); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -463,7 +463,7 @@ error_code sys_rsxaudio_stop_process(u32 handle) { sys_rsxaudio.trace("sys_rsxaudio_stop_process(handle=0x%x)", handle); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { @@ -511,7 +511,7 @@ error_code sys_rsxaudio_get_dma_param(u32 handle, u32 flag, vm::ptr out) { sys_rsxaudio.trace("sys_rsxaudio_get_dma_param(handle=0x%x, flag=0x%x, out=0x%x)", handle, flag, out); - const auto rsxaudio_obj = idm::get(handle); + const auto rsxaudio_obj = idm::get_unlocked(handle); if (!rsxaudio_obj) { diff --git a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h index 609215fbe4..e13b33816d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h +++ b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.h @@ -161,7 +161,7 @@ struct lv2_rsxaudio final : lv2_obj vm::addr_t shmem{}; - std::array, SYS_RSXAUDIO_PORT_CNT> event_queue{}; + std::array, SYS_RSXAUDIO_PORT_CNT> event_queue{}; // lv2 uses port memory addresses for their names static constexpr std::array event_port_name{ 0x8000000000400100, 0x8000000000400200, 0x8000000000400300 }; @@ -583,7 +583,7 @@ public: atomic_t rsxaudio_ctx_allocated = false; shared_mutex rsxaudio_obj_upd_m{}; - std::shared_ptr rsxaudio_obj_ptr{}; + shared_ptr rsxaudio_obj_ptr{}; void operator()(); rsxaudio_data_thread& operator=(thread_state state); diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index fe77f6b421..173fe68a79 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -19,10 +19,9 @@ lv2_rwlock::lv2_rwlock(utils::serial& ar) ar(owner); } -std::shared_ptr lv2_rwlock::load(utils::serial& ar) +std::function lv2_rwlock::load(utils::serial& ar) { - auto rwlock = std::make_shared(ar); - return lv2_obj::load(rwlock->key, rwlock); + return load_func(make_shared(stx::exact_t(ar))); } void lv2_rwlock::save(utils::serial& ar) @@ -56,7 +55,7 @@ error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr rw_lock_id, vm::ptr(_attr.pshared, ipc_key, _attr.flags, [&] { - return std::make_shared(protocol, ipc_key, _attr.name_u64); + return make_shared(protocol, ipc_key, _attr.name_u64); })) { return error; diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.h b/rpcs3/Emu/Cell/lv2/sys_rwlock.h index c3016af5ea..9bfcac0008 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.h +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.h @@ -40,7 +40,7 @@ struct lv2_rwlock final : lv2_obj } lv2_rwlock(utils::serial& ar); - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); }; diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index 7cf7ffd03d..02e40522e2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -20,10 +20,9 @@ lv2_sema::lv2_sema(utils::serial& ar) ar(val); } -std::shared_ptr lv2_sema::load(utils::serial& ar) +std::function lv2_sema::load(utils::serial& ar) { - auto sema = std::make_shared(ar); - return lv2_obj::load(sema->key, sema); + return load_func(make_shared(stx::exact_t(ar))); } void lv2_sema::save(utils::serial& ar) @@ -68,7 +67,7 @@ error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr sem_id, vm::ptr(_attr.pshared, ipc_key, _attr.flags, [&] { - return std::make_shared(protocol, ipc_key, _attr.name_u64, max_val, initial_val); + return make_shared(protocol, ipc_key, _attr.name_u64, max_val, initial_val); })) { return error; diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.h b/rpcs3/Emu/Cell/lv2/sys_semaphore.h index 9267c633c4..737d2b0e69 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.h +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.h @@ -42,7 +42,7 @@ struct lv2_sema final : lv2_obj } lv2_sema(utils::serial& ar); - static std::shared_ptr load(utils::serial& ar); + static std::function load(utils::serial& ar); void save(utils::serial& ar); }; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 0de03fcbaa..61a5ee80d1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -228,7 +228,7 @@ lv2_spu_group::lv2_spu_group(utils::serial& ar) noexcept if (ar.pop()) { ar(id_manager::g_id); - thread = std::make_shared>(stx::launch_retainer{}, ar, this); + thread = stx::make_shared>(stx::launch_retainer{}, ar, this); ensure(idm::import_existing>(thread, idm::last_id())); running += !thread->stop_flag_removal_protection; } @@ -340,7 +340,7 @@ void lv2_spu_image::save(utils::serial& ar) } // Get spu thread ptr, returns group ptr as well for refcounting -std::pair*, std::shared_ptr> lv2_spu_group::get_thread(u32 id) +std::pair*, shared_ptr> lv2_spu_group::get_thread(u32 id) { if (id >= 0x06000000) { @@ -349,7 +349,7 @@ std::pair*, std::shared_ptr> lv2_spu_gro } // Bits 0-23 contain group id (without id base) - decltype(get_thread(0)) res{nullptr, idm::get((id & 0xFFFFFF) | (lv2_spu_group::id_base & ~0xFFFFFF))}; + decltype(get_thread(0)) res{nullptr, idm::get_unlocked((id & 0xFFFFFF) | (lv2_spu_group::id_base & ~0xFFFFFF))}; // Bits 24-31 contain thread index within the group const u32 index = id >> 24; @@ -461,7 +461,7 @@ error_code _sys_spu_image_get_information(ppu_thread& ppu, vm::ptr(img->entry_point); + const auto image = idm::get_unlocked(img->entry_point); if (!image) { @@ -544,7 +544,7 @@ error_code _sys_spu_image_get_segments(ppu_thread& ppu, vm::ptr i return CELL_EINVAL; } - const auto handle = idm::get(img->entry_point); + const auto handle = idm::get_unlocked(img->entry_point); if (!handle) { @@ -604,7 +604,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g { case SYS_SPU_IMAGE_TYPE_KERNEL: { - const auto handle = idm::get(image.entry_point); + const auto handle = idm::get_unlocked(image.entry_point); if (!handle) { @@ -702,7 +702,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g // Read thread name const std::string thread_name(attr_data.name.get_ptr(), std::max(attr_data.name_len, 1) - 1); - const auto group = idm::get(group_id); + const auto group = idm::get_unlocked(group_id); if (!group) { @@ -737,7 +737,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g ensure(idm::import>([&]() { - const auto spu = std::make_shared>(group.get(), spu_num, thread_name, tid, false, option); + const auto spu = stx::make_shared>(group.get(), spu_num, thread_name, tid, false, option); group->threads[inited] = spu; group->threads_map[spu_num] = static_cast(inited); return spu; @@ -763,7 +763,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g } lock.unlock(); - sys_spu.warning(u8"sys_spu_thread_initialize(): Thread “%s” created (id=0x%x)", thread_name, tid); + sys_spu.warning("sys_spu_thread_initialize(): Thread \"%s\" created (id=0x%x)", thread_name, tid); ppu.check_state(); *thread = tid; @@ -927,7 +927,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num if (use_memct && mem_size) { - const auto sct = idm::get(attr_data.ct); + const auto sct = idm::get_unlocked(attr_data.ct); if (!sct) { @@ -970,7 +970,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num } lock.unlock(); - sys_spu.warning(u8"sys_spu_thread_group_create(): Thread group “%s” created (id=0x%x)", group->name, idm::last_id()); + sys_spu.warning("sys_spu_thread_group_create(): Thread group \"%s\" created (id=0x%x)", group->name, idm::last_id()); ppu.check_state(); *id = idm::last_id(); @@ -1040,7 +1040,7 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id) sys_spu.trace("sys_spu_thread_group_start(id=0x%x)", id); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1126,7 +1126,7 @@ error_code sys_spu_thread_group_suspend(ppu_thread& ppu, u32 id) sys_spu.trace("sys_spu_thread_group_suspend(id=0x%x)", id); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1209,7 +1209,7 @@ error_code sys_spu_thread_group_resume(ppu_thread& ppu, u32 id) sys_spu.trace("sys_spu_thread_group_resume(id=0x%x)", id); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1297,7 +1297,7 @@ error_code sys_spu_thread_group_yield(ppu_thread& ppu, u32 id) sys_spu.trace("sys_spu_thread_group_yield(id=0x%x)", id); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1331,7 +1331,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) sys_spu.trace("sys_spu_thread_group_terminate(id=0x%x, value=0x%x)", id, value); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1450,7 +1450,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause sys_spu.trace("sys_spu_thread_group_join(id=0x%x, cause=*0x%x, status=*0x%x)", id, cause, status); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1556,7 +1556,7 @@ error_code sys_spu_thread_group_set_priority(ppu_thread& ppu, u32 id, s32 priori sys_spu.trace("sys_spu_thread_group_set_priority(id=0x%x, priority=%d)", id, priority); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1582,7 +1582,7 @@ error_code sys_spu_thread_group_get_priority(ppu_thread& ppu, u32 id, vm::ptr(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1609,7 +1609,7 @@ error_code sys_spu_thread_group_set_cooperative_victims(ppu_thread& ppu, u32 id, sys_spu.warning("sys_spu_thread_group_set_cooperative_victims(id=0x%x, threads_mask=0x%x)", id, threads_mask); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1637,7 +1637,7 @@ error_code sys_spu_thread_group_syscall_253(ppu_thread& ppu, u32 id, vm::ptr(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1855,7 +1855,7 @@ error_code sys_spu_thread_group_connect_event(ppu_thread& ppu, u32 id, u32 eq, u sys_spu.warning("sys_spu_thread_group_connect_event(id=0x%x, eq=0x%x, et=%d)", id, eq, et); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1879,7 +1879,7 @@ error_code sys_spu_thread_group_connect_event(ppu_thread& ppu, u32 id, u32 eq, u return CELL_EINVAL; } - auto queue = idm::get(eq); + auto queue = idm::get_unlocked(eq); std::lock_guard lock(group->mutex); @@ -1904,7 +1904,7 @@ error_code sys_spu_thread_group_disconnect_event(ppu_thread& ppu, u32 id, u32 et sys_spu.warning("sys_spu_thread_group_disconnect_event(id=0x%x, et=%d)", id, et); - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -1939,7 +1939,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, sys_spu.warning("sys_spu_thread_connect_event(id=0x%x, eq=0x%x, et=%d, spup=%d)", id, eq, et, spup); const auto [thread, group] = lv2_spu_group::get_thread(id); - auto queue = idm::get(eq); + auto queue = idm::get_unlocked(eq); if (!queue || !thread) [[unlikely]] { @@ -2006,7 +2006,7 @@ error_code sys_spu_thread_bind_queue(ppu_thread& ppu, u32 id, u32 spuq, u32 spuq sys_spu.warning("sys_spu_thread_bind_queue(id=0x%x, spuq=0x%x, spuq_num=0x%x)", id, spuq, spuq_num); const auto [thread, group] = lv2_spu_group::get_thread(id); - auto queue = idm::get(spuq); + auto queue = idm::get_unlocked(spuq);; if (!queue || !thread) [[unlikely]] { @@ -2096,8 +2096,8 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i return CELL_EINVAL; } - const auto group = idm::get(id); - const auto queue = idm::get(eq); + const auto group = idm::get_unlocked(id); + const auto queue = idm::get_unlocked(eq); if (!group || !queue) { @@ -2178,7 +2178,7 @@ error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u3 return CELL_EINVAL; } - const auto group = idm::get(id); + const auto group = idm::get_unlocked(id); if (!group) { @@ -2258,7 +2258,7 @@ error_code sys_raw_spu_recover_page_fault(ppu_thread& ppu, u32 id) sys_spu.warning("sys_raw_spu_recover_page_fault(id=0x%x)", id); - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread) [[unlikely]] { @@ -2367,7 +2367,7 @@ error_code sys_isolated_spu_create(ppu_thread& ppu, vm::ptr id, vm::ptr(img.entry_point); + auto image_info = idm::get_unlocked(img.entry_point); img.deploy(thread->ls, std::span(image_info->segs.get_ptr(), image_info->nsegs)); thread->write_reg(ls_addr + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, image_info->e_entry); @@ -2402,7 +2402,7 @@ error_code raw_spu_destroy(ppu_thread& ppu, u32 id) // TODO: CELL_EBUSY is not returned // Kernel objects which must be removed - std::vector, u32>> to_remove; + std::vector, u32>> to_remove; // Clear interrupt handlers for (auto& intr : thread->int_ctrl) @@ -2484,7 +2484,7 @@ error_code raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 /*hwthread*/, const auto tag = idm::import([&]() { - std::shared_ptr result; + shared_ptr result; auto thread = idm::check_unlocked>(spu_thread::find_raw_spu(id)); @@ -2502,7 +2502,7 @@ error_code raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 /*hwthread*/, return result; } - result = std::make_shared(); + result = make_single(); int_ctrl.tag = result; return result; }); @@ -2543,7 +2543,7 @@ error_code raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask) return CELL_EINVAL; } - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread || thread->get_type() != (isolated ? spu_type::isolated : spu_type::raw)) [[unlikely]] { @@ -2582,7 +2582,7 @@ error_code raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat) return CELL_EINVAL; } - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread || thread->get_type() != (isolated ? spu_type::isolated : spu_type::raw)) [[unlikely]] { @@ -2620,7 +2620,7 @@ error_code raw_spu_get_int_control(u32 id, u32 class_id, vm::ptr value, ato return CELL_EINVAL; } - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread || thread->get_type() != (isolated ? spu_type::isolated : spu_type::raw)) [[unlikely]] { @@ -2672,7 +2672,7 @@ error_code sys_isolated_spu_get_int_stat(ppu_thread& ppu, u32 id, u32 class_id, template error_code raw_spu_read_puint_mb(u32 id, vm::ptr value) { - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread || thread->get_type() != (isolated ? spu_type::isolated : spu_type::raw)) [[unlikely]] { @@ -2711,7 +2711,7 @@ error_code raw_spu_set_spu_cfg(u32 id, u32 value) fmt::throw_exception("Unexpected value (0x%x)", value); } - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread || thread->get_type() != (isolated ? spu_type::isolated : spu_type::raw)) [[unlikely]] { @@ -2744,7 +2744,7 @@ error_code sys_isolated_spu_set_spu_cfg(ppu_thread& ppu, u32 id, u32 value) template error_code raw_spu_get_spu_cfg(u32 id, vm::ptr value) { - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread || thread->get_type() != (isolated ? spu_type::isolated : spu_type::raw)) [[unlikely]] { @@ -2781,7 +2781,7 @@ error_code sys_isolated_spu_start(ppu_thread& ppu, u32 id) sys_spu.todo("sys_isolated_spu_start(id=%d)", id); - const auto thread = idm::get>(spu_thread::find_raw_spu(id)); + const auto thread = idm::get_unlocked>(spu_thread::find_raw_spu(id)); if (!thread) [[unlikely]] { diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 7ce2c8b2ef..c1f6c31bb5 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -296,14 +296,14 @@ struct lv2_spu_group class ppu_thread* waiter = nullptr; bool set_terminate = false; - std::array>, 8> threads; // SPU Threads + std::array>, 8> threads; // SPU Threads std::array threads_map; // SPU Threads map based number std::array>, 8> imgs; // Entry points, SPU image segments std::array, 8> args; // SPU Thread Arguments - std::shared_ptr ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events - std::shared_ptr ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION - std::shared_ptr ep_sysmodule; // TODO: SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE + shared_ptr ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events + shared_ptr ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION + shared_ptr ep_sysmodule; // TODO: SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE lv2_spu_group(std::string name, u32 num, s32 _prio, s32 type, lv2_memory_container* ct, bool uses_scheduler, u32 mem_size) noexcept : name(std::move(name)) @@ -344,7 +344,7 @@ struct lv2_spu_group return ep_sysmodule ? ep_sysmodule->send(SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3) : CELL_ENOTCONN; } - static std::pair*, std::shared_ptr> get_thread(u32 id); + static std::pair*, shared_ptr> get_thread(u32 id); }; class ppu_thread; diff --git a/rpcs3/Emu/Cell/lv2/sys_storage.cpp b/rpcs3/Emu/Cell/lv2/sys_storage.cpp index e5e1aec24e..07e2956d31 100644 --- a/rpcs3/Emu/Cell/lv2/sys_storage.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_storage.cpp @@ -16,7 +16,7 @@ namespace struct storage_manager { // This is probably wrong and should be assigned per fd or something - atomic_ptr> asyncequeue; + atomic_ptr> asyncequeue; }; } @@ -65,7 +65,7 @@ error_code sys_storage_read(u32 fd, u32 mode, u32 start_sector, u32 num_sectors, } std::memset(bounce_buf.get_ptr(), 0, num_sectors * 0x200ull); - const auto handle = idm::get(fd); + const auto handle = idm::get_unlocked(fd); if (!handle) { @@ -94,7 +94,7 @@ error_code sys_storage_write(u32 fd, u32 mode, u32 start_sector, u32 num_sectors return CELL_EFAULT; } - const auto handle = idm::get(fd); + const auto handle = idm::get_unlocked(fd); if (!handle) { @@ -119,7 +119,7 @@ error_code sys_storage_async_configure(u32 fd, u32 io_buf, u32 equeue_id, u32 un auto& manager = g_fxo->get(); - if (auto queue = idm::get(equeue_id)) + if (auto queue = idm::get_unlocked(equeue_id)) { manager.asyncequeue.store(queue); } diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index afc92edd9d..83a1b22c94 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -10,6 +10,8 @@ #include "Emu/IdManager.h" #include "Emu/IPC.h" +#include "util/shared_ptr.hpp" + #include // attr_protocol (waiting scheduling policy) @@ -93,7 +95,9 @@ public: lv2_obj() noexcept = default; lv2_obj(u32 i) noexcept : exists{ i } {} + lv2_obj(lv2_obj&& rhs) noexcept : exists{ +rhs.exists } {} lv2_obj(utils::serial&) noexcept {} + lv2_obj& operator=(lv2_obj&& rhs) noexcept { exists = +rhs.exists; return *this; } void save(utils::serial&) {} // Existence validation (workaround for shared-ptr ref-counting) @@ -344,11 +348,11 @@ public: // EAGAIN for IDM IDs shortage CellError error = CELL_EAGAIN; - if (!idm::import([&]() -> std::shared_ptr + if (!idm::import([&]() -> shared_ptr { - std::shared_ptr result = make(); + shared_ptr result = make(); - auto finalize_construct = [&]() -> std::shared_ptr + auto finalize_construct = [&]() -> shared_ptr { if ((error = result->on_id_create())) { @@ -409,7 +413,7 @@ public: } template - static void on_id_destroy(T& obj, u64 ipc_key, u64 pshared = -1) + static void on_id_destroy(T& obj, u64 ipc_key, u64 pshared = umax) { if (pshared == umax) { @@ -424,16 +428,16 @@ public: } template - static std::shared_ptr load(u64 ipc_key, std::shared_ptr make, u64 pshared = -1) + static shared_ptr load(u64 ipc_key, shared_ptr make, u64 pshared = umax) { if (pshared == umax ? ipc_key != 0 : pshared != 0) { g_fxo->need>(); - make = g_fxo->get>().add(ipc_key, [&]() + g_fxo->get>().add(ipc_key, [&]() { return make; - }, true).second; + }); } // Ensure no error @@ -441,6 +445,13 @@ public: return make; } + template + static std::function load_func(shared_ptr make, u64 pshared = umax) + { + const u64 key = make->key; + return [ptr = load(key, make, pshared)](void* storage) { *static_cast*>(storage) = ptr; }; + } + static bool wait_timeout(u64 usec, ppu_thread* cpu = {}, bool scale = true, bool is_usleep = false); static inline void notify_all() diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index ec0d3cd7e2..b4b3b780f2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -20,7 +20,7 @@ LOG_CHANNEL(sys_timer); struct lv2_timer_thread { shared_mutex mutex; - std::deque> timers; + std::deque> timers; lv2_timer_thread(); void operator()(); @@ -31,7 +31,7 @@ struct lv2_timer_thread }; lv2_timer::lv2_timer(utils::serial& ar) - : lv2_obj{1} + : lv2_obj(1) , state(ar) , port(lv2_event_queue::load_ptr(ar, port, "timer")) , source(ar) @@ -368,7 +368,7 @@ error_code sys_timer_connect_event_queue(ppu_thread& ppu, u32 timer_id, u32 queu const auto timer = idm::check(timer_id, [&](lv2_timer& timer) -> CellError { - const auto found = idm::find_unlocked(queue_id); + auto found = idm::get_unlocked(queue_id); if (!found) { @@ -383,7 +383,7 @@ error_code sys_timer_connect_event_queue(ppu_thread& ppu, u32 timer_id, u32 queu } // Connect event queue - timer.port = std::static_pointer_cast(found->second); + timer.port = found; timer.source = name ? name : (u64{process_getpid() + 0u} << 32) | u64{timer_id}; timer.data1 = data1; timer.data2 = data2; diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.h b/rpcs3/Emu/Cell/lv2/sys_timer.h index b88bc5c390..14e1f31f8d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.h +++ b/rpcs3/Emu/Cell/lv2/sys_timer.h @@ -28,7 +28,7 @@ struct lv2_timer : lv2_obj shared_mutex mutex; atomic_t state{SYS_TIMER_STATE_STOP}; - std::shared_ptr port; + shared_ptr port; u64 source; u64 data1; u64 data2; @@ -40,7 +40,7 @@ struct lv2_timer : lv2_obj u64 check_unlocked(u64 _now) noexcept; lv2_timer() noexcept - : lv2_obj{1} + : lv2_obj(1) { } diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index 273787e6c2..2591824b1d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -64,7 +64,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 return CELL_EINVAL; } - const auto idm_ct = idm::get(cid); + const auto idm_ct = idm::get_unlocked(cid); const auto ct = cid == SYS_MEMORY_CONTAINER_ID_INVALID ? &g_fxo->get() : idm_ct.get(); @@ -260,7 +260,7 @@ error_code sys_vm_lock(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -281,7 +281,7 @@ error_code sys_vm_unlock(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -302,7 +302,7 @@ error_code sys_vm_touch(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -323,7 +323,7 @@ error_code sys_vm_flush(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -344,7 +344,7 @@ error_code sys_vm_invalidate(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -365,7 +365,7 @@ error_code sys_vm_store(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -386,7 +386,7 @@ error_code sys_vm_sync(ppu_thread& ppu, u32 addr, u32 size) return CELL_EINVAL; } - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -402,7 +402,7 @@ error_code sys_vm_test(ppu_thread& ppu, u32 addr, u32 size, vm::ptr result) sys_vm.warning("sys_vm_test(addr=0x%x, size=0x%x, result=*0x%x)", addr, size, result); - const auto block = idm::get(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || u64{addr} + size > u64{block->addr} + block->size) { @@ -421,7 +421,7 @@ error_code sys_vm_get_statistics(ppu_thread& ppu, u32 addr, vm::ptr(sys_vm_t::find_id(addr)); + const auto block = idm::get_unlocked(sys_vm_t::find_id(addr)); if (!block || block->addr != addr) { diff --git a/rpcs3/Emu/GDB.cpp b/rpcs3/Emu/GDB.cpp index 2b0d197eda..56ad52705a 100644 --- a/rpcs3/Emu/GDB.cpp +++ b/rpcs3/Emu/GDB.cpp @@ -587,7 +587,7 @@ bool gdb_thread::cmd_thread_info(gdb_cmd&) bool gdb_thread::cmd_current_thread(gdb_cmd&) { - return send_cmd_ack(selected_thread.expired() ? "" : ("QC" + u64_to_padded_hex(selected_thread.lock()->id))); + return send_cmd_ack(selected_thread && selected_thread->state.none_of(cpu_flag::exit) ? ("QC" + u64_to_padded_hex(selected_thread->id)) : ""); } bool gdb_thread::cmd_read_register(gdb_cmd& cmd) @@ -596,8 +596,13 @@ bool gdb_thread::cmd_read_register(gdb_cmd& cmd) { return send_cmd_ack("E02"); } - auto th = selected_thread.lock(); - if (auto ppu = th->try_get>()) + + if (!selected_thread || selected_thread->state & cpu_flag::exit) + { + return send_cmd_ack(""); + } + + if (auto ppu = selected_thread->try_get>()) { u32 rid = hex_to_u32(cmd.data); std::string result = get_reg(ppu, rid); @@ -608,7 +613,8 @@ bool gdb_thread::cmd_read_register(gdb_cmd& cmd) } return send_cmd_ack(result); } - GDB.warning("Unimplemented thread type %d.", th->id_type()); + + GDB.warning("Unimplemented thread type %d.", selected_thread->id_type()); return send_cmd_ack(""); } @@ -618,10 +624,14 @@ bool gdb_thread::cmd_write_register(gdb_cmd& cmd) { return send_cmd_ack("E02"); } - auto th = selected_thread.lock(); - if (th->get_class() == thread_class::ppu) + + if (!selected_thread || selected_thread->state & cpu_flag::exit) + { + return send_cmd_ack(""); + } + + if (auto ppu = selected_thread->try_get>()) { - auto ppu = static_cast*>(th.get()); usz eq_pos = cmd.data.find('='); if (eq_pos == umax) { @@ -637,7 +647,7 @@ bool gdb_thread::cmd_write_register(gdb_cmd& cmd) } return send_cmd_ack("OK"); } - GDB.warning("Unimplemented thread type %d.", th->id_type()); + GDB.warning("Unimplemented thread type %d.", selected_thread->id_type()); return send_cmd_ack(""); } @@ -707,10 +717,13 @@ bool gdb_thread::cmd_read_all_registers(gdb_cmd&) std::string result; select_thread(general_ops_thread_id); - auto th = selected_thread.lock(); - if (th->get_class() == thread_class::ppu) + if (!selected_thread || selected_thread->state & cpu_flag::exit) + { + return send_cmd_ack(""); + } + + if (auto ppu = selected_thread->try_get>()) { - auto ppu = static_cast*>(th.get()); //68 64-bit registers, and 3 32-bit result.reserve(68*16 + 3*8); for (int i = 0; i < 71; ++i) @@ -719,17 +732,22 @@ bool gdb_thread::cmd_read_all_registers(gdb_cmd&) } return send_cmd_ack(result); } - GDB.warning("Unimplemented thread type %d.", th->id_type()); + + GDB.warning("Unimplemented thread type %d.", selected_thread->id_type()); return send_cmd_ack(""); } bool gdb_thread::cmd_write_all_registers(gdb_cmd& cmd) { select_thread(general_ops_thread_id); - auto th = selected_thread.lock(); - if (th->get_class() == thread_class::ppu) + + if (!selected_thread || selected_thread->state & cpu_flag::exit) + { + return send_cmd_ack(""); + } + + if (auto ppu = selected_thread->try_get>()) { - auto ppu = static_cast*>(th.get()); int ptr = 0; for (int i = 0; i < 71; ++i) { @@ -739,7 +757,8 @@ bool gdb_thread::cmd_write_all_registers(gdb_cmd& cmd) } return send_cmd_ack("OK"); } - GDB.warning("Unimplemented thread type %d.", th->id_type()); + + GDB.warning("Unimplemented thread type %d.", selected_thread->id_type()); return send_cmd_ack("E01"); } @@ -789,13 +808,23 @@ bool gdb_thread::cmd_vcont(gdb_cmd& cmd) if (cmd.data[1] == 'c' || cmd.data[1] == 's') { select_thread(continue_ops_thread_id); - auto ppu = std::static_pointer_cast>(selected_thread.lock()); + + auto ppu = !selected_thread || selected_thread->state & cpu_flag::exit ? nullptr : selected_thread->try_get>(); + paused = false; - if (cmd.data[1] == 's') + + if (ppu) { - ppu->state += cpu_flag::dbg_step; + bs_t add_flags{}; + + if (cmd.data[1] == 's') + { + add_flags += cpu_flag::dbg_step; + } + + ppu->add_remove_flags(add_flags, cpu_flag::dbg_pause); } - ppu->state -= cpu_flag::dbg_pause; + //special case if app didn't start yet (only loaded) if (Emu.IsReady()) { @@ -805,19 +834,21 @@ bool gdb_thread::cmd_vcont(gdb_cmd& cmd) { Emu.Resume(); } - else - { - ppu->state.notify_one(); - } + wait_with_interrupts(); //we are in all-stop mode Emu.Pause(); select_thread(pausedBy); // we have to remove dbg_pause from thread that paused execution, otherwise // it will be paused forever (Emu.Resume only removes dbg_global_pause) - ppu = std::static_pointer_cast>(selected_thread.lock()); + + ppu = !selected_thread || selected_thread->state & cpu_flag::exit ? nullptr : selected_thread->try_get>(); + if (ppu) - ppu->state -= cpu_flag::dbg_pause; + { + ppu->add_remove_flags({}, cpu_flag::dbg_pause); + } + return send_reason(); } return send_cmd_ack(""); diff --git a/rpcs3/Emu/GDB.h b/rpcs3/Emu/GDB.h index b77578b3ae..8ba241e110 100644 --- a/rpcs3/Emu/GDB.h +++ b/rpcs3/Emu/GDB.h @@ -16,7 +16,7 @@ class gdb_thread int server_socket = -1; int client_socket = -1; - std::weak_ptr selected_thread{}; + shared_ptr selected_thread{}; u64 continue_ops_thread_id = ANY_THREAD; u64 general_ops_thread_id = ANY_THREAD; diff --git a/rpcs3/Emu/IPC.h b/rpcs3/Emu/IPC.h index 9df802c7bb..26819a3fbd 100644 --- a/rpcs3/Emu/IPC.h +++ b/rpcs3/Emu/IPC.h @@ -5,11 +5,13 @@ #include "Utilities/mutex.h" +#include "util/shared_ptr.hpp" + // IPC manager for objects of type T and IPC keys of type K. template class ipc_manager final { - std::unordered_map> m_map; + std::unordered_map> m_map; mutable shared_mutex m_mutex; @@ -17,12 +19,12 @@ public: // Add new object if specified ipc_key is not used // .first: added new object?, .second: what's at m_map[key] after this function if (peek_ptr || added new object) is true template - std::pair> add(const K& ipc_key, F&& provider, bool peek_ptr = true) + std::pair> add(const K& ipc_key, F&& provider, bool peek_ptr = true) { std::lock_guard lock(m_mutex); // Get object location - std::shared_ptr& ptr = m_map[ipc_key]; + shared_ptr& ptr = m_map[ipc_key]; const bool existed = ptr.operator bool(); if (!existed) @@ -32,7 +34,7 @@ public: } const bool added = !existed && ptr; - return {added, (peek_ptr || added) ? ptr : nullptr}; + return {added, (peek_ptr || added) ? ptr : null_ptr}; } // Unregister specified ipc_key, may return true even if the object doesn't exist anymore @@ -44,7 +46,7 @@ public: } // Get object with specified ipc_key - std::shared_ptr get(const K& ipc_key) const + shared_ptr get(const K& ipc_key) const { reader_lock lock(m_mutex); @@ -55,7 +57,7 @@ public: return found->second; } - return nullptr; + return {}; } // Check whether the object actually exists diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index 71dea33da4..b8225b07ef 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -33,7 +33,7 @@ std::vector>& id_manager::get_typeinfo_map return s_map; } -idm::map_data* idm::allocate_id(std::vector& vec, u32 type_id, u32 dst_id, u32 base, u32 step, u32 count, bool uses_lowest_id, std::pair invl_range) +id_manager::id_key* idm::allocate_id(std::span keys, u32& highest_index, u32 type_id, u32 dst_id, u32 base, u32 step, u32 count, bool uses_lowest_id, std::pair invl_range) { if (dst_id != (base ? 0 : u32{umax})) { @@ -41,44 +41,43 @@ idm::map_data* idm::allocate_id(std::vector& vec, u32 type_id, u32 dst const u32 index = id_manager::get_index(dst_id, base, step, count, invl_range); ensure(index < count); - vec.resize(std::max(vec.size(), index + 1)); + highest_index = std::max(highest_index, index + 1); - if (vec[index].second) + if (keys[index].type() != umax) { return nullptr; } id_manager::g_id = dst_id; - vec[index] = {id_manager::id_key(dst_id, type_id), nullptr}; - return &vec[index]; + keys[index] = id_manager::id_key(dst_id, type_id); + return &keys[index]; } if (uses_lowest_id) { // Disable the optimization below (hurts accuracy for known cases) - vec.resize(count); + highest_index = count; } - else if (vec.size() < count) + else if (highest_index < count) { // Try to emplace back - const u32 _next = base + step * ::size32(vec); + const u32 _next = base + step * highest_index; id_manager::g_id = _next; - vec.emplace_back(id_manager::id_key(_next, type_id), nullptr); - return &vec.back(); + return &(keys[highest_index++] = (id_manager::id_key(_next, type_id))); } // Check all IDs starting from "next id" (TODO) for (u32 i = 0, next = base; i < count; i++, next += step) { - const auto ptr = &vec[i]; + const auto ptr = &keys[i]; // Look for free ID - if (!ptr->second) + if (ptr->type() == umax) { // Incremenet ID invalidation counter - const u32 id = next | ((ptr->first + (1u << invl_range.first)) & (invl_range.second ? (((1u << invl_range.second) - 1) << invl_range.first) : 0)); + const u32 id = next | ((ptr->value() + (1u << invl_range.first)) & (invl_range.second ? (((1u << invl_range.second) - 1) << invl_range.first) : 0)); id_manager::g_id = id; - ptr->first = id_manager::id_key(id, type_id); + *ptr = id_manager::id_key(id, type_id); return ptr; } } diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 2b5b05fc5b..99082462f9 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -7,8 +7,10 @@ #include #include #include +#include #include "util/serialization.hpp" +#include "util/shared_ptr.hpp" #include "util/fixed_typemap.hpp" extern stx::manual_typemap g_fixed_typemap; @@ -19,9 +21,24 @@ enum class thread_state : u32; extern u16 serial_breathe_and_tag(utils::serial& ar, std::string_view name, bool tag_bit); +template +concept IdmCompatible = requires () { u32{T::id_base}, u32{T::id_step}, u32{T::id_count}; }; + +template +concept IdmBaseCompatible = (std::is_final_v ? IdmCompatible : !!(requires () { u32{T::id_step}, u32{T::id_count}; })); + +template +concept IdmSavable = IdmBaseCompatible && T::savestate_init_pos != 0 && (requires () { std::declval().save(std::declval>()); }); + +// If id_base is declared in base type, than storage type must declare id_type +template +concept IdmTypesCompatible = PtrSame && IdmCompatible && IdmBaseCompatible && (std::is_same_v || !IdmCompatible || !!(requires () { u32{Type::id_type}; })); + // Helper namespace namespace id_manager { + using pointer_keeper = std::function; + // Common global mutex extern shared_mutex g_mutex; @@ -31,7 +48,7 @@ namespace id_manager return {0, 0}; } - template requires requires () { T::id_invl_range; } + template requires requires () { T::id_invl_range.first + T::id_invl_range.second; } constexpr std::pair get_invl_range() { return T::id_invl_range; @@ -49,15 +66,6 @@ namespace id_manager return T::id_lowest; } - template - concept IdmCompatible = requires () { +T::id_base, +T::id_step, +T::id_count; }; - - template - concept IdmBaseCompatible = (std::is_final_v ? IdmCompatible : !!(requires () { +T::id_step, +T::id_count; })); - - template - concept IdmSavable = IdmBaseCompatible && T::savestate_init_pos != 0 && (requires () { std::declval().save(std::declval>()); }); - // Last allocated ID for constructors extern thread_local u32 g_id; @@ -102,23 +110,27 @@ namespace id_manager template struct id_traits_load_func { - static constexpr std::shared_ptr(*load)(utils::serial&) = [](utils::serial& ar) -> std::shared_ptr + static constexpr pointer_keeper(*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper { + stx::shared_ptr ptr; + if constexpr (std::is_constructible_v, stx::exact_t>) { - return std::make_shared(stx::launch_retainer{}, stx::exact_t(ar)); + ptr = stx::make_shared(stx::launch_retainer{}, stx::exact_t(ar)); } else { - return std::make_shared(stx::exact_t(ar)); + ptr = stx::make_shared(stx::exact_t(ar)); } + + return [ptr](void* storage) { *static_cast*>(storage) = ptr; }; }; }; template struct id_traits_load_func> { - static constexpr std::shared_ptr(*load)(utils::serial&) = [](utils::serial& ar) -> std::shared_ptr + static constexpr pointer_keeper(*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper { return T::load(stx::exact_t(ar)); }; @@ -138,8 +150,8 @@ namespace id_manager struct dummy_construct { - dummy_construct() {} - dummy_construct(utils::serial&){} + dummy_construct() = default; + dummy_construct(utils::serial&) noexcept {} void save(utils::serial&) {} static constexpr u32 id_base = 1, id_step = 1, id_count = 1; @@ -154,7 +166,7 @@ namespace id_manager struct typeinfo { public: - std::shared_ptr(*load)(utils::serial&); + std::function(*load)(utils::serial&); void(*save)(utils::serial&, void*); bool(*savable)(void* ptr); @@ -164,13 +176,6 @@ namespace id_manager bool uses_lowest_id; std::pair invl_range; - // Get type index - template - static inline u32 get_index() - { - return stx::typeindex(); - } - // Unique type ID within the same container: we use id_base if nothing else was specified template static consteval u32 get_type() @@ -205,11 +210,11 @@ namespace id_manager const u128 key = u128{get_type()} << 64 | std::bit_cast(C::savestate_init_pos); - for (const auto& tinfo : get_typeinfo_map()) + for (const auto& [tkey, tinfo] : get_typeinfo_map()) { - if (!(tinfo.first ^ key)) + if (!(tkey ^ key)) { - ensure(!std::memcmp(&info, &tinfo.second, sizeof(info))); + ensure(tinfo == info); return info; } } @@ -230,18 +235,23 @@ namespace id_manager return info; } + + bool operator==(const typeinfo& rhs) const noexcept + { + return base == rhs.base && invl_range == rhs.invl_range && save == rhs.save; + } }; // ID value with additional type stored class id_key { - u32 m_value; // ID value - u32 m_base; // ID base (must be unique for each type in the same container) + u32 m_value = 0; // ID value + u32 m_base = umax; // ID base (must be unique for each type in the same container) public: - id_key() = default; + id_key() noexcept = default; - id_key(u32 value, u32 type) + id_key(u32 value, u32 type) noexcept : m_value(value) , m_base(type) { @@ -257,7 +267,12 @@ namespace id_manager return m_base; } - operator u32() const + void clear() + { + m_base = umax; + } + + operator u32() const noexcept { return m_value; } @@ -268,14 +283,14 @@ namespace id_manager { static_assert(IdmBaseCompatible, "Please specify IDM compatible type."); - std::vector>> vec{}, private_copy{}; + std::array, T::id_count> vec_data{}; + std::array, T::id_count> private_copy{}; + std::array vec_keys{}; + u32 highest_index = 0; + shared_mutex mutex{}; // TODO: Use this instead of global mutex - id_map() noexcept - { - // Preallocate memory - vec.reserve(T::id_count); - } + id_map() noexcept = default; // Order it directly before the source type's position static constexpr double savestate_init_pos_original = T::savestate_init_pos; @@ -283,10 +298,6 @@ namespace id_manager id_map(utils::serial& ar) noexcept requires IdmSavable { - vec.resize(T::id_count); - - usz highest = 0; - while (true) { const u16 tag = serial_breathe_and_tag(ar, g_fxo->get_name>(), false); @@ -319,26 +330,26 @@ namespace id_manager // Simulate construction semantics (idm::last_id() value) g_id = id; - const usz object_index = get_index(id, info->base, info->step, info->count, info->invl_range); - auto& obj = ::at32(vec, object_index); - ensure(!obj.second); + const u32 object_index = get_index(id, info->base, info->step, info->count, info->invl_range); + auto& obj = ::at32(vec_data, object_index); + ensure(!obj); - highest = std::max(highest, object_index + 1); + highest_index = std::max(highest_index, object_index + 1); - obj.first = id_key(id, static_cast(static_cast(type_init_pos >> 64))); - obj.second = info->load(ar); + vec_keys[object_index] = id_key(id, static_cast(static_cast(type_init_pos >> 64))); + info->load(ar)(&obj); } - - vec.resize(highest); } void save(utils::serial& ar) requires IdmSavable { - for (const auto& p : vec) + for (const auto& p : vec_data) { - if (!p.second) continue; + if (!p) continue; - const u128 type_init_pos = u128{p.first.type()} << 64 | std::bit_cast(T::savestate_init_pos); + auto& key = vec_keys[&p - vec_data.data()]; + + const u128 type_init_pos = u128{key.type()} << 64 | std::bit_cast(T::savestate_init_pos); const typeinfo* info = nullptr; // Search load functions for the one of this type (see make_typeinfo() for explenation about key composition reasoning) @@ -351,13 +362,13 @@ namespace id_manager } // Save each object with needed information - if (info && info->savable(p.second.get())) + if (info && info->savable(p.observe())) { // Create a tag for each object serial_breathe_and_tag(ar, g_fxo->get_name>(), false); - ar(p.first.value(), p.first.type()); - info->save(ar, p.second.get()); + ar(key.value(), key.type()); + info->save(ar, p.observe()); } } @@ -367,22 +378,23 @@ namespace id_manager id_map& operator=(thread_state state) noexcept requires (std::is_assignable_v) { - private_copy.clear(); - - if (!vec.empty() || !private_copy.empty()) + if (highest_index) { reader_lock lock(g_mutex); // Save all entries - private_copy = vec; + for (u32 i = 0; i < highest_index; i++) + { + private_copy[i] = vec_data[i].load(); + } } // Signal or join threads - for (const auto& [key, ptr] : private_copy) + for (const auto& ptr : private_copy) { if (ptr) { - *static_cast(ptr.get()) = state; + *ptr = state; } } @@ -422,24 +434,27 @@ class idm // Helper type: pointer + return value propagated template - struct return_pair + struct return_pair; + + template + struct return_pair, RT> { - std::shared_ptr ptr; + stx::shared_ptr ptr; RT ret; - explicit operator bool() const + explicit operator bool() const noexcept { return ptr.operator bool(); } - T& operator*() const + T& operator*() const noexcept { return *ptr; } - T* operator->() const + T* operator->() const noexcept { - return ptr.get(); + return ptr.operator->(); } }; @@ -450,61 +465,67 @@ class idm T* ptr; RT ret; - explicit operator bool() const + explicit operator bool() const noexcept { return ptr != nullptr; } - T& operator*() const + T& operator*() const noexcept { return *ptr; } - T* operator->() const + T* operator->() const noexcept { return ptr; } }; - using map_data = std::pair>; + // Get type ID that is meant to be unique within the same container + template + static consteval u32 get_type() + { + return id_manager::typeinfo::get_type(); + } // Prepare new ID (returns nullptr if out of resources) - static map_data* allocate_id(std::vector& vec, u32 type_id, u32 dst_id, u32 base, u32 step, u32 count, bool uses_lowest_id, std::pair invl_range); + static id_manager::id_key* allocate_id(std::span keys, u32& highest_index, u32 type_id, u32 dst_id, u32 base, u32 step, u32 count, bool uses_lowest_id, std::pair invl_range); // Get object by internal index if exists (additionally check type if types are not equal) template - static map_data* find_index(u32 index, u32 id) + static std::pair*, id_manager::id_key*> find_index(u32 index, u32 id) { - static_assert(PtrSame, "Invalid ID type combination"); + static_assert(IdmTypesCompatible, "Invalid ID type combination"); - auto& vec = g_fxo->get>().vec; + auto& map = g_fxo->get>(); - if (index >= vec.size()) + if (index >= map.highest_index) { - return nullptr; + return {}; } - auto& data = vec[index]; + auto& data = map.vec_data[index]; + auto& key = map.vec_keys[index]; - if (data.second) + if (data) { - if (std::is_same_v || data.first.type() == get_type()) + if (std::is_same_v || key.type() == get_type()) { - if (!id_manager::id_traits::invl_range.second || data.first.value() == id) + if (!id_manager::id_traits::invl_range.second || key.value() == id) { - return &data; + return { &data, &key }; } } } - return nullptr; + return {}; } // Find ID template - static map_data* find_id(u32 id) + static std::pair*, id_manager::id_key*> find_id(u32 id) { - static_assert(PtrSame, "Invalid ID type combination"); + static_assert(IdmTypesCompatible, "Invalid ID type combination"); const u32 index = get_index(id); @@ -513,9 +534,9 @@ class idm // Allocate new ID (or use fixed ID) and assign the object from the provider() template - static map_data* create_id(F&& provider, u32 id = id_manager::id_traits::invalid) + static stx::shared_ptr create_id(F&& provider, u32 id = id_manager::id_traits::invalid) { - static_assert(PtrSame, "Invalid ID type combination"); + static_assert(IdmTypesCompatible, "Invalid ID type combination"); // ID traits using traits = id_manager::id_traits; @@ -528,18 +549,21 @@ class idm auto& map = g_fxo->get>(); - if (auto* place = allocate_id(map.vec, get_type(), id, traits::base, traits::step, traits::count, traits::uses_lowest_id, traits::invl_range)) + if (auto* key_ptr = allocate_id({map.vec_keys.data(), map.vec_keys.size()}, map.highest_index, get_type(), id, traits::base, traits::step, traits::count, traits::uses_lowest_id, traits::invl_range)) { - // Get object, store it - place->second = provider(); + auto& place = map.vec_data[key_ptr - map.vec_keys.data()]; - if (place->second) + // Get object, store it + if (auto object = provider()) { - return place; + place = object; + return object; } + + *key_ptr = {}; } - return nullptr; + return {}; } public: @@ -549,7 +573,16 @@ public: static inline void clear() { std::lock_guard lock(id_manager::g_mutex); - g_fxo->get>().vec.clear(); + + for (auto& ptr : g_fxo->get>().vec_data) + { + ptr.reset(); + } + + for (auto& key : g_fxo->get>().vec_keys) + { + key.clear(); + } } // Get last ID (updated in create_id/allocate_id) @@ -558,44 +591,38 @@ public: return id_manager::g_id; } - // Get type ID that is meant to be unique within the same container - template - static consteval u32 get_type() - { - return id_manager::typeinfo::get_type(); - } - - // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) + // Add a new ID of specified type with specified constructor arguments (returns object or null_ptr) template requires (std::is_constructible_v) - static inline std::shared_ptr make_ptr(Args&&... args) + static inline stx::shared_ptr make_ptr(Args&&... args) { - if (auto pair = create_id([&] { return std::make_shared(std::forward(args)...); })) + if (auto pair = create_id([&] { return stx::make_shared(std::forward(args)...); })) { - return {pair->second, static_cast(pair->second.get())}; + return pair; } - return nullptr; + return null_ptr; } // Add a new ID of specified type with specified constructor arguments (returns id) template requires (std::is_constructible_v) static inline u32 make(Args&&... args) { - if (auto pair = create_id([&] { return std::make_shared(std::forward(args)...); })) + if (create_id([&] { return stx::make_shared(std::forward(args)...); })) { - return pair->first; + return last_id(); } return id_manager::id_traits::invalid; } // Add a new ID for an object returned by provider() - template requires (std::is_invocable_v) + template + requires IdmTypesCompatible && std::is_convertible_v, stx::shared_ptr> static inline u32 import(F&& provider, u32 id = id_manager::id_traits::invalid) { - if (auto pair = create_id(std::forward(provider), id)) + if (create_id(std::forward(provider), id)) { - return pair->first; + return last_id(); } return id_manager::id_traits::invalid; @@ -603,41 +630,28 @@ public: // Add a new ID for an existing object provided (returns new id) template - static inline u32 import_existing(std::shared_ptr ptr, u32 id = id_manager::id_traits::invalid) + requires IdmTypesCompatible + static inline u32 import_existing(stx::shared_ptr ptr, u32 id = id_manager::id_traits::invalid) { - return import([&] { return std::move(ptr); }, id); - } - - // Access the ID record without locking (unsafe) - template - static inline map_data* find_unlocked(u32 id) - { - return find_id(id); + return import([&]() -> stx::shared_ptr { return std::move(ptr); }, id); } // Check the ID without locking (can be called from other method) template + requires IdmTypesCompatible static inline Get* check_unlocked(u32 id) { - if (const auto found = find_id(id)) + if (const auto found = find_id(id); found.first) { - return static_cast(found->second.get()); + return static_cast(found.first->observe()); } return nullptr; } - // Check the ID - template - static inline Get* check(u32 id) - { - reader_lock lock(id_manager::g_mutex); - - return check_unlocked(id); - } - // Check the ID, access object under shared lock template > + requires IdmTypesCompatible static inline std::conditional_t, Get*, return_pair> check(u32 id, F&& func) { const u32 index = get_index(id); @@ -649,9 +663,9 @@ public: reader_lock lock(id_manager::g_mutex); - if (const auto found = find_index(index, id)) + if (const auto found = find_index(index, id); found.first) { - const auto ptr = static_cast(found->second.get()); + const auto ptr = static_cast(found.first->observe()); if constexpr (!std::is_void_v) { @@ -669,57 +683,51 @@ public: // Get the object without locking (can be called from other method) template - static inline std::shared_ptr get_unlocked(u32 id) + requires IdmTypesCompatible + static inline stx::shared_ptr get_unlocked(u32 id) { const auto found = find_id(id); - if (found == nullptr) [[unlikely]] + if (!found.first) [[unlikely]] { - return nullptr; + return null_ptr; } - return std::static_pointer_cast(found->second); - } - - // Get the object - template - static inline std::shared_ptr get(u32 id) - { - reader_lock lock(id_manager::g_mutex); - - return get_unlocked(id); + return static_cast>(found.first->load()); } // Get the object, access object under reader lock template > - static inline std::conditional_t, std::shared_ptr, return_pair> get(u32 id, F&& func) + requires IdmTypesCompatible + static inline std::conditional_t, stx::shared_ptr, return_pair, FRT>> get(u32 id, F&& func) { const u32 index = get_index(id); if (index >= id_manager::id_traits::count) { - return {nullptr}; + return {}; } reader_lock lock(id_manager::g_mutex); const auto found = find_index(index, id); - if (found == nullptr) [[unlikely]] + if (!found.first) [[unlikely]] { - return {nullptr}; + return {}; } - const auto ptr = static_cast(found->second.get()); + auto ptr = static_cast>(found.first->load()); + Get* obj_ptr = ptr.get(); if constexpr (std::is_void_v) { - func(*ptr); - return {found->second, ptr}; + func(*obj_ptr); + return ptr; } else { - return {{found->second, ptr}, func(*ptr)}; + return {std::move(ptr), func(*obj_ptr)}; } } @@ -728,9 +736,10 @@ public: // Access all objects of specified type. Returns the number of objects processed. // If function result evaluates to true, stop and return the object and the value. template - static inline auto select(F&& func, Lock = {}) + requires IdmBaseCompatible && (IdmCompatible && ...) && (std::is_invocable_v && ...) + static inline auto select(F&& func, Lock = std::true_type{}) { - static_assert((PtrSame && ...), "Invalid ID type combination"); + static_assert((IdmTypesCompatible && ...), "Invalid ID type combination"); [[maybe_unused]] std::conditional_t lock(id_manager::g_mutex); @@ -740,23 +749,30 @@ public: static_assert(PtrSame, "Invalid function argument type combination"); - std::conditional_t, u32, return_pair> result{}; + std::conditional_t, u32, return_pair, result_type>> result{}; - for (auto& id : g_fxo->get>().vec) + auto& map = g_fxo->get>(); + + for (auto& id : map.vec_data) { - if (auto ptr = static_cast(id.second.get())) + if (auto ptr = static_cast(id.observe())) { - if (sizeof...(Get) == 0 || ((id.first.type() == get_type()) || ...)) + auto& key = map.vec_keys[&id - map.vec_data.data()]; + + if (sizeof...(Get) == 0 || ((key.type() == get_type()) || ...)) { if constexpr (std::is_void_v) { - func(id.first, *ptr); + func(key, *ptr); result++; } - else if ((result.ret = func(id.first, *ptr))) + else { - result.ptr = {id.second, ptr}; - break; + if ((result.ret = func(key, *ptr))) + { + result.ptr = static_cast>(id.load()); + break; + } } } } @@ -767,15 +783,17 @@ public: // Remove the ID template + requires IdmTypesCompatible static inline bool remove(u32 id) { - std::shared_ptr ptr; + stx::shared_ptr ptr; { std::lock_guard lock(id_manager::g_mutex); - if (const auto found = find_id(id)) + if (const auto found = find_id(id); found.first) { - ptr = std::move(found->second); + ptr = found.first->exchange(null_ptr); + found.second->clear(); } else { @@ -783,21 +801,31 @@ public: } } + if constexpr (std::is_assignable_v) + { + if (ptr) + { + constexpr thread_state finished{3}; + *static_cast(ptr.get()) = finished; + } + } + return true; } // Remove the ID if matches the weak/shared ptr - template - static inline bool remove_verify(u32 id, Ptr sptr) + template + requires IdmTypesCompatible && std::is_convertible_v + static inline bool remove_verify(u32 id, Ptr&& sptr, Lock = std::true_type{}) { - std::shared_ptr ptr; + stx::shared_ptr ptr; { - std::lock_guard lock(id_manager::g_mutex); + [[maybe_unused]] std::conditional_t, const shared_mutex&> lock(id_manager::g_mutex); - if (const auto found = find_id(id); found && - (!found->second.owner_before(sptr) && !sptr.owner_before(found->second))) + if (const auto found = find_id(id); found.first && found.first->is_equal(sptr)) { - ptr = std::move(found->second); + ptr = found.first->exchange(null_ptr); + found.second->clear(); } else { @@ -805,20 +833,31 @@ public: } } + if constexpr (std::is_assignable_v) + { + if (ptr) + { + constexpr thread_state finished{3}; + *static_cast(ptr.get()) = finished; + } + } + return true; } // Remove the ID and return the object - template - static inline std::shared_ptr withdraw(u32 id) + template + requires IdmTypesCompatible + static inline stx::shared_ptr withdraw(u32 id, int = 0, Lock = std::true_type{}) { - std::shared_ptr ptr; + stx::shared_ptr ptr; { - std::lock_guard lock(id_manager::g_mutex); + [[maybe_unused]] std::conditional_t, const shared_mutex&> lock(id_manager::g_mutex); - if (const auto found = find_id(id)) + if (const auto found = find_id(id); found.first) { - ptr = std::static_pointer_cast(::as_rvalue(std::move(found->second))); + ptr = static_cast>(found.first->exchange(null_ptr)); + found.second->clear(); } } @@ -827,25 +866,27 @@ public: // Remove the ID after accessing the object under writer lock, return the object and propagate return value template > - static inline std::conditional_t, std::shared_ptr, return_pair> withdraw(u32 id, F&& func) + requires IdmTypesCompatible && std::is_invocable_v + static inline std::conditional_t, stx::shared_ptr, return_pair, FRT>> withdraw(u32 id, F&& func) { const u32 index = get_index(id); if (index >= id_manager::id_traits::count) { - return {nullptr}; + return {}; } std::unique_lock lock(id_manager::g_mutex); - if (const auto found = find_index(index, id)) + if (const auto found = find_index(index, id); found.first) { - const auto _ptr = static_cast(found->second.get()); + const auto _ptr = static_cast(found.first->observe()); if constexpr (std::is_void_v) { func(*_ptr); - return std::static_pointer_cast(::as_rvalue(std::move(found->second))); + found.second->clear(); + return static_cast>(found.first->exchange(null_ptr)); } else { @@ -854,13 +895,14 @@ public: if (ret) { // If return value evaluates to true, don't delete the object (error code) - return {{found->second, _ptr}, std::move(ret)}; + return {static_cast>(found.first->load()), std::move(ret)}; } - return {std::static_pointer_cast(::as_rvalue(std::move(found->second))), std::move(ret)}; + found.second->clear(); + return {static_cast>(found.first->exchange(null_ptr)), std::move(ret)}; } } - return {nullptr}; + return {}; } }; diff --git a/rpcs3/Emu/Io/Null/null_camera_handler.h b/rpcs3/Emu/Io/Null/null_camera_handler.h index 61e26a8d96..a250facd75 100644 --- a/rpcs3/Emu/Io/Null/null_camera_handler.h +++ b/rpcs3/Emu/Io/Null/null_camera_handler.h @@ -7,10 +7,10 @@ class null_camera_handler final : public camera_handler_base public: null_camera_handler() : camera_handler_base() {} - void open_camera() override { m_state = camera_handler_state::open; } - void close_camera() override { m_state = camera_handler_state::closed; } - void start_camera() override { m_state = camera_handler_state::running; } - void stop_camera() override { m_state = camera_handler_state::open; } + void open_camera() override { set_state(camera_handler_state::open); } + void close_camera() override { set_state(camera_handler_state::closed); } + void start_camera() override { set_state(camera_handler_state::running); } + void stop_camera() override { set_state(camera_handler_state::open); } void set_format(s32 format, u32 bytesize) override { @@ -45,6 +45,6 @@ public: height = 0; frame_number = 0; bytes_read = 0; - return m_state; + return get_state(); } }; diff --git a/rpcs3/Emu/Io/camera_handler_base.h b/rpcs3/Emu/Io/camera_handler_base.h index 531fa3abe3..49ce4dc635 100644 --- a/rpcs3/Emu/Io/camera_handler_base.h +++ b/rpcs3/Emu/Io/camera_handler_base.h @@ -30,22 +30,29 @@ public: virtual u64 frame_number() const = 0; // Convenience function to check if there's a new frame. virtual camera_handler_state get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) = 0; - camera_handler_state get_state() const { return m_state.load(); }; + camera_handler_state get_state() const { return m_state.load(); } + void set_state(camera_handler_state state) { m_state = m_state_expected = state; } - bool mirrored() const { return m_mirrored; }; - s32 format() const { return m_format; }; - u32 bytesize() const { return m_bytesize; }; - u32 width() const { return m_width; }; - u32 height() const { return m_height; }; - u32 frame_rate() const { return m_frame_rate; }; + camera_handler_state get_expected_state() const { return m_state_expected.load(); } + void set_expected_state(camera_handler_state state) { m_state_expected = state; } + + bool mirrored() const { return m_mirrored; } + s32 format() const { return m_format; } + u32 bytesize() const { return m_bytesize; } + u32 width() const { return m_width; } + u32 height() const { return m_height; } + u32 frame_rate() const { return m_frame_rate; } protected: std::mutex m_mutex; - atomic_t m_state = camera_handler_state::closed; bool m_mirrored = false; s32 m_format = 2; // CELL_CAMERA_RAW8 u32 m_bytesize = 0; u32 m_width = 640; u32 m_height = 480; u32 m_frame_rate = 30; + +private: + atomic_t m_state = camera_handler_state::closed; + atomic_t m_state_expected = camera_handler_state::closed; }; diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index 77d56fdf59..1f9552a6f8 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -466,13 +466,21 @@ struct ps_move_data bool external_device_read_requested = false; bool external_device_write_requested = false; + bool calibration_requested = false; + bool calibration_succeeded = false; + + bool magnetometer_enabled = false; + std::array quaternion { 1.0f, 0.0f, 0.0f, 0.0f }; // quaternion orientation (x,y,z,w) of controller relative to default (facing the camera with buttons up) - f32 accelerometer_x = 0; // linear velocity in m/s² - f32 accelerometer_y = 0; // linear velocity in m/s² - f32 accelerometer_z = 0; // linear velocity in m/s² - f32 gyro_x = 0; // angular velocity in rad/s - f32 gyro_y = 0; // angular velocity in rad/s - f32 gyro_z = 0; // angular velocity in rad/s + f32 accelerometer_x = 0.0f; // linear velocity in m/s² + f32 accelerometer_y = 0.0f; // linear velocity in m/s² + f32 accelerometer_z = 0.0f; // linear velocity in m/s² + f32 gyro_x = 0.0f; // angular velocity in rad/s + f32 gyro_y = 0.0f; // angular velocity in rad/s + f32 gyro_z = 0.0f; // angular velocity in rad/s + f32 magnetometer_x = 0.0f; + f32 magnetometer_y = 0.0f; + f32 magnetometer_z = 0.0f; s16 temperature = 0; }; diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 446d8d98a3..6ab0ecc71d 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1749,8 +1749,7 @@ namespace vm if (is_memory_compatible_for_copy_from_executable_optimization(addr, shm.first)) { // Revert changes - ar.data.resize(ar.data.size() - (sizeof(u32) * 2 + sizeof(memory_page))); - ar.seek_end(); + ar.trunc(sizeof(u32) * 2 + sizeof(memory_page)); vm_log.success("Removed memory block matching the memory of the executable from savestate. (addr=0x%x, size=0x%x)", addr, shm.first); continue; } diff --git a/rpcs3/Emu/NP/np_contexts.cpp b/rpcs3/Emu/NP/np_contexts.cpp index 8c047b7eb5..cd9a11f28d 100644 --- a/rpcs3/Emu/NP/np_contexts.cpp +++ b/rpcs3/Emu/NP/np_contexts.cpp @@ -9,6 +9,7 @@ LOG_CHANNEL(sceNp2); generic_async_transaction_context::generic_async_transaction_context(const SceNpCommunicationId& communicationId, const SceNpCommunicationPassphrase& passphrase, u64 timeout) : communicationId(communicationId), passphrase(passphrase), timeout(timeout) + , idm_id(idm::last_id()) { } @@ -73,12 +74,12 @@ bool destroy_tus_context(s32 ctx_id) return idm::remove(static_cast(ctx_id)); } -tus_transaction_ctx::tus_transaction_ctx(const std::shared_ptr& tus) +tus_transaction_ctx::tus_transaction_ctx(const shared_ptr& tus) : generic_async_transaction_context(tus->communicationId, tus->passphrase, tus->timeout) { } -s32 create_tus_transaction_context(const std::shared_ptr& tus) +s32 create_tus_transaction_context(const shared_ptr& tus) { s32 tus_id = idm::make(tus); @@ -116,13 +117,13 @@ bool destroy_score_context(s32 ctx_id) return idm::remove(static_cast(ctx_id)); } -score_transaction_ctx::score_transaction_ctx(const std::shared_ptr& score) +score_transaction_ctx::score_transaction_ctx(const shared_ptr& score) : generic_async_transaction_context(score->communicationId, score->passphrase, score->timeout) { pcId = score->pcId; } -s32 create_score_transaction_context(const std::shared_ptr& score) +s32 create_score_transaction_context(const shared_ptr& score) { s32 trans_id = idm::make(score); @@ -158,11 +159,11 @@ bool destroy_match2_context(u16 ctx_id) } bool check_match2_context(u16 ctx_id) { - return (idm::check(ctx_id) != nullptr); + return (idm::check_unlocked(ctx_id) != nullptr); } -std::shared_ptr get_match2_context(u16 ctx_id) +shared_ptr get_match2_context(u16 ctx_id) { - return idm::get(ctx_id); + return idm::get_unlocked(ctx_id); } lookup_title_ctx::lookup_title_ctx(vm::cptr communicationId) @@ -207,9 +208,9 @@ bool destroy_commerce2_context(u32 ctx_id) { return idm::remove(static_cast(ctx_id)); } -std::shared_ptr get_commerce2_context(u16 ctx_id) +shared_ptr get_commerce2_context(u16 ctx_id) { - return idm::get(ctx_id); + return idm::get_unlocked(ctx_id); } signaling_ctx::signaling_ctx(vm::ptr npid, vm::ptr handler, vm::ptr arg) @@ -226,9 +227,9 @@ bool destroy_signaling_context(u32 ctx_id) { return idm::remove(static_cast(ctx_id)); } -std::shared_ptr get_signaling_context(u32 ctx_id) +shared_ptr get_signaling_context(u32 ctx_id) { - return idm::get(ctx_id); + return idm::get_unlocked(ctx_id); } matching_ctx::matching_ctx(vm::ptr npId, vm::ptr handler, vm::ptr arg) @@ -266,9 +267,9 @@ s32 create_matching_context(vm::ptr npId, vm::ptr ctx->ctx_id = ctx_id; return static_cast(ctx_id); } -std::shared_ptr get_matching_context(u32 ctx_id) +shared_ptr get_matching_context(u32 ctx_id) { - return idm::get(ctx_id); + return idm::get_unlocked(ctx_id); } bool destroy_matching_context(u32 ctx_id) { diff --git a/rpcs3/Emu/NP/np_contexts.h b/rpcs3/Emu/NP/np_contexts.h index cb576f6e95..cf11098dd8 100644 --- a/rpcs3/Emu/NP/np_contexts.h +++ b/rpcs3/Emu/NP/np_contexts.h @@ -20,7 +20,7 @@ // Used By Score and Tus struct generic_async_transaction_context { - virtual ~generic_async_transaction_context(); + ~generic_async_transaction_context(); generic_async_transaction_context(const SceNpCommunicationId& communicationId, const SceNpCommunicationPassphrase& passphrase, u64 timeout); @@ -37,6 +37,8 @@ struct generic_async_transaction_context u64 timeout; std::thread thread; + + u32 idm_id; }; struct tdata_invalid @@ -137,8 +139,7 @@ bool destroy_tus_context(s32 ctx_id); struct tus_transaction_ctx : public generic_async_transaction_context { - tus_transaction_ctx(const std::shared_ptr& tus); - virtual ~tus_transaction_ctx() = default; + tus_transaction_ctx(const shared_ptr& tus); static const u32 id_base = 0x8001; static const u32 id_step = 1; @@ -148,7 +149,7 @@ struct tus_transaction_ctx : public generic_async_transaction_context std::variant tdata; }; -s32 create_tus_transaction_context(const std::shared_ptr& tus); +s32 create_tus_transaction_context(const shared_ptr& tus); bool destroy_tus_transaction_context(s32 ctx_id); // Score related @@ -172,8 +173,7 @@ bool destroy_score_context(s32 ctx_id); struct score_transaction_ctx : public generic_async_transaction_context { - score_transaction_ctx(const std::shared_ptr& score); - virtual ~score_transaction_ctx() = default; + score_transaction_ctx(const shared_ptr& score); static const u32 id_base = 0x1001; static const u32 id_step = 1; @@ -183,7 +183,7 @@ struct score_transaction_ctx : public generic_async_transaction_context std::variant tdata; s32 pcId = 0; }; -s32 create_score_transaction_context(const std::shared_ptr& score); +s32 create_score_transaction_context(const shared_ptr& score); bool destroy_score_transaction_context(s32 ctx_id); // Match2 related @@ -214,7 +214,7 @@ struct match2_ctx }; u16 create_match2_context(vm::cptr communicationId, vm::cptr passphrase, s32 option); bool check_match2_context(u16 ctx_id); -std::shared_ptr get_match2_context(u16 ctx_id); +shared_ptr get_match2_context(u16 ctx_id); bool destroy_match2_context(u16 ctx_id); struct lookup_title_ctx @@ -261,7 +261,7 @@ struct commerce2_ctx vm::ptr context_callback_param{}; }; s32 create_commerce2_context(u32 version, vm::cptr npid, vm::ptr handler, vm::ptr arg); -std::shared_ptr get_commerce2_context(u16 ctx_id); +shared_ptr get_commerce2_context(u16 ctx_id); bool destroy_commerce2_context(u32 ctx_id); struct signaling_ctx @@ -282,7 +282,7 @@ struct signaling_ctx vm::ptr ext_arg{}; }; s32 create_signaling_context(vm::ptr npid, vm::ptr handler, vm::ptr arg); -std::shared_ptr get_signaling_context(u32 ctx_id); +shared_ptr get_signaling_context(u32 ctx_id); bool destroy_signaling_context(u32 ctx_id); struct matching_ctx @@ -315,5 +315,5 @@ struct matching_ctx atomic_t get_room_limit_version = false; }; s32 create_matching_context(vm::ptr npid, vm::ptr handler, vm::ptr arg); -std::shared_ptr get_matching_context(u32 ctx_id); +shared_ptr get_matching_context(u32 ctx_id); bool destroy_matching_context(u32 ctx_id); diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index e3eafc7b9d..3bcff2f960 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -502,7 +502,7 @@ namespace np np_handler::~np_handler() { - std::unordered_map> moved_trans; + std::unordered_map> moved_trans; { std::lock_guard lock(mutex_async_transactions); moved_trans = std::move(async_transactions); @@ -999,7 +999,7 @@ namespace np return CELL_OK; } - std::optional>> np_handler::get_message(u64 id) + std::optional>> np_handler::get_message(u64 id) { return get_rpcn()->get_message(id); } @@ -1019,7 +1019,7 @@ namespace np } } - std::optional>> np_handler::get_message_selected(SceNpBasicAttachmentDataId id) + std::optional>> np_handler::get_message_selected(SceNpBasicAttachmentDataId id) { switch (id) { @@ -1672,7 +1672,7 @@ namespace np return ctx_id; } - std::shared_ptr np_handler::take_pending_gui_request(u32 req_id) + shared_ptr np_handler::take_pending_gui_request(u32 req_id) { const u32 ctx_id = take_gui_request(req_id); diff --git a/rpcs3/Emu/NP/np_handler.h b/rpcs3/Emu/NP/np_handler.h index 8b6f2f7110..e6524ab98a 100644 --- a/rpcs3/Emu/NP/np_handler.h +++ b/rpcs3/Emu/NP/np_handler.h @@ -150,9 +150,9 @@ namespace np error_code get_basic_event(vm::ptr event, vm::ptr from, vm::ptr data, vm::ptr size); // Messages-related functions - std::optional>> get_message(u64 id); + std::optional>> get_message(u64 id); void set_message_selected(SceNpBasicAttachmentDataId id, u64 msg_id); - std::optional>> get_message_selected(SceNpBasicAttachmentDataId id); + std::optional>> get_message_selected(SceNpBasicAttachmentDataId id); void clear_message_selected(SceNpBasicAttachmentDataId id); void send_message(const message_data& msg_data, const std::set& npids); @@ -206,29 +206,29 @@ namespace np void set_current_gui_ctx_id(u32 id); // Score requests - void transaction_async_handler(std::unique_lock lock, const std::shared_ptr& trans_ctx, u32 req_id, bool async); - void get_board_infos(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, vm::ptr boardInfo, bool async); - void record_score(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, vm::cptr scoreComment, const u8* data, u32 data_size, vm::ptr tmpRank, bool async); - void record_score_data(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, u32 totalSize, u32 sendSize, const u8* score_data, bool async); - void get_score_data(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const SceNpId& npId, vm::ptr totalSize, u32 recvSize, vm::ptr score_data, bool async); - void get_score_range(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreRankNumber startSerialRank, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated); - void get_score_npid(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const std::vector>& npid_vec, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated); - void get_score_friend(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated); + void transaction_async_handler(std::unique_lock lock, const shared_ptr& trans_ctx, u32 req_id, bool async); + void get_board_infos(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, vm::ptr boardInfo, bool async); + void record_score(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, vm::cptr scoreComment, const u8* data, u32 data_size, vm::ptr tmpRank, bool async); + void record_score_data(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, u32 totalSize, u32 sendSize, const u8* score_data, bool async); + void get_score_data(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const SceNpId& npId, vm::ptr totalSize, u32 recvSize, vm::ptr score_data, bool async); + void get_score_range(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreRankNumber startSerialRank, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated); + void get_score_npid(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const std::vector>& npid_vec, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated); + void get_score_friend(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated); // TUS requests - void tus_set_multislot_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::cptr variableArray, s32 arrayNum, bool vuser, bool async); - void tus_get_multislot_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async); - void tus_get_multiuser_variable(std::shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async); - void tus_get_friends_variable(std::shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr variableArray,s32 arrayNum, bool async); - void tus_add_and_get_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s64 inVariable, vm::ptr outVariable, vm::ptr option, bool vuser, bool async); - void tus_try_and_set_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s32 opeType, s64 variable, vm::ptr resultVariable, vm::ptr option, bool vuser, bool async); - void tus_delete_multislot_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async); - void tus_set_data(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr data, vm::cptr info, vm::ptr option, bool vuser, bool async); - void tus_get_data(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, vm::ptr dataStatus, vm::ptr data, u32 recvSize, bool vuser, bool async); - void tus_get_multislot_data_status(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async); - void tus_get_multiuser_data_status(std::shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async); - void tus_get_friends_data_status(std::shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr statusArray, s32 arrayNum, bool async); - void tus_delete_multislot_data(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async); + void tus_set_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::cptr variableArray, s32 arrayNum, bool vuser, bool async); + void tus_get_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async); + void tus_get_multiuser_variable(shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async); + void tus_get_friends_variable(shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr variableArray,s32 arrayNum, bool async); + void tus_add_and_get_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s64 inVariable, vm::ptr outVariable, vm::ptr option, bool vuser, bool async); + void tus_try_and_set_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s32 opeType, s64 variable, vm::ptr resultVariable, vm::ptr option, bool vuser, bool async); + void tus_delete_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async); + void tus_set_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr data, vm::cptr info, vm::ptr option, bool vuser, bool async); + void tus_get_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, vm::ptr dataStatus, vm::ptr data, u32 recvSize, bool vuser, bool async); + void tus_get_multislot_data_status(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async); + void tus_get_multiuser_data_status(shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async); + void tus_get_friends_data_status(shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr statusArray, s32 arrayNum, bool async); + void tus_delete_multislot_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async); // Local functions std::pair> local_get_npid(u64 room_id, u16 member_id); @@ -494,7 +494,7 @@ namespace np // Async transaction threads shared_mutex mutex_async_transactions; - std::unordered_map> async_transactions; // (req_id, transaction_ctx) + std::unordered_map> async_transactions; // (req_id, transaction_ctx) // RPCN shared_mutex mutex_rpcn; @@ -529,7 +529,7 @@ namespace np void add_gui_request(u32 req_id, u32 ctx_id); void remove_gui_request(u32 req_id); u32 take_gui_request(u32 req_id); - std::shared_ptr take_pending_gui_request(u32 req_id); + shared_ptr take_pending_gui_request(u32 req_id); shared_mutex mutex_quickmatching; std::map pending_quickmatching; diff --git a/rpcs3/Emu/NP/np_notifications.cpp b/rpcs3/Emu/NP/np_notifications.cpp index 3634ad6cf9..e6b4b547df 100644 --- a/rpcs3/Emu/NP/np_notifications.cpp +++ b/rpcs3/Emu/NP/np_notifications.cpp @@ -348,7 +348,7 @@ namespace np return generic_gui_notification_handler(data, "UserKickedGUI", SCE_NP_MATCHING_EVENT_ROOM_KICKED); } - void gui_epilog(const std::shared_ptr& ctx); + void gui_epilog(const shared_ptr& ctx); void np_handler::notif_quickmatch_complete_gui(std::vector& data) { diff --git a/rpcs3/Emu/NP/np_requests.cpp b/rpcs3/Emu/NP/np_requests.cpp index fd4ae49532..ff124ad15d 100644 --- a/rpcs3/Emu/NP/np_requests.cpp +++ b/rpcs3/Emu/NP/np_requests.cpp @@ -802,7 +802,7 @@ namespace np return true; } - void np_handler::transaction_async_handler(std::unique_lock lock, const std::shared_ptr& trans_ctx, u32 req_id, bool async) + void np_handler::transaction_async_handler(std::unique_lock lock, const shared_ptr& trans_ctx, u32 req_id, bool async) { auto worker_function = [trans_ctx = trans_ctx, req_id, this](std::unique_lock lock) { @@ -842,7 +842,7 @@ namespace np cpu_thread.check_state(); } - void np_handler::get_board_infos(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, vm::ptr boardInfo, bool async) + void np_handler::get_board_infos(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, vm::ptr boardInfo, bool async) { std::unique_lock lock(trans_ctx->mutex); @@ -877,7 +877,7 @@ namespace np return false; } - auto score_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(score_trans); std::lock_guard lock(score_trans->mutex); @@ -892,7 +892,7 @@ namespace np return true; } - void np_handler::record_score(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, vm::cptr scoreComment, const u8* data, u32 data_size, vm::ptr tmpRank, bool async) + void np_handler::record_score(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, vm::cptr scoreComment, const u8* data, u32 data_size, vm::ptr tmpRank, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE); @@ -920,7 +920,7 @@ namespace np return false; } - auto score_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(score_trans); std::lock_guard lock(score_trans->mutex); @@ -961,7 +961,7 @@ namespace np return true; } - void np_handler::record_score_data(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, u32 totalSize, u32 sendSize, const u8* score_data, bool async) + void np_handler::record_score_data(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreValue score, u32 totalSize, u32 sendSize, const u8* score_data, bool async) { std::unique_lock lock(trans_ctx->mutex); @@ -1021,7 +1021,7 @@ namespace np return set_result_and_wake(CELL_OK); } - void np_handler::get_score_data(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const SceNpId& npId, vm::ptr totalSize, u32 recvSize, vm::ptr score_data, bool async) + void np_handler::get_score_data(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const SceNpId& npId, vm::ptr totalSize, u32 recvSize, vm::ptr score_data, bool async) { std::unique_lock lock(trans_ctx->mutex); @@ -1062,7 +1062,7 @@ namespace np return false; } - auto score_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(score_trans); std::lock_guard lock(score_trans->mutex); @@ -1098,7 +1098,7 @@ namespace np return score_trans->set_result_and_wake(not_an_error(to_copy)); } - void np_handler::get_score_range(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreRankNumber startSerialRank, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) + void np_handler::get_score_range(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, SceNpScoreRankNumber startSerialRank, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE); @@ -1152,7 +1152,7 @@ namespace np return false; } - auto score_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto score_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(score_trans); std::lock_guard lock(score_trans->mutex); @@ -1280,7 +1280,7 @@ namespace np return handle_GetScoreResponse(req_id, reply_data); } - void np_handler::get_score_friend(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) + void np_handler::get_score_friend(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, bool include_self, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE); @@ -1309,7 +1309,7 @@ namespace np return handle_GetScoreResponse(req_id, reply_data); } - void np_handler::get_score_npid(std::shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const std::vector>& npid_vec, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) + void np_handler::get_score_npid(shared_ptr& trans_ctx, SceNpScoreBoardId boardId, const std::vector>& npid_vec, vm::ptr rankArray, u32 rankArraySize, vm::ptr commentArray, [[maybe_unused]] u32 commentArraySize, vm::ptr infoArray, u32 infoArraySize, u32 arrayNum, vm::ptr lastSortDate, vm::ptr totalRecord, bool async, bool deprecated) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE); @@ -1380,7 +1380,7 @@ namespace np return false; } - auto tus_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); @@ -1448,7 +1448,7 @@ namespace np return false; } - auto tus_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); @@ -1506,7 +1506,7 @@ namespace np return false; } - auto tus_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); @@ -1568,7 +1568,7 @@ namespace np return true; } - void np_handler::tus_set_multislot_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::cptr variableArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_set_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::cptr variableArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1582,7 +1582,7 @@ namespace np return handle_tus_no_data(req_id, reply_data); } - void np_handler::tus_get_multislot_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_get_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1601,7 +1601,7 @@ namespace np return handle_TusVarResponse(req_id, reply_data); } - void np_handler::tus_get_multiuser_variable(std::shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_get_multiuser_variable(shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr variableArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1620,7 +1620,7 @@ namespace np return handle_TusVarResponse(req_id, reply_data); } - void np_handler::tus_get_friends_variable(std::shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr variableArray,s32 arrayNum, bool async) + void np_handler::tus_get_friends_variable(shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr variableArray,s32 arrayNum, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1639,7 +1639,7 @@ namespace np return handle_TusVarResponse(req_id, reply_data); } - void np_handler::tus_add_and_get_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s64 inVariable, vm::ptr outVariable, vm::ptr option, bool vuser, bool async) + void np_handler::tus_add_and_get_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s64 inVariable, vm::ptr outVariable, vm::ptr option, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1657,7 +1657,7 @@ namespace np return handle_TusVariable(req_id, reply_data); } - void np_handler::tus_try_and_set_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s32 opeType, s64 variable, vm::ptr resultVariable, vm::ptr option, bool vuser, bool async) + void np_handler::tus_try_and_set_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, s32 opeType, s64 variable, vm::ptr resultVariable, vm::ptr option, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1675,7 +1675,7 @@ namespace np return handle_TusVariable(req_id, reply_data); } - void np_handler::tus_delete_multislot_variable(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_delete_multislot_variable(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1689,7 +1689,7 @@ namespace np return handle_tus_no_data(req_id, reply_data); } - void np_handler::tus_set_data(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr data, vm::cptr info, vm::ptr option, bool vuser, bool async) + void np_handler::tus_set_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, u32 totalSize, u32 sendSize, vm::cptr data, vm::cptr info, vm::ptr option, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); @@ -1723,7 +1723,7 @@ namespace np return handle_tus_no_data(req_id, reply_data); } - void np_handler::tus_get_data(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, vm::ptr dataStatus, vm::ptr data, u32 recvSize, bool vuser, bool async) + void np_handler::tus_get_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, SceNpTusSlotId slotId, vm::ptr dataStatus, vm::ptr data, u32 recvSize, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); @@ -1762,7 +1762,7 @@ namespace np return false; } - auto tus_trans = std::dynamic_pointer_cast(::at32(async_transactions, req_id)); + auto tus_trans = idm::get_unlocked(::at32(async_transactions, req_id)->idm_id); ensure(tus_trans); std::lock_guard lock(tus_trans->mutex); @@ -1835,7 +1835,7 @@ namespace np return true; } - void np_handler::tus_get_multislot_data_status(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_get_multislot_data_status(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1854,7 +1854,7 @@ namespace np return handle_TusDataStatusResponse(req_id, reply_data); } - void np_handler::tus_get_multiuser_data_status(std::shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_get_multiuser_data_status(shared_ptr& trans_ctx, std::vector targetNpIdArray, SceNpTusSlotId slotId, vm::ptr statusArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1873,7 +1873,7 @@ namespace np return handle_TusDataStatusResponse(req_id, reply_data); } - void np_handler::tus_get_friends_data_status(std::shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr statusArray, s32 arrayNum, bool async) + void np_handler::tus_get_friends_data_status(shared_ptr& trans_ctx, SceNpTusSlotId slotId, s32 includeSelf, s32 sortType, vm::ptr statusArray, s32 arrayNum, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); @@ -1892,7 +1892,7 @@ namespace np return handle_TusDataStatusResponse(req_id, reply_data); } - void np_handler::tus_delete_multislot_data(std::shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async) + void np_handler::tus_delete_multislot_data(shared_ptr& trans_ctx, const SceNpOnlineId& targetNpId, vm::cptr slotIdArray, s32 arrayNum, bool vuser, bool async) { std::unique_lock lock(trans_ctx->mutex); const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS); diff --git a/rpcs3/Emu/NP/np_requests_gui.cpp b/rpcs3/Emu/NP/np_requests_gui.cpp index ed099bc6d6..f46307b384 100644 --- a/rpcs3/Emu/NP/np_requests_gui.cpp +++ b/rpcs3/Emu/NP/np_requests_gui.cpp @@ -14,7 +14,7 @@ LOG_CHANNEL(rpcn_log, "rpcn"); namespace np { - std::pair> gui_prelude(u32 ctx_id, vm::ptr handler, vm::ptr arg) + std::pair> gui_prelude(u32 ctx_id, vm::ptr handler, vm::ptr arg) { auto ctx = get_matching_context(ctx_id); @@ -33,7 +33,7 @@ namespace np return {CELL_OK, ctx}; } - void gui_epilog(const std::shared_ptr& ctx) + void gui_epilog(const shared_ptr& ctx) { ensure(ctx->busy.compare_and_swap_test(1, 0), "Matching context wasn't busy in gui_epilog"); ctx->queue_gui_callback(SCE_NP_MATCHING_GUI_EVENT_COMMON_UNLOAD, 0); @@ -662,7 +662,7 @@ namespace np if (ctx->wakey == 0) { // Verify that the context is still valid - if (!idm::check(ctx->ctx_id)) + if (!idm::check_unlocked(ctx->ctx_id)) return; rpcn_log.notice("QuickMatch timeout"); diff --git a/rpcs3/Emu/NP/rpcn_client.cpp b/rpcs3/Emu/NP/rpcn_client.cpp index 245ef2c96c..dc46881b22 100644 --- a/rpcs3/Emu/NP/rpcn_client.cpp +++ b/rpcs3/Emu/NP/rpcn_client.cpp @@ -2775,7 +2775,7 @@ namespace rpcn { std::lock_guard lock(mutex_messages); const u64 msg_id = message_counter++; - auto id_and_msg = std::make_shared>(std::make_pair(std::move(sender), std::move(mdata))); + auto id_and_msg = stx::make_shared>(std::make_pair(std::move(sender), std::move(mdata))); messages.emplace(msg_id, id_and_msg); new_messages.push_back(msg_id); active_messages.insert(msg_id); @@ -2791,7 +2791,7 @@ namespace rpcn } } - std::optional>> rpcn_client::get_message(u64 id) + std::optional>> rpcn_client::get_message(u64 id) { { std::lock_guard lock(mutex_messages); @@ -2803,9 +2803,9 @@ namespace rpcn } } - std::vector>>> rpcn_client::get_messages_and_register_cb(SceNpBasicMessageMainType type_filter, bool include_bootable, message_cb_func cb_func, void* cb_param) + std::vector>>> rpcn_client::get_messages_and_register_cb(SceNpBasicMessageMainType type_filter, bool include_bootable, message_cb_func cb_func, void* cb_param) { - std::vector>>> vec_messages; + std::vector>>> vec_messages; { std::lock_guard lock(mutex_messages); for (auto id : active_messages) diff --git a/rpcs3/Emu/NP/rpcn_client.h b/rpcs3/Emu/NP/rpcn_client.h index 4f772f04c4..fb8921076a 100644 --- a/rpcs3/Emu/NP/rpcn_client.h +++ b/rpcs3/Emu/NP/rpcn_client.h @@ -331,7 +331,7 @@ namespace rpcn }; using friend_cb_func = void (*)(void* param, NotificationType ntype, const std::string& username, bool status); - using message_cb_func = void (*)(void* param, const std::shared_ptr> new_msg, u64 msg_id); + using message_cb_func = void (*)(void* param, const shared_ptr> new_msg, u64 msg_id); struct friend_online_data { @@ -463,8 +463,8 @@ namespace rpcn std::map get_presence_states(); std::vector get_new_messages(); - std::optional>> get_message(u64 id); - std::vector>>> get_messages_and_register_cb(SceNpBasicMessageMainType type, bool include_bootable, message_cb_func cb_func, void* cb_param); + std::optional>> get_message(u64 id); + std::vector>>> get_messages_and_register_cb(SceNpBasicMessageMainType type, bool include_bootable, message_cb_func cb_func, void* cb_param); void remove_message_cb(message_cb_func cb_func, void* cb_param); void mark_message_used(u64 id); @@ -595,7 +595,7 @@ namespace rpcn }; shared_mutex mutex_messages; std::set message_cbs; - std::unordered_map>> messages; // msg id / (sender / message) + std::unordered_map>> messages; // msg id / (sender / message) std::set active_messages; // msg id of messages that have not been discarded std::vector new_messages; // list of msg_id used to inform np_handler of new messages u64 message_counter = 3; // id counter diff --git a/rpcs3/Emu/RSX/Common/texture_cache_utils.h b/rpcs3/Emu/RSX/Common/texture_cache_utils.h index 79ad1b610e..d01660775e 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache_utils.h +++ b/rpcs3/Emu/RSX/Common/texture_cache_utils.h @@ -5,6 +5,7 @@ #include "TextureUtils.h" #include "Emu/Memory/vm.h" +#include "Emu/RSX/Host/MM.h" #include "util/vm.hpp" #include @@ -29,8 +30,7 @@ namespace rsx { ensure(range.is_page_range()); - //rsx_log.error("memory_protect(0x%x, 0x%x, %x)", static_cast(range.start), static_cast(range.length()), static_cast(prot)); - utils::memory_protect(vm::base(range.start), range.length(), prot); + rsx::mm_protect(vm::base(range.start), range.length(), prot); #ifdef TEXTURE_CACHE_DEBUG tex_cache_checker.set_protection(range, prot); diff --git a/rpcs3/Emu/RSX/GL/GLCompute.h b/rpcs3/Emu/RSX/GL/GLCompute.h index 23752997af..54458c1f1c 100644 --- a/rpcs3/Emu/RSX/GL/GLCompute.h +++ b/rpcs3/Emu/RSX/GL/GLCompute.h @@ -381,7 +381,7 @@ namespace gl template T* get_compute_task() { - u32 index = id_manager::typeinfo::get_index(); + u32 index = stx::typeindex(); auto &e = g_compute_tasks[index]; if (!e) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index cc17333dde..c785ddc879 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -7,6 +7,7 @@ #include "Emu/Memory/vm_locking.h" #include "Emu/RSX/rsx_methods.h" +#include "Emu/RSX/Host/MM.h" #include "Emu/RSX/Host/RSXDMAWriter.h" #include "Emu/RSX/NV47/HW/context_accessors.define.h" @@ -1082,6 +1083,8 @@ void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou bool GLGSRender::on_access_violation(u32 address, bool is_writing) { + rsx::mm_flush(address); + const bool can_flush = is_current_thread(); const rsx::invalidation_cause cause = is_writing ? (can_flush ? rsx::invalidation_cause::write : rsx::invalidation_cause::deferred_write) diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index 1ab07b3161..92f76160a8 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -112,7 +112,7 @@ namespace gl template T* get_overlay_pass() { - u32 index = id_manager::typeinfo::get_index(); + u32 index = stx::typeindex(); auto &e = g_overlay_passes[index]; if (!e) diff --git a/rpcs3/Emu/RSX/Host/MM.cpp b/rpcs3/Emu/RSX/Host/MM.cpp new file mode 100644 index 0000000000..cf21b6e046 --- /dev/null +++ b/rpcs3/Emu/RSX/Host/MM.cpp @@ -0,0 +1,110 @@ +#include "stdafx.h" +#include "MM.h" +#include +#include + +#include +#include +#include +#include +#include + +namespace rsx +{ + rsx::simple_array g_deferred_mprotect_queue; + shared_mutex g_mprotect_queue_lock; + + void mm_flush_mprotect_queue_internal() + { + for (const auto& block : g_deferred_mprotect_queue) + { + utils::memory_protect(reinterpret_cast(block.start), block.length, block.prot); + } + + g_deferred_mprotect_queue.clear(); + } + + void mm_defer_mprotect_internal(u64 start, u64 length, utils::protection prot) + { + // We could stack and merge requests here, but that is more trouble than it is truly worth. + // A fresh call to memory_protect only takes a few nanoseconds of setup overhead, it is not worth the risk of hanging because of conflicts. + g_deferred_mprotect_queue.push_back({ start, length, prot }); + } + + void mm_protect(void* ptr, u64 length, utils::protection prot) + { + if (g_cfg.video.disable_async_host_memory_manager) + { + utils::memory_protect(ptr, length, prot); + return; + } + + // Naive merge. Eventually it makes more sense to do conflict resolution, but it's not as important. + const auto start = reinterpret_cast(ptr); + const auto end = start + length; + + std::lock_guard lock(g_mprotect_queue_lock); + + if (prot == utils::protection::rw || prot == utils::protection::wx) + { + // Basically an unlock op. Flush if any overlap is detected + for (const auto& block : g_deferred_mprotect_queue) + { + if (block.overlaps(start, end)) + { + mm_flush_mprotect_queue_internal(); + break; + } + } + + utils::memory_protect(ptr, length, prot); + return; + } + + // No, Ro, etc. + mm_defer_mprotect_internal(start, length, prot); + } + + void mm_flush() + { + std::lock_guard lock(g_mprotect_queue_lock); + mm_flush_mprotect_queue_internal(); + } + + void mm_flush(u32 vm_address) + { + std::lock_guard lock(g_mprotect_queue_lock); + if (g_deferred_mprotect_queue.empty()) + { + return; + } + + const auto addr = reinterpret_cast(vm::base(vm_address)); + for (const auto& block : g_deferred_mprotect_queue) + { + if (block.overlaps(addr)) + { + mm_flush_mprotect_queue_internal(); + return; + } + } + } + + void mm_flush_lazy() + { + if (!g_cfg.video.multithreaded_rsx) + { + mm_flush(); + return; + } + + std::lock_guard lock(g_mprotect_queue_lock); + if (g_deferred_mprotect_queue.empty()) + { + return; + } + + auto& rsxdma = g_fxo->get(); + rsxdma.backend_ctrl(mm_backend_ctrl::cmd_mm_flush, nullptr); + } +} diff --git a/rpcs3/Emu/RSX/Host/MM.h b/rpcs3/Emu/RSX/Host/MM.h new file mode 100644 index 0000000000..e9415a685f --- /dev/null +++ b/rpcs3/Emu/RSX/Host/MM.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace rsx +{ + struct MM_block + { + u64 start; + u64 length; + utils::protection prot; + + inline bool overlaps(u64 start, u64 end) const + { + // [Start, End] is not a proper closed range, there is an off-by-one by design. + // FIXME: Use address_range64 + const u64 this_end = this->start + this->length; + return (this->start < end && start < this_end); + } + + inline bool overlaps(u64 addr) const + { + // [Start, End] is not a proper closed range, there is an off-by-one by design. + // FIXME: Use address_range64 + const u64 this_end = this->start + this->length; + return (addr >= start && addr < this_end); + } + }; + + enum mm_backend_ctrl : u32 + { + cmd_mm_flush = 0x81000000, + }; + + void mm_protect(void* start, u64 length, utils::protection prot); + void mm_flush_lazy(); + void mm_flush(u32 vm_address); + void mm_flush(); +} diff --git a/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp b/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp index fe6dc21ba5..9c153b2056 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp @@ -7,6 +7,9 @@ namespace rsx { + void mm_flush_lazy(); + void mm_flush(); + namespace util { template @@ -24,17 +27,24 @@ namespace rsx return; } - if constexpr (FlushDMA) + if constexpr (FlushDMA || FlushPipe) { - // If the backend handled the request, this call will basically be a NOP - g_fxo->get().sync(); - } + // Release op must be acoompanied by MM flush. + // FlushPipe implicitly does a MM flush but FlushDMA does not. Trigger the flush here + rsx::mm_flush(); - if constexpr (FlushPipe) - { - // Manually flush the pipeline. - // It is possible to stream report writes using the host GPU, but that generates too much submit traffic. - RSX(ctx)->sync(); + if constexpr (FlushDMA) + { + // If the backend handled the request, this call will basically be a NOP + g_fxo->get().sync(); + } + + if constexpr (FlushPipe) + { + // Manually flush the pipeline. + // It is possible to stream report writes using the host GPU, but that generates too much submit traffic. + RSX(ctx)->sync(); + } } if (handled) diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp index 50d690d56a..fe82f81253 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp @@ -83,6 +83,8 @@ namespace rsx add_dropdown(&g_cfg.io.pad_mode, localized_string_id::HOME_MENU_SETTINGS_INPUT_PAD_MODE); add_unsigned_slider(&g_cfg.io.pad_sleep, localized_string_id::HOME_MENU_SETTINGS_INPUT_PAD_SLEEP, " µs", 100); + add_unsigned_slider(&g_cfg.io.fake_move_rotation_cone_h, localized_string_id::HOME_MENU_SETTINGS_INPUT_FAKE_MOVE_ROTATION_CONE_H, "°", 1); + add_unsigned_slider(&g_cfg.io.fake_move_rotation_cone_v, localized_string_id::HOME_MENU_SETTINGS_INPUT_FAKE_MOVE_ROTATION_CONE_V, "°", 1); apply_layout(); } diff --git a/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.cpp b/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.cpp index d5a2e58f8a..12ccdc0b27 100644 --- a/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.cpp +++ b/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.cpp @@ -9,7 +9,7 @@ namespace rsx { namespace overlays { - void recvmessage_callback(void* param, std::shared_ptr> new_msg, u64 msg_id) + void recvmessage_callback(void* param, shared_ptr> new_msg, u64 msg_id) { auto* dlg = static_cast(param); dlg->callback_handler(std::move(new_msg), msg_id); @@ -319,7 +319,7 @@ namespace rsx return result; } - void recvmessage_dialog::callback_handler(std::shared_ptr> new_msg, u64 msg_id) + void recvmessage_dialog::callback_handler(shared_ptr> new_msg, u64 msg_id) { ensure(new_msg); diff --git a/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.h b/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.h index 8d2ea4500f..0c910e1311 100644 --- a/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.h +++ b/rpcs3/Emu/RSX/Overlays/Network/overlay_recvmessage_dialog.h @@ -36,7 +36,7 @@ namespace rsx compiled_resource get_compiled() override; error_code Exec(SceNpBasicMessageMainType type, SceNpBasicMessageRecvOptions options, SceNpBasicMessageRecvAction& recv_result, u64& chosen_msg_id) override; - void callback_handler(const std::shared_ptr> new_msg, u64 msg_id) override; + void callback_handler(const shared_ptr> new_msg, u64 msg_id) override; }; } } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_manager.h b/rpcs3/Emu/RSX/Overlays/overlay_manager.h index 18359b7cec..d7a10988c1 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_manager.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_manager.h @@ -52,7 +52,7 @@ namespace rsx std::lock_guard lock(m_list_mutex); entry->uid = m_uid_ctr.fetch_add(1); - entry->type_index = id_manager::typeinfo::get_index(); + entry->type_index = stx::typeindex(); if (remove_existing) { @@ -88,7 +88,7 @@ namespace rsx template void remove() { - const auto type_id = id_manager::typeinfo::get_index(); + const auto type_id = stx::typeindex(); if (m_list_mutex.try_lock()) { remove_type(type_id); @@ -138,7 +138,7 @@ namespace rsx { reader_lock lock(m_list_mutex); - const auto type_id = id_manager::typeinfo::get_index(); + const auto type_id = stx::typeindex(); for (const auto& iface : m_iface_list) { if (iface->type_index == type_id) diff --git a/rpcs3/Emu/RSX/RSXTexture.h b/rpcs3/Emu/RSX/RSXTexture.h index a7d94db658..5517a39e3f 100644 --- a/rpcs3/Emu/RSX/RSXTexture.h +++ b/rpcs3/Emu/RSX/RSXTexture.h @@ -142,4 +142,7 @@ namespace rsx rsx::texture_dimension_extended get_extended_texture_dimension() const; u16 get_exact_mipmap_count() const; }; + + template + concept Texture = std::is_same_v || std::is_same_v; } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f266a25587..5e10e67e59 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -9,6 +9,7 @@ #include "Common/time.hpp" #include "Core/RSXReservationLock.hpp" #include "Core/RSXEngLock.hpp" +#include "Host/MM.h" #include "Host/RSXDMAWriter.h" #include "NV47/HW/context.h" #include "Program/GLSLCommon.h" @@ -2603,8 +2604,14 @@ namespace rsx rsx_log.error("Depth texture bound to pipeline with unexpected format 0x%X", format); } } - else if (!backend_config.supports_hw_renormalization) + else if (!backend_config.supports_hw_renormalization /* && + tex.min_filter() == rsx::texture_minify_filter::nearest && + tex.mag_filter() == rsx::texture_magnify_filter::nearest*/) { + // FIXME: This check should only apply to point-sampled textures. However, it severely regresses some games (id tech 5). + // This is because even when filtering is active, the error from the PS3 texture expansion still applies. + // A proper fix is to expand these formats into BGRA8 when high texture precision is required. That requires different GUI settings and inflation shaders, so it will be handled separately. + switch (format) { case CELL_GCM_TEXTURE_A1R5G5B5: @@ -3175,6 +3182,8 @@ namespace rsx { m_eng_interrupt_mask.clear(rsx::pipe_flush_interrupt); + mm_flush(); + if (zcull_ctrl->has_pending()) { zcull_ctrl->sync(this); @@ -3627,10 +3636,25 @@ namespace rsx on_invalidate_memory_range(m_invalidated_memory_range, rsx::invalidation_cause::read); } + // Host sync + rsx::mm_flush(); + on_invalidate_memory_range(m_invalidated_memory_range, rsx::invalidation_cause::unmap); m_invalidated_memory_range.invalidate(); } + void thread::renderctl(u32 request_code, void* /*args*/) + { + switch (request_code) + { + case rsx::mm_backend_ctrl::cmd_mm_flush: + rsx::mm_flush(); + break; + default: + fmt::throw_exception("Unknown backend request: 0x%x", request_code); + } + } + //Pause/cont wrappers for FIFO ctrl. Never call this from rsx thread itself! void thread::pause() { @@ -3696,6 +3720,9 @@ namespace rsx { bool pause_emulator = false; + // MM sync. This is a pre-emptive operation, so we can use a deferred request. + rsx::mm_flush_lazy(); + // Marks the end of a frame scope GPU-side if (g_user_asked_for_frame_capture.exchange(false) && !capture_current_frame) { diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index b7bf5ff83e..e861a96e25 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -269,7 +269,7 @@ namespace rsx const backend_configuration& get_backend_config() const { return backend_config; } public: - std::shared_ptr> intr_thread; + shared_ptr> intr_thread; // I hate this flag, but until hle is closer to lle, its needed bool isHLE{ false }; @@ -404,7 +404,7 @@ namespace rsx virtual void notify_tile_unbound(u32 /*tile*/) {} // control - virtual void renderctl(u32 /*request_code*/, void* /*args*/) {} + virtual void renderctl(u32 request_code, void* args); // zcull void notify_zcull_info_changed(); diff --git a/rpcs3/Emu/RSX/VK/VKCommandStream.h b/rpcs3/Emu/RSX/VK/VKCommandStream.h index e559a688f4..4ee4d00e19 100644 --- a/rpcs3/Emu/RSX/VK/VKCommandStream.h +++ b/rpcs3/Emu/RSX/VK/VKCommandStream.h @@ -9,7 +9,7 @@ namespace vk enum // callback commands { rctrl_queue_submit = 0x80000000, - rctrl_run_gc = 0x80000001 + rctrl_run_gc = 0x80000001, }; struct submit_packet diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index cc0246f3e2..499976b660 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -96,6 +96,7 @@ namespace vk optimal_group_size = 64; break; case vk::driver_vendor::MVK: + case vk::driver_vendor::HONEYKRISP: unroll_loops = true; optimal_kernel_size = 1; optimal_group_size = 256; diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index e3cce8100a..faadecfc18 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -668,7 +668,7 @@ namespace vk template T* get_compute_task() { - u32 index = id_manager::typeinfo::get_index(); + u32 index = stx::typeindex(); auto &e = g_compute_tasks[index]; if (!e) diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index ad0bca997f..ef268cfda3 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -244,6 +244,13 @@ void VKGSRender::load_texture_env() return false; }; + auto get_border_color = [&](const rsx::Texture auto& tex) + { + return m_device->get_custom_border_color_support().require_border_color_remap + ? tex.remapped_border_color() + : rsx::decode_border_color(tex.border_color()); + }; + std::lock_guard lock(m_sampler_mutex); for (u32 textures_ref = current_fp_metadata.referenced_textures_mask, i = 0; textures_ref; textures_ref >>= 1, ++i) @@ -304,10 +311,10 @@ void VKGSRender::load_texture_env() const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t()); const auto wrap_r = vk::vk_wrap_mode(tex.wrap_r()); - // NOTE: In vulkan, the border color bypasses the swizzling defined in the image view. - // It is a direct texel replacement and must be remapped before attaching to the sampler. + // NOTE: In vulkan, the border color can bypass the sample swizzle stage. + // Check the device properties to determine whether to pre-swizzle the colors or not. const auto border_color = rsx::is_border_clamped_texture(tex) - ? vk::border_color_t(tex.remapped_border_color()) + ? vk::border_color_t(get_border_color(tex)) : vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); // Check if non-point filtering can even be used on this format @@ -449,10 +456,10 @@ void VKGSRender::load_texture_env() const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s()); const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t()); - // NOTE: In vulkan, the border color bypasses the swizzling defined in the image view. - // It is a direct texel replacement and must be remapped before attaching to the sampler. + // NOTE: In vulkan, the border color can bypass the sample swizzle stage. + // Check the device properties to determine whether to pre-swizzle the colors or not. const auto border_color = is_border_clamped_texture(tex) - ? vk::border_color_t(tex.remapped_border_color()) + ? vk::border_color_t(get_border_color(tex)) : vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); if (vs_sampler_handles[i]) @@ -790,6 +797,16 @@ void VKGSRender::emit_geometry(u32 sub_index) } } + // Before starting a query, we need to match RP scope (VK_1_0 rules). + // We always want our queries to start outside a renderpass whenever possible. + // We ignore this for performance reasons whenever possible of course and only do this for sensitive drivers. + if (vk::use_strict_query_scopes() && + vk::is_renderpass_open(*m_current_command_buffer)) + { + vk::end_renderpass(*m_current_command_buffer); + emergency_query_cleanup(m_current_command_buffer); + } + // Begin query m_occlusion_query_manager->begin_query(*m_current_command_buffer, occlusion_id); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 371a777e94..5de8f62d92 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -15,6 +15,7 @@ #include "vkutils/scratch.h" #include "Emu/RSX/rsx_methods.h" +#include "Emu/RSX/Host/MM.h" #include "Emu/RSX/Host/RSXDMAWriter.h" #include "Emu/RSX/NV47/HW/context_accessors.define.h" #include "Emu/Memory/vm_locking.h" @@ -1010,6 +1011,8 @@ VKGSRender::~VKGSRender() bool VKGSRender::on_access_violation(u32 address, bool is_writing) { + rsx::mm_flush(address); + vk::texture_cache::thrashed_set result; { const rsx::invalidation_cause cause = is_writing ? rsx::invalidation_cause::deferred_write : rsx::invalidation_cause::deferred_read; @@ -2460,6 +2463,9 @@ void VKGSRender::close_and_submit_command_buffer(vk::fence* pFence, VkSemaphore { ensure(!m_queue_status.test_and_set(flush_queue_state::flushing)); + // Host MM sync before executing anything on the GPU + rsx::mm_flush(); + // Workaround for deadlock occuring during RSX offloader fault // TODO: Restructure command submission infrastructure to avoid this condition const bool sync_success = g_fxo->get().sync(); @@ -2824,7 +2830,7 @@ void VKGSRender::renderctl(u32 request_code, void* args) break; } default: - fmt::throw_exception("Unhandled request code 0x%x", request_code); + rsx::thread::renderctl(request_code, args); } } @@ -2871,6 +2877,14 @@ void VKGSRender::end_occlusion_query(rsx::reports::occlusion_query_info* query) // NOTE: flushing the queue is very expensive, do not flush just because query stopped if (m_current_command_buffer->flags & vk::command_buffer::cb_has_open_query) { + // VK_1_0 rules dictate that query must match subpass behavior on begin/end query. + // This is slow, so only do this for drivers that care. + if (vk::use_strict_query_scopes() && + vk::is_renderpass_open(*m_current_command_buffer)) + { + vk::end_renderpass(*m_current_command_buffer); + } + // End query auto open_query = m_occlusion_map[m_active_query_info->driver_handle].indices.back(); m_occlusion_query_manager->end_query(*m_current_command_buffer, open_query); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index ada6c13f2c..7789661ef2 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -31,6 +31,8 @@ namespace vk bool g_drv_sanitize_fp_values = false; bool g_drv_disable_fence_reset = false; bool g_drv_emulate_cond_render = false; + bool g_drv_strict_query_scopes = false; + bool g_drv_force_reuse_query_pools = false; u64 g_num_processed_frames = 0; u64 g_num_total_frames = 0; @@ -139,6 +141,9 @@ namespace vk rsx_log.error("Dozen is currently unsupported. How did you even get this to run outside windows?"); #endif break; + case driver_vendor::HONEYKRISP: + // Needs more testing + break; default: rsx_log.warning("Unsupported device: %s", gpu_name); } @@ -228,6 +233,16 @@ namespace vk return g_drv_emulate_cond_render; } + bool use_strict_query_scopes() + { + return g_drv_strict_query_scopes; + } + + bool force_reuse_query_pools() + { + return g_drv_force_reuse_query_pools; + } + void raise_status_interrupt(runtime_state status) { g_runtime_state |= status; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 0db4c7153f..281aab5f1b 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -62,6 +62,8 @@ namespace vk bool sanitize_fp_values(); bool fence_reset_disabled(); bool emulate_conditional_rendering(); + bool use_strict_query_scopes(); + bool force_reuse_query_pools(); VkFlags get_heap_compatible_buffer_types(); // Sync helpers around vkQueueSubmit diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index edce672de8..d1288fb80a 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -237,7 +237,7 @@ namespace vk template T* get_overlay_pass() { - u32 index = id_manager::typeinfo::get_index(); + u32 index = stx::typeindex(); auto& e = g_overlay_passes[index]; if (!e) diff --git a/rpcs3/Emu/RSX/VK/VKQueryPool.cpp b/rpcs3/Emu/RSX/VK/VKQueryPool.cpp index 449d8d13b9..3fd80a8d67 100644 --- a/rpcs3/Emu/RSX/VK/VKQueryPool.cpp +++ b/rpcs3/Emu/RSX/VK/VKQueryPool.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "VKHelpers.h" #include "VKQueryPool.h" #include "VKRenderPass.h" #include "VKResourceManager.h" @@ -74,13 +75,20 @@ namespace vk { ensure(!m_current_query_pool); - const u32 count = ::size32(query_slot_status); - m_current_query_pool = std::make_unique(*owner, query_type, count); + if (m_query_pool_cache.size() > 0) + { + m_current_query_pool = std::move(m_query_pool_cache.front()); + m_query_pool_cache.pop_front(); + } + else + { + const u32 count = ::size32(query_slot_status); + m_current_query_pool = std::make_unique(*owner, query_type, count); + } // From spec: "After query pool creation, each query must be reset before it is used." - vkCmdResetQueryPool(cmd, *m_current_query_pool.get(), 0, count); - - m_pool_lifetime_counter = count; + vkCmdResetQueryPool(cmd, *m_current_query_pool.get(), 0, m_current_query_pool->size()); + m_pool_lifetime_counter = m_current_query_pool->size(); } void query_pool_manager::reallocate_pool(vk::command_buffer& cmd) @@ -89,7 +97,8 @@ namespace vk { if (!m_current_query_pool->has_refs()) { - vk::get_resource_manager()->dispose(m_current_query_pool); + auto ref = std::make_unique(this, m_current_query_pool); + vk::get_resource_manager()->dispose(ref); } else { @@ -112,7 +121,8 @@ namespace vk { if (!(*It)->has_refs()) { - vk::get_resource_manager()->dispose(*It); + auto ref = std::make_unique(this, *It); + vk::get_resource_manager()->dispose(ref); It = m_consumed_pools.erase(It); } else @@ -219,4 +229,21 @@ namespace vk return ~0u; } + + void query_pool_manager::on_query_pool_released(std::unique_ptr& pool) + { + if (!vk::force_reuse_query_pools()) + { + // Delete and let the driver recreate a new pool each time. + pool.reset(); + return; + } + + m_query_pool_cache.emplace_back(std::move(pool)); + } + + query_pool_manager::query_pool_ref::~query_pool_ref() + { + m_pool_man->on_query_pool_released(m_object); + } } diff --git a/rpcs3/Emu/RSX/VK/VKQueryPool.h b/rpcs3/Emu/RSX/VK/VKQueryPool.h index 6aa1e19978..009afca379 100644 --- a/rpcs3/Emu/RSX/VK/VKQueryPool.h +++ b/rpcs3/Emu/RSX/VK/VKQueryPool.h @@ -19,7 +19,22 @@ namespace vk u32 data; }; + class query_pool_ref + { + std::unique_ptr m_object; + query_pool_manager* m_pool_man; + + public: + query_pool_ref(query_pool_manager* pool_man, std::unique_ptr& pool) + : m_object(std::move(pool)) + , m_pool_man(pool_man) + {} + + ~query_pool_ref(); + }; + std::vector> m_consumed_pools; + std::deque> m_query_pool_cache; std::unique_ptr m_current_query_pool; std::deque m_available_slots; u32 m_pool_lifetime_counter = 0; @@ -52,6 +67,8 @@ namespace vk u32 allocate_query(vk::command_buffer& cmd); void free_query(vk::command_buffer&/*cmd*/, u32 index); + void on_query_pool_released(std::unique_ptr& pool); + template class _List> void free_queries(vk::command_buffer& cmd, _List& list) { diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index fa9d7d06ef..4bee28227a 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -189,6 +189,7 @@ namespace vk case driver_vendor::DOZEN: case driver_vendor::LAVAPIPE: case driver_vendor::V3DV: + case driver_vendor::HONEYKRISP: break; } diff --git a/rpcs3/Emu/RSX/VK/VulkanAPI.h b/rpcs3/Emu/RSX/VK/VulkanAPI.h index f6383c78c1..0cb493045c 100644 --- a/rpcs3/Emu/RSX/VK/VulkanAPI.h +++ b/rpcs3/Emu/RSX/VK/VulkanAPI.h @@ -21,39 +21,6 @@ #include -#ifndef VK_EXT_attachment_feedback_loop_layout - -#define VK_EXT_attachment_feedback_loop_layout 1 -#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout" -#define VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT static_cast(1000339000) -#define VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT 0x00080000 -#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT static_cast(1000339000) - -typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 attachmentFeedbackLoopLayout; -} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT; - -#endif - -#ifndef VK_KHR_fragment_shader_barycentric - -#define VK_KHR_fragment_shader_barycentric 1 -#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 -#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric" -#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR static_cast(1000203000) - -typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR { - VkStructureType sType; - void* pNext; - VkBool32 fragmentShaderBarycentric; -} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR; - -typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR { - VkStructureType sType; - void* pNext; - VkBool32 triStripVertexOrderIndependentOfProvokingVertex; -} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; - +#if VK_HEADER_VERSION < 287 +constexpr VkDriverId VK_DRIVER_ID_MESA_HONEYKRISP = static_cast(26); #endif diff --git a/rpcs3/Emu/RSX/VK/vkutils/chip_class.cpp b/rpcs3/Emu/RSX/VK/vkutils/chip_class.cpp index 4e877047d1..5bb811d531 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/chip_class.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/chip_class.cpp @@ -103,7 +103,11 @@ namespace vk if (vendor_id == 0x106B) { - return chip_class::MVK_apple; +#ifdef __APPLE__ + return chip_class::APPLE_MVK; +#else + return chip_class::APPLE_HK_generic; // Lazy, but at the moment we don't care about the differences in M1, M2, M3, M4, etc +#endif } if (vendor_id == 0x8086) diff --git a/rpcs3/Emu/RSX/VK/vkutils/chip_class.h b/rpcs3/Emu/RSX/VK/vkutils/chip_class.h index c1dcfcb900..07b087d403 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/chip_class.h +++ b/rpcs3/Emu/RSX/VK/vkutils/chip_class.h @@ -31,7 +31,9 @@ namespace vk _NV_ENUM_MAX_, // Do not insert NV enums beyond this point // APPLE - MVK_apple, + APPLE_HK_generic, + APPLE_MVK, + _APPLE_ENUM_MAX, // Do not insert APPLE enums beyond this point // INTEL INTEL_generic, @@ -51,7 +53,8 @@ namespace vk DOZEN, LAVAPIPE, NVK, - V3DV + V3DV, + HONEYKRISP }; driver_vendor get_driver_vendor(); diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.cpp b/rpcs3/Emu/RSX/VK/vkutils/device.cpp index c3a96ba237..25b2a57d62 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/device.cpp @@ -34,6 +34,8 @@ namespace vk VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT fbo_loops_info{}; VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR shader_barycentric_info{}; VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border_color_info{}; + VkPhysicalDeviceBorderColorSwizzleFeaturesEXT border_color_swizzle_info{}; + VkPhysicalDeviceFaultFeaturesEXT device_fault_info{}; if (device_extensions.is_supported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) { @@ -70,6 +72,20 @@ namespace vk features2.pNext = &custom_border_color_info; } + if (device_extensions.is_supported(VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME)) + { + border_color_swizzle_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT; + border_color_swizzle_info.pNext = features2.pNext; + features2.pNext = &border_color_swizzle_info; + } + + if (device_extensions.is_supported(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) + { + device_fault_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT; + device_fault_info.pNext = features2.pNext; + features2.pNext = &device_fault_info; + } + auto _vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast(vkGetInstanceProcAddr(parent, "vkGetPhysicalDeviceFeatures2KHR")); ensure(_vkGetPhysicalDeviceFeatures2KHR); // "vkGetInstanceProcAddress failed to find entry point!" _vkGetPhysicalDeviceFeatures2KHR(dev, &features2); @@ -78,9 +94,13 @@ namespace vk shader_types_support.allow_float16 = !!shader_support_info.shaderFloat16; shader_types_support.allow_int8 = !!shader_support_info.shaderInt8; - optional_features_support.custom_border_color = !!custom_border_color_info.customBorderColors && !!custom_border_color_info.customBorderColorWithoutFormat; + custom_border_color_support.supported = !!custom_border_color_info.customBorderColors && !!custom_border_color_info.customBorderColorWithoutFormat; + custom_border_color_support.swizzle_extension_supported = border_color_swizzle_info.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT; + custom_border_color_support.require_border_color_remap = !border_color_swizzle_info.borderColorSwizzleFromImage; + optional_features_support.barycentric_coords = !!shader_barycentric_info.fragmentShaderBarycentric; optional_features_support.framebuffer_loops = !!fbo_loops_info.attachmentFeedbackLoopLayout; + optional_features_support.extended_device_fault = !!device_fault_info.deviceFault; features = features2.features; @@ -107,6 +127,13 @@ namespace vk optional_features_support.debug_utils = instance_extensions.is_supported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); optional_features_support.surface_capabilities_2 = instance_extensions.is_supported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + // Post-initialization checks + if (!custom_border_color_support.swizzle_extension_supported) + { + // So far only AMD is known to remap image view and border color together. Mark as not required. + custom_border_color_support.require_border_color_remap = get_driver_vendor() != driver_vendor::AMD; + } } void physical_device::get_physical_device_properties(bool allow_extensions) @@ -270,6 +297,11 @@ namespace vk return driver_vendor::V3DV; } + if (gpu_name.find("Apple") != umax) + { + return driver_vendor::HONEYKRISP; + } + return driver_vendor::unknown; } else @@ -295,6 +327,8 @@ namespace vk return driver_vendor::NVK; case VK_DRIVER_ID_MESA_V3DV: return driver_vendor::V3DV; + case VK_DRIVER_ID_MESA_HONEYKRISP: + return driver_vendor::HONEYKRISP; default: // Mobile? return driver_vendor::unknown; @@ -438,6 +472,11 @@ namespace vk requested_extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); } + if (pgpu->custom_border_color_support) + { + requested_extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); + } + if (pgpu->optional_features_support.conditional_rendering) { requested_extensions.push_back(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME); @@ -480,16 +519,16 @@ namespace vk requested_extensions.push_back(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME); } - if (pgpu->optional_features_support.custom_border_color) - { - requested_extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); - } - if (pgpu->optional_features_support.synchronization_2) { requested_extensions.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME); } + if (pgpu->optional_features_support.extended_device_fault) + { + requested_extensions.push_back(VK_EXT_DEVICE_FAULT_EXTENSION_NAME); + } + enabled_features.robustBufferAccess = VK_TRUE; enabled_features.fullDrawIndexUint32 = VK_TRUE; enabled_features.independentBlend = VK_TRUE; @@ -665,6 +704,16 @@ namespace vk device.pNext = &indexing_features; } + VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border_color_features{}; + if (pgpu->custom_border_color_support) + { + custom_border_color_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; + custom_border_color_features.customBorderColors = VK_TRUE; + custom_border_color_features.customBorderColorWithoutFormat = VK_TRUE; + custom_border_color_features.pNext = const_cast(device.pNext); + device.pNext = &custom_border_color_features; + } + VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT fbo_loop_features{}; if (pgpu->optional_features_support.framebuffer_loops) { @@ -674,16 +723,6 @@ namespace vk device.pNext = &fbo_loop_features; } - VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border_color_features{}; - if (pgpu->optional_features_support.custom_border_color) - { - custom_border_color_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - custom_border_color_features.customBorderColors = VK_TRUE; - custom_border_color_features.customBorderColorWithoutFormat = VK_TRUE; - custom_border_color_features.pNext = const_cast(device.pNext); - device.pNext = &custom_border_color_features; - } - VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2_info{}; if (pgpu->optional_features_support.synchronization_2) { @@ -693,6 +732,16 @@ namespace vk device.pNext = &synchronization2_info; } + VkPhysicalDeviceFaultFeaturesEXT device_fault_info{}; + if (pgpu->optional_features_support.extended_device_fault) + { + device_fault_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT; + device_fault_info.pNext = const_cast(device.pNext); + device_fault_info.deviceFault = VK_TRUE; + device_fault_info.deviceFaultVendorBinary = VK_FALSE; + device_fault_info.pNext = &device_fault_info; + } + if (auto error = vkCreateDevice(*pgpu, &device, nullptr, &dev)) { dump_debug_info(requested_extensions, enabled_features); @@ -736,6 +785,11 @@ namespace vk _vkCmdPipelineBarrier2KHR = reinterpret_cast(vkGetDeviceProcAddr(dev, "vkCmdPipelineBarrier2KHR")); } + if (pgpu->optional_features_support.extended_device_fault) + { + _vkGetDeviceFaultInfoEXT = reinterpret_cast(vkGetDeviceProcAddr(dev, "vkGetDeviceFaultInfoEXT")); + } + memory_map = vk::get_memory_mapping(pdev); m_formats_support = vk::get_optimal_tiling_supported_formats(pdev); m_pipeline_binding_table = vk::get_pipeline_binding_table(pdev); diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.h b/rpcs3/Emu/RSX/VK/vkutils/device.h index 4a9a0fca3d..98f97e6e19 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.h +++ b/rpcs3/Emu/RSX/VK/vkutils/device.h @@ -49,7 +49,16 @@ namespace vk descriptor_indexing_features(bool supported = false) : supported(supported) {} - operator bool() { return supported; } + operator bool() const { return supported; } + }; + + struct custom_border_color_features + { + bool supported = false; + bool swizzle_extension_supported = false; + bool require_border_color_remap = true; // Assume that without the swizzle extension and explicit remap the device just samples border color as replacement. + + operator bool() const { return supported; } }; class physical_device @@ -68,11 +77,12 @@ namespace vk u32 descriptor_max_draw_calls = DESCRIPTOR_MAX_DRAW_CALLS; descriptor_indexing_features descriptor_indexing_support{}; + custom_border_color_features custom_border_color_support{}; + struct { bool barycentric_coords = false; bool conditional_rendering = false; - bool custom_border_color = false; bool debug_utils = false; bool external_memory_host = false; bool framebuffer_loops = false; @@ -81,6 +91,7 @@ namespace vk bool surface_capabilities_2 = false; bool synchronization_2 = false; bool unrestricted_depth_range = false; + bool extended_device_fault = false; } optional_features_support; friend class render_device; @@ -143,6 +154,7 @@ namespace vk PFN_vkCmdSetEvent2KHR _vkCmdSetEvent2KHR = nullptr; PFN_vkCmdWaitEvents2KHR _vkCmdWaitEvents2KHR = nullptr; PFN_vkCmdPipelineBarrier2KHR _vkCmdPipelineBarrier2KHR = nullptr; + PFN_vkGetDeviceFaultInfoEXT _vkGetDeviceFaultInfoEXT = nullptr; public: render_device() = default; @@ -161,6 +173,7 @@ namespace vk const gpu_formats_support& get_formats_support() const { return m_formats_support; } const pipeline_binding_table& get_pipeline_binding_table() const { return m_pipeline_binding_table; } const gpu_shader_types_support& get_shader_types_support() const { return pgpu->shader_types_support; } + const custom_border_color_features& get_custom_border_color_support() const { return pgpu->custom_border_color_support; } bool get_shader_stencil_export_support() const { return pgpu->optional_features_support.shader_stencil_export; } bool get_depth_bounds_support() const { return pgpu->features.depthBounds != VK_FALSE; } @@ -175,8 +188,8 @@ namespace vk bool get_descriptor_indexing_support() const { return pgpu->descriptor_indexing_support; } bool get_framebuffer_loops_support() const { return pgpu->optional_features_support.framebuffer_loops; } bool get_barycoords_support() const { return pgpu->optional_features_support.barycentric_coords; } - bool get_custom_border_color_support() const { return pgpu->optional_features_support.custom_border_color; } bool get_synchronization2_support() const { return pgpu->optional_features_support.synchronization_2; } + bool get_extended_device_fault_support() const { return pgpu->optional_features_support.extended_device_fault; } u64 get_descriptor_update_after_bind_support() const { return pgpu->descriptor_indexing_support.update_after_bind_mask; } u32 get_descriptor_max_draw_calls() const { return pgpu->descriptor_max_draw_calls; } diff --git a/rpcs3/Emu/RSX/VK/vkutils/query_pool.hpp b/rpcs3/Emu/RSX/VK/vkutils/query_pool.hpp index 90d4df9057..3cf0146c0b 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/query_pool.hpp +++ b/rpcs3/Emu/RSX/VK/vkutils/query_pool.hpp @@ -9,17 +9,19 @@ namespace vk { VkQueryPool m_query_pool; VkDevice m_device; + u32 m_size; public: query_pool(VkDevice dev, VkQueryType type, u32 size) : m_query_pool(VK_NULL_HANDLE) , m_device(dev) + , m_size(size) { VkQueryPoolCreateInfo info{}; info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; info.queryType = type; info.queryCount = size; - vkCreateQueryPool(dev, &info, nullptr, &m_query_pool); + CHECK_RESULT(vkCreateQueryPool(dev, &info, nullptr, &m_query_pool)); // Take 'size' references on this object ref_count.release(static_cast(size)); @@ -34,5 +36,10 @@ namespace vk { return m_query_pool; } + + inline u32 size() const + { + return m_size; + } }; } diff --git a/rpcs3/Emu/RSX/VK/vkutils/shared.cpp b/rpcs3/Emu/RSX/VK/vkutils/shared.cpp index 9f2d315305..16bc0066ae 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/shared.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/shared.cpp @@ -1,3 +1,4 @@ +#include "device.h" #include "shared.h" #include "util/logs.hpp" @@ -9,9 +10,110 @@ namespace vk { extern void print_debug_markers(); + std::string retrieve_device_fault_info() + { + if (!g_render_device || !g_render_device->get_extended_device_fault_support()) + { + return "Extended fault info is not available. Extension 'VK_EXT_device_fault' is probably not supported by your driver."; + } + + ensure(g_render_device->_vkGetDeviceFaultInfoEXT); + + VkDeviceFaultCountsEXT fault_counts + { + .sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT + }; + + std::vector address_info; + std::vector vendor_info; + std::vector vendor_binary_data; + std::string fault_description; + +#ifdef _MSC_VER + __try + { +#endif + // Retrieve sizes + g_render_device->_vkGetDeviceFaultInfoEXT(*g_render_device, &fault_counts, nullptr); + + // Resize arrays and fill + address_info.resize(fault_counts.addressInfoCount); + vendor_info.resize(fault_counts.vendorInfoCount); + vendor_binary_data.resize(fault_counts.vendorBinarySize); + + VkDeviceFaultInfoEXT fault_info + { + .sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT, + .pAddressInfos = address_info.data(), + .pVendorInfos = vendor_info.data(), + .pVendorBinaryData = vendor_binary_data.data() + }; + g_render_device->_vkGetDeviceFaultInfoEXT(*g_render_device, &fault_counts, &fault_info); + + fault_description = fault_info.description; +#ifdef _MSC_VER + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + rsx_log.error("Driver crashed retrieving extended crash information. Are you running on an NVIDIA card?"); + return "Extended fault information is not available. The driver crashed when retrieving the details."; + } +#endif + + std::string fault_message = fmt::format( + "Device Fault Information:\n" + "Fault Summary:\n" + " %s\n\n", + fault_description); + + if (!address_info.empty()) + { + fmt::append(fault_message, " Address Fault Information:\n", fault_description); + + for (const auto& fault : address_info) + { + std::string access_type = "access_unknown"; + switch (fault.addressType) + { + case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT: + access_type = "access_none"; + break; + case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT: + access_type = "access_read"; break; + case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT: + access_type = "access_write"; break; + case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT: + access_type = "access_execute"; break; + case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT: + access_type = "instruction_pointer_unknown"; break; + case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT: + access_type = "instruction_pointer_invalid"; break; + case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT: + access_type = "instruction_pointer_fault"; break; + default: + break; + } + + fmt::append(fault_message, " - Fault at address 0x%llx caused by %s\n", fault.reportedAddress, access_type); + } + } + + if (!vendor_info.empty()) + { + fmt::append(fault_message, " Vendor Fault Information:\n", fault_description); + + for (const auto& fault : vendor_info) + { + fmt::append(fault_message, " - [0x%llx, 0x%llx] %s\n", fault.vendorFaultCode, fault.vendorFaultData, fault.description); + } + } + + return fault_message; + } + void die_with_error(VkResult error_code, std::string message, std::source_location src_loc) { - std::string error_message; + std::string error_message, extra_info; int severity = 0; // 0 - die, 1 - warn, 2 - nothing switch (error_code) @@ -42,6 +144,7 @@ namespace vk break; case VK_ERROR_DEVICE_LOST: error_message = "Device lost (Driver crashed with unspecified error or stopped responding and recovered) (VK_ERROR_DEVICE_LOST)"; + extra_info = retrieve_device_fault_info(); break; case VK_ERROR_MEMORY_MAP_FAILED: error_message = "Memory map failed (VK_ERROR_MEMORY_MAP_FAILED)"; @@ -100,6 +203,11 @@ namespace vk break; } + if (!extra_info.empty()) + { + error_message = fmt::format("%s\n---------------- EXTRA INFORMATION --------------------\n%s", error_message, extra_info); + } + switch (severity) { default: diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index a4dbf084a5..551e7de36d 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -78,12 +78,12 @@ atomic_t g_watchdog_hold_ctr{0}; extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr); extern void spu_load_exec(const spu_exec_object&); extern void spu_load_rel_exec(const spu_rel_object&); -extern void ppu_precompile(std::vector& dir_queue, std::vector* loaded_prx); -extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); -extern void ppu_finalize(const ppu_module&); +extern void ppu_precompile(std::vector& dir_queue, std::vector*>* loaded_prx); +extern bool ppu_initialize(const ppu_module&, bool check_only = false, u64 file_size = 0); +extern void ppu_finalize(const ppu_module&); extern void ppu_unload_prx(const lv2_prx&); -extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 = 0, utils::serial* = nullptr); -extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 = 0, utils::serial* = nullptr); +extern shared_ptr ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 = 0, utils::serial* = nullptr); +extern std::pair, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 = 0, utils::serial* = nullptr); extern bool ppu_load_rel_exec(const ppu_rel_object&); extern void send_close_home_menu_cmds(); @@ -209,7 +209,7 @@ void Emulator::BlockingCallFromMainThread(std::function&& func, std::sou // This function ensures constant initialization order between different compilers and builds void init_fxo_for_exec(utils::serial* ar, bool full = false) { - g_fxo->init(); + g_fxo->init>(); void init_ppu_functions(utils::serial* ar, bool full); @@ -305,7 +305,7 @@ static void fixup_settings(const psf::registry* _psf) } } -extern void dump_executable(std::span data, const ppu_module* _module, std::string_view title_id) +extern void dump_executable(std::span data, const ppu_module* _module, std::string_view title_id) { std::string_view filename = _module->path; filename = filename.substr(filename.find_last_of('/') + 1); @@ -1666,7 +1666,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, { m_state = system_state::ready; GetCallbacks().on_ready(); - ensure(g_fxo->init()); + ensure(g_fxo->init>()); vm::init(); m_force_boot = false; @@ -1754,7 +1754,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, if (obj == elf_error::ok && ppu_load_exec(obj, true, path)) { - ensure(g_fxo->try_get())->path = path; + ensure(g_fxo->try_get>())->path = path; } else { @@ -1765,7 +1765,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, g_fxo->init("SPRX Loader"sv, [this, dir_queue]() mutable { - if (auto& _main = *ensure(g_fxo->try_get()); !_main.path.empty()) + if (auto& _main = *ensure(g_fxo->try_get>()); !_main.path.empty()) { if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_patches, std::vector{}, [](){ return Emu.IsStopped(); })) { @@ -2365,7 +2365,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, sys_log.error("Booting HG category outside of HDD0!"); } - const auto _main = ensure(g_fxo->init()); + const auto _main = ensure(g_fxo->init>()); if (ppu_load_exec(ppu_exec, false, m_path, DeserialManager())) { @@ -2718,8 +2718,15 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message) cpu.state += cpu_flag::dbg_global_pause; }; - idm::select>(on_select); - idm::select>(on_select); + if (g_fxo->is_init>>()) + { + idm::select>(on_select); + } + + if (g_fxo->is_init>>()) + { + idm::select>(on_select); + } if (auto rsx = g_fxo->try_get()) { @@ -2760,6 +2767,7 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message) std::unique_ptr> m_thread; }; + g_fxo->need(); g_fxo->get().m_thread.reset(); g_fxo->get().m_thread = std::make_unique>("Pause Message Thread"sv, std::move(refresh_l)); }); @@ -3010,7 +3018,7 @@ void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op, bool savesta } extern bool check_if_vdec_contexts_exist(); -extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock = false, std::vector>, u32>>* out_list = nullptr); +extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock = false, std::vector>, u32>>* out_list = nullptr); void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_stage) { @@ -3032,7 +3040,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s *pause_thread = make_ptr(new named_thread("Savestate Prepare Thread"sv, [pause_thread, allow_autoexit, this]() mutable { - std::vector>, u32>> paused_spus; + std::vector>, u32>> paused_spus; if (!try_lock_spu_threads_in_a_state_compatible_with_savestates(false, &paused_spus)) { @@ -3926,7 +3934,7 @@ s32 error_code::error_report(s32 result, const logs::message* channel, const cha void Emulator::ConfigurePPUCache() const { - auto& _main = g_fxo->get(); + auto& _main = g_fxo->get>(); _main.cache = rpcs3::utils::get_cache_dir(_main.path); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 97ff1c1d60..d9d1991b3e 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -401,7 +401,7 @@ private: struct savestate_stage { bool prepared = false; - std::vector>, u32>> paused_spus; + std::vector>, u32>> paused_spus; }; public: diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 800a7f9ff6..8484c57246 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -949,7 +949,7 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2 // Lock mount point, close file descriptors, retry const auto from0 = std::string_view(from).substr(0, from.find_last_not_of(fs::delim) + 1); - std::vector, std::string>> escaped_real; + std::vector, std::string>> escaped_real; std::unique_lock mp_lock(mp->mutex, std::defer_lock); diff --git a/rpcs3/Emu/cache_utils.cpp b/rpcs3/Emu/cache_utils.cpp index 601998848b..5c191ee7ee 100644 --- a/rpcs3/Emu/cache_utils.cpp +++ b/rpcs3/Emu/cache_utils.cpp @@ -3,6 +3,7 @@ #include "system_utils.hpp" #include "system_config.h" #include "IdManager.h" +#include "Emu/Cell/lv2/sys_sync.h" #include "Emu/Cell/PPUAnalyser.h" #include "Emu/Cell/PPUThread.h" @@ -12,7 +13,7 @@ namespace rpcs3::cache { std::string get_ppu_cache() { - const auto _main = g_fxo->try_get(); + const auto _main = g_fxo->try_get>(); if (!_main || _main->cache.empty()) { diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index 7476d58a59..2e560284d6 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -223,6 +223,8 @@ enum class localized_string_id HOME_MENU_SETTINGS_INPUT_CAMERA_FLIP, HOME_MENU_SETTINGS_INPUT_PAD_MODE, HOME_MENU_SETTINGS_INPUT_PAD_SLEEP, + HOME_MENU_SETTINGS_INPUT_FAKE_MOVE_ROTATION_CONE_H, + HOME_MENU_SETTINGS_INPUT_FAKE_MOVE_ROTATION_CONE_V, HOME_MENU_SETTINGS_ADVANCED, HOME_MENU_SETTINGS_ADVANCED_PREFERRED_SPU_THREADS, HOME_MENU_SETTINGS_ADVANCED_MAX_CPU_PREEMPTIONS, diff --git a/rpcs3/Emu/perf_meter.cpp b/rpcs3/Emu/perf_meter.cpp index db9aace584..70cfa6b63e 100644 --- a/rpcs3/Emu/perf_meter.cpp +++ b/rpcs3/Emu/perf_meter.cpp @@ -26,13 +26,13 @@ void perf_stat_base::print(const char* name) const noexcept { if (u64 num_total = m_log[0].load()) { - perf_log.notice(u8"Perf stats for %s: total events: %u (total time %.4fs, avg %.4fµs)", name, num_total, m_log[65].load() / 1000'000'000., m_log[65].load() / 1000. / num_total); + perf_log.notice(u8"Perf stats for %s: total events: %u (total time %.4fs, avg %.4fus)", name, num_total, m_log[65].load() / 1000'000'000., m_log[65].load() / 1000. / num_total); for (u32 i = 0; i < 13; i++) { if (u64 count = m_log[i + 1].load()) { - perf_log.notice(u8"Perf stats for %s: events < %.3fµs: %u", name, std::pow(2., i) / 1000., count); + perf_log.notice(u8"Perf stats for %s: events < %.3fus: %u", name, std::pow(2., i) / 1000., count); } } @@ -84,7 +84,7 @@ SAFE_BUFFERS(void) perf_stat_base::push(u64 data[66], u64 start_time, const char // Print in microseconds if (static_cast(diff * 1000'000.) >= g_cfg.core.perf_report_threshold) { - perf_log.notice(u8"%s: %.3fµs", name, diff * 1000'000.); + perf_log.notice(u8"%s: %.3fus", name, diff * 1000'000.); } data[0] += ns != 0; diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index 89de9767b8..85a2a82574 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -42,7 +42,7 @@ static std::array s_serial_versions; return ::s_serial_versions[identifier].current_version;\ } -SERIALIZATION_VER(global_version, 0, 17) // For stuff not listed here +SERIALIZATION_VER(global_version, 0, 19) // For stuff not listed here SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/) SERIALIZATION_VER(spu, 2, 1) SERIALIZATION_VER(lv2_sync, 3, 1) @@ -72,7 +72,7 @@ SERIALIZATION_VER(sceNp, 11) SERIALIZATION_VER(cellVdec, 12, 1) SERIALIZATION_VER(cellAudio, 13, 1) SERIALIZATION_VER(cellCamera, 14, 1) -SERIALIZATION_VER(cellGem, 15, 1) +SERIALIZATION_VER(cellGem, 15, 1, 2/*calibration_status_flags*/) SERIALIZATION_VER(sceNpTrophy, 16, 1) SERIALIZATION_VER(cellMusic, 17, 1) SERIALIZATION_VER(cellVoice, 18, 1) @@ -372,6 +372,7 @@ namespace stx { // Reset, probably a new utils::serial object s_tls_call_count = 1; + s_tls_object_name = "none"sv; } s_tls_current_pos = ar.pos; @@ -392,7 +393,7 @@ namespace stx if ((saved ^ tag) & data_mask) { ensure(!ar.is_writing()); - fmt::throw_exception("serial_breathe_and_tag(%u): %s, object: '%s', next-object: '%s', expected/tag: 0x%x != 0x%x,", s_tls_call_count, ar, s_tls_object_name, name, tag, saved); + fmt::throw_exception("serial_breathe_and_tag(%u): %s\nobject: '%s', next-object: '%s', expected/tag: 0x%x != 0x%x,", s_tls_call_count, ar, s_tls_object_name, name, tag, saved); } s_tls_object_name = name; diff --git a/rpcs3/Emu/scoped_progress_dialog.cpp b/rpcs3/Emu/scoped_progress_dialog.cpp index 35606b4600..ababe3d190 100644 --- a/rpcs3/Emu/scoped_progress_dialog.cpp +++ b/rpcs3/Emu/scoped_progress_dialog.cpp @@ -91,8 +91,8 @@ scoped_progress_dialog::scoped_progress_dialog(std::string text) noexcept scoped_progress_dialog& scoped_progress_dialog::operator=(std::string text) noexcept { - // Exchange text atomically - g_progr_text_queue[m_text_index].exchange(make_single_value(std::move(text))); + // Set text atomically + g_progr_text_queue[m_text_index].store(make_single_value(std::move(text))); return *this; } diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 8a0e7737ca..3cb3e39851 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -178,6 +178,7 @@ struct cfg_root : cfg::node cfg::_bool decr_memory_layout{ this, "DECR memory layout", false}; // Force enable increased allowed main memory range as DECR console cfg::_bool host_label_synchronization{ this, "Allow Host GPU Labels", false }; cfg::_bool disable_msl_fast_math{ this, "Disable MSL Fast Math", false }; + cfg::_bool disable_async_host_memory_manager{ this, "Disable Asynchronous Memory Manager", false, true }; cfg::_enum output_scaling{ this, "Output Scaling Mode", output_scaling_mode::bilinear, true }; struct node_vk : cfg::node @@ -278,10 +279,14 @@ struct cfg_root : cfg::node cfg::uint<0, 100'000> pad_sleep{this, "Pad handler sleep (microseconds)", 1'000, true}; cfg::_bool background_input_enabled{this, "Background input enabled", true, true}; cfg::_bool show_move_cursor{this, "Show move cursor", false, true}; + cfg::_bool paint_move_spheres{this, "Paint move spheres", false, true}; + cfg::_bool allow_move_hue_set_by_game{this, "Allow move hue set by game", false, true}; cfg::_bool lock_overlay_input_to_player_one{this, "Lock overlay input to player one", false, true}; cfg::string midi_devices{this, "Emulated Midi devices", "ßßß@@@ßßß@@@ßßß@@@"}; cfg::_bool load_sdl_mappings{ this, "Load SDL GameController Mappings", true }; cfg::_bool debug_overlay{ this, "IO Debug overlay", false, true }; + cfg::uint<1, 180> fake_move_rotation_cone_h{ this, "Fake Move Rotation Cone", 10, true }; + cfg::uint<1, 180> fake_move_rotation_cone_v{ this, "Fake Move Rotation Cone (Vertical)", 10, true }; } io{ this }; diff --git a/rpcs3/Input/gui_pad_thread.cpp b/rpcs3/Input/gui_pad_thread.cpp index ff179f644e..87fa0999f3 100644 --- a/rpcs3/Input/gui_pad_thread.cpp +++ b/rpcs3/Input/gui_pad_thread.cpp @@ -27,6 +27,10 @@ #elif defined(__APPLE__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#pragma GCC diagnostic ignored "-Wnullability-completeness" +#pragma GCC diagnostic ignored "-Wdeprecated-anon-enum-enum-conversion" #include #include #pragma GCC diagnostic pop diff --git a/rpcs3/Input/ps_move_config.h b/rpcs3/Input/ps_move_config.h index cdf70f9646..0e12889956 100644 --- a/rpcs3/Input/ps_move_config.h +++ b/rpcs3/Input/ps_move_config.h @@ -26,8 +26,8 @@ struct cfg_ps_moves final : cfg::node cfg_ps_move move3{ this, "PS Move 3" }; cfg_ps_move move4{ this, "PS Move 4" }; - cfg::_float<0, 100> min_radius{ this, "Minimum Radius", 1.0f, true }; // Percentage of image width - cfg::_float<0, 100> max_radius{ this, "Maximum Radius", 10.0f, true }; // Percentage of image width + cfg::_float<0, 50> min_radius{ this, "Minimum Radius", 1.0f, true }; // Percentage of image width + cfg::_float<0, 50> max_radius{ this, "Maximum Radius", 10.0f, true }; // Percentage of image width std::array move{ &move1, &move2, &move3, &move4 }; diff --git a/rpcs3/Input/ps_move_handler.cpp b/rpcs3/Input/ps_move_handler.cpp index 07c379a9ee..83049f5fd0 100644 --- a/rpcs3/Input/ps_move_handler.cpp +++ b/rpcs3/Input/ps_move_handler.cpp @@ -359,12 +359,7 @@ void ps_move_handler::check_add_device(hid_device* hidDevice, std::string_view p psmove_parse_calibration(calibration, *device); } - // Initialize Fusion - FusionAhrsInitialise(&device->ahrs); - device->ahrs.settings.convention = FusionConvention::FusionConventionEnu; - device->ahrs.settings.gain = 0.0f; // If gain is set, the algorithm tries to adjust the orientation over time. - FusionAhrsSetSettings(&device->ahrs, &device->ahrs.settings); - FusionAhrsReset(&device->ahrs); + device->reset_orientation(); // Activate if (send_output_report(device) == -1) @@ -683,12 +678,19 @@ void ps_move_handler::get_extended_info(const pad_ensemble& binding) if (dev->model == ps_move_model::ZCM1) { - accel_x = (input.accel_x_1 + input.accel_x_2) / 2 - zero_shift; - accel_y = (input.accel_y_1 + input.accel_y_2) / 2 - zero_shift; - accel_z = (input.accel_z_1 + input.accel_z_2) / 2 - zero_shift; - gyro_x = (input.gyro_x_1 + input.gyro_x_2) / 2 - zero_shift; - gyro_y = (input.gyro_y_1 + input.gyro_y_2) / 2 - zero_shift; - gyro_z = (input.gyro_z_1 + input.gyro_z_2) / 2 - zero_shift; + accel_x -= zero_shift; + accel_y -= zero_shift; + accel_z -= zero_shift; + gyro_x -= zero_shift; + gyro_y -= zero_shift; + gyro_z -= zero_shift; + + const ps_move_input_report_ZCM1& input_zcm1 = dev->input_report_ZCM1; + + #define TWELVE_BIT_SIGNED(x) (((x) & 0x800) ? (-(((~(x)) & 0xFFF) + 1)) : (x)) + pad->move_data.magnetometer_x = static_cast(TWELVE_BIT_SIGNED(((input.magnetometer_x & 0x0F) << 8) | input_zcm1.magnetometer_x2)); + pad->move_data.magnetometer_y = static_cast(TWELVE_BIT_SIGNED((input_zcm1.magnetometer_y << 4) | (input_zcm1.magnetometer_yz & 0xF0) >> 4)); + pad->move_data.magnetometer_z = static_cast(TWELVE_BIT_SIGNED(((input_zcm1.magnetometer_yz & 0x0F) << 8) | input_zcm1.magnetometer_z)); } // Apply calibration @@ -720,57 +722,7 @@ void ps_move_handler::get_extended_info(const pad_ensemble& binding) pad->m_sensors[2].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.accelerometer_z)); pad->m_sensors[3].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.gyro_z * -1.0f)); - // Get elapsed time since last update - const u64 now_us = get_system_time(); - const float elapsed_sec = (dev->last_ahrs_update_time_us == 0) ? 0.0f : ((now_us - dev->last_ahrs_update_time_us) / 1'000'000.0f); - dev->last_ahrs_update_time_us = now_us; - - // The ps move handler's axis may differ from the Fusion axis, so we have to map them correctly. - // Don't ask how the axis work. It's basically been trial and error. - ensure(dev->ahrs.settings.convention == FusionConvention::FusionConventionEnu); // East-North-Up - - const FusionVector accelerometer{ - .axis { - .x = -pad->move_data.accelerometer_x, - .y = +pad->move_data.accelerometer_y, - .z = +pad->move_data.accelerometer_z - } - }; - - static constexpr f32 PI = 3.14159265f; - const auto rad_to_degree = [](f32 radians) -> f32 { return radians * 180.0f / PI; }; - const FusionVector gyroscope{ - .axis { - .x = +rad_to_degree(pad->move_data.gyro_x), - .y = +rad_to_degree(pad->move_data.gyro_z), - .z = -rad_to_degree(pad->move_data.gyro_y) - } - }; - - FusionVector magnetometer {}; - - // TODO: use magnetometer if possible - //if (dev->model == ps_move_model::ZCM1) - //{ - // const ps_move_input_report_ZCM1& input = dev->input_report_ZCM1; - // magnetometer = FusionVector{ - // .axis { - // .x = input.magnetometer_x2, - // .y = input.magnetometer_y, - // .z = input.magnetometer_z - // } - // }; - //} - - // Update Fusion - FusionAhrsUpdate(&dev->ahrs, gyroscope, accelerometer, magnetometer, elapsed_sec); - - // Get quaternion - const FusionQuaternion quaternion = FusionAhrsGetQuaternion(&dev->ahrs); - pad->move_data.quaternion[0] = quaternion.array[0]; - pad->move_data.quaternion[1] = quaternion.array[1]; - pad->move_data.quaternion[2] = quaternion.array[2]; - pad->move_data.quaternion[3] = quaternion.array[3]; + dev->update_orientation(pad->move_data); handle_external_device(binding); } @@ -817,11 +769,9 @@ int ps_move_handler::send_output_report(ps_move_device* device) const auto elapsed = now - device->last_output_report_time; // Update LED at an interval or it will be disabled automatically - if (elapsed >= 4000ms) - { - device->new_output_data = true; - } - else + device->new_output_data |= elapsed >= 4000ms; + + if (!device->new_output_data) { // Use LED update rate of 120ms if (elapsed < 120ms) @@ -858,6 +808,7 @@ void ps_move_handler::apply_pad_data(const pad_ensemble& binding) const u8 speed_large = config->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : 0; + dev->new_output_data |= dev->large_motor != speed_large; dev->large_motor = speed_large; if (send_output_report(dev) >= 0) @@ -912,3 +863,74 @@ u32 ps_move_handler::get_battery_level(const std::string& padId) // 0 to 5 return std::clamp(device->battery_level * 20, 0, 100); } + +void ps_move_device::reset_orientation() +{ + // Initialize Fusion + ahrs = {}; + FusionAhrsInitialise(&ahrs); + ahrs.settings.convention = FusionConvention::FusionConventionEnu; + ahrs.settings.gain = 0.0f; // If gain is set, the algorithm tries to adjust the orientation over time. + FusionAhrsSetSettings(&ahrs, &ahrs.settings); + FusionAhrsReset(&ahrs); +} + +void ps_move_device::update_orientation(ps_move_data& move_data) +{ + if (move_data.calibration_requested) + { + reset_orientation(); + + move_data.calibration_succeeded = true; + } + + // Get elapsed time since last update + const u64 now_us = get_system_time(); + const float elapsed_sec = (last_ahrs_update_time_us == 0) ? 0.0f : ((now_us - last_ahrs_update_time_us) / 1'000'000.0f); + last_ahrs_update_time_us = now_us; + + // The ps move handler's axis may differ from the Fusion axis, so we have to map them correctly. + // Don't ask how the axis work. It's basically been trial and error. + ensure(ahrs.settings.convention == FusionConvention::FusionConventionEnu); // East-North-Up + + const FusionVector accelerometer{ + .axis { + .x = -move_data.accelerometer_x, + .y = +move_data.accelerometer_y, + .z = +move_data.accelerometer_z + } + }; + + static constexpr f32 PI = 3.14159265f; + const auto rad_to_degree = [](f32 radians) -> f32 { return radians * 180.0f / PI; }; + const FusionVector gyroscope{ + .axis { + .x = +rad_to_degree(move_data.gyro_x), + .y = +rad_to_degree(move_data.gyro_z), + .z = -rad_to_degree(move_data.gyro_y) + } + }; + + FusionVector magnetometer {}; + + if (move_data.magnetometer_enabled) + { + magnetometer = FusionVector{ + .axis { + .x = move_data.magnetometer_x, + .y = move_data.magnetometer_y, + .z = move_data.magnetometer_z + } + }; + } + + // Update Fusion + FusionAhrsUpdate(&ahrs, gyroscope, accelerometer, magnetometer, elapsed_sec); + + // Get quaternion + const FusionQuaternion quaternion = FusionAhrsGetQuaternion(&ahrs); + move_data.quaternion[0] = quaternion.array[1]; + move_data.quaternion[1] = quaternion.array[2]; + move_data.quaternion[2] = quaternion.array[3]; + move_data.quaternion[3] = quaternion.array[0]; +} diff --git a/rpcs3/Input/ps_move_handler.h b/rpcs3/Input/ps_move_handler.h index 434a3c81a2..4c6097fecf 100644 --- a/rpcs3/Input/ps_move_handler.h +++ b/rpcs3/Input/ps_move_handler.h @@ -54,8 +54,9 @@ namespace reports // ID Size Description u8 magnetometer_x2{}; // 0x27 1- X-axis magnetometer - u8 magnetometer_y{}; // 0x28 1+ Z-axis magnetometer - u16 magnetometer_z{}; // 0x29 1- Y-axis magnetometer + u8 magnetometer_y{}; // 0x28 1+ Y-axis magnetometer + u8 magnetometer_yz{}; // 0x29 1 YZ-axis magnetometer + u8 magnetometer_z{}; // 0x2A 1- Z-axis magnetometer u8 timestamp_lower{}; // 0x2B 1 Timestamp (lower byte) std::array ext_device_data{}; // 0x2C 5 External device data }; @@ -148,6 +149,9 @@ public: FusionAhrs ahrs {}; // Used to calculate quaternions from sensor data u64 last_ahrs_update_time_us = 0; // Last ahrs update + void update_orientation(ps_move_data& move_data); + void reset_orientation(); + const reports::ps_move_input_report_common& input_report_common() const; }; diff --git a/rpcs3/Input/ps_move_tracker.cpp b/rpcs3/Input/ps_move_tracker.cpp index e72c550338..b831e87967 100644 --- a/rpcs3/Input/ps_move_tracker.cpp +++ b/rpcs3/Input/ps_move_tracker.cpp @@ -277,9 +277,9 @@ void ps_move_tracker::process_hues() for (u32 x = 0; x < width; x++, rgba += 4, hsv += 3) { - const float r = rgba[0] / 255.0f; - const float g = rgba[1] / 255.0f; - const float b = rgba[2] / 255.0f; + const f32 r = rgba[0] / 255.0f; + const f32 g = rgba[1] / 255.0f; + const f32 b = rgba[2] / 255.0f; const auto [hue, saturation, value] = rgb_to_hsv(r, g, b); hsv[0] = static_cast(hue / 2); @@ -296,23 +296,51 @@ void ps_move_tracker::process_hues() } #ifdef HAVE_OPENCV -static bool is_circular_contour(const std::vector& contour, float& area) +static bool is_circular_contour(const std::vector& contour, f32& area) { std::vector approx; cv::approxPolyDP(contour, approx, 0.01 * cv::arcLength(contour, true), true); if (approx.size() < 8ULL) return false; - area = static_cast(cv::contourArea(contour)); + area = static_cast(cv::contourArea(contour)); if (area < 30.0f) return false; cv::Point2f center; - float radius; + f32 radius; cv::minEnclosingCircle(contour, center, radius); if (radius < 5.0f) return false; return true; } +template +void ps_move_tracker::draw_sphere_size_range(f32 result_radius) +{ + if constexpr (!DiagnosticsEnabled) return; + if (!m_draw_overlays) return; + + // Map memory + cv::Mat rgba(cv::Size(m_width, m_height), CV_8UC4, m_image_rgba_contours.data(), 0); + + // Draw result, min and max radius + const f32 min_radius = m_min_radius * m_width; + const f32 max_radius = m_max_radius * m_width; + const f32 min_radius_clamped = std::max(0.0f, std::min(min_radius, max_radius)); + const cv::Point2f center = cv::Point2f(m_width - 1 - max_radius, max_radius); + if (result_radius > 0.0f) + { + cv::circle(rgba, center, static_cast(result_radius), cv::Scalar(255, 0, 0, 255), cv::FILLED); + } + if (min_radius_clamped > 0.0f && min_radius_clamped <= max_radius) + { + cv::circle(rgba, center, static_cast(min_radius_clamped), cv::Scalar(0, 0, 0, 255), cv::FILLED); + } + if (max_radius > min_radius_clamped) + { + cv::circle(rgba, center, static_cast(max_radius), cv::Scalar(0, 0, 0, 255), 1); + } +} + template void ps_move_tracker::process_contours(ps_move_info& info, u32 index) { @@ -363,7 +391,7 @@ void ps_move_tracker::process_contours(ps_move_info& info, u cv::findContours(binary, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); for (auto it = contours.begin(); it != contours.end();) { - float area; + f32 area; if (is_circular_contour(*it, area)) { it = contours.erase(it); @@ -384,6 +412,11 @@ void ps_move_tracker::process_contours(ps_move_info& info, u if (all_contours.empty()) { set_valid(info, index, false); + + if constexpr (DiagnosticsEnabled) + { + draw_sphere_size_range(0.0f); + } return; } @@ -393,24 +426,24 @@ void ps_move_tracker::process_contours(ps_move_info& info, u std::vector centers; centers.reserve(all_contours.size()); - std::vector radii; + std::vector radii; radii.reserve(all_contours.size()); const f32 min_radius = m_min_radius * width; const f32 max_radius = m_max_radius * width; usz best_index = umax; - float best_area = 0.0f; + f32 best_area = 0.0f; for (usz i = 0; i < all_contours.size(); i++) { const std::vector& contour = all_contours[i]; - float area; + f32 area; if (!is_circular_contour(contour, area)) continue; // Get center and radius cv::Point2f center; - float radius; + f32 radius; cv::minEnclosingCircle(contour, center, radius); // Filter radius @@ -431,6 +464,11 @@ void ps_move_tracker::process_contours(ps_move_info& info, u if (best_index == umax) { set_valid(info, index, false); + + if constexpr (DiagnosticsEnabled) + { + draw_sphere_size_range(0.0f); + } return; } @@ -438,7 +476,7 @@ void ps_move_tracker::process_contours(ps_move_info& info, u const f32 sphere_radius_pixels = radii[best_index]; constexpr f32 focal_length_mm = 3.5f; // Based on common webcam specs constexpr f32 sensor_width_mm = 3.6f; // Based on common webcam specs - const f32 image_width_pixels = static_cast(width); + const f32 image_width_pixels = static_cast(width); const f32 focal_length_pixels = (focal_length_mm * image_width_pixels) / sensor_width_mm; const f32 distance_mm = (focal_length_pixels * CELL_GEM_SPHERE_RADIUS_MM) / sphere_radius_pixels; @@ -472,6 +510,8 @@ void ps_move_tracker::process_contours(ps_move_info& info, u if (!m_draw_contours && !m_draw_overlays) [[likely]] return; + draw_sphere_size_range(info.radius); + // Map memory cv::Mat rgba(cv::Size(width, height), CV_8UC4, m_image_rgba_contours.data(), 0); @@ -499,11 +539,11 @@ void ps_move_tracker::process_contours(ps_move_info& info, u for (usz i = 0; i < centers.size(); i++) { const cv::Point2f& center = centers[i]; - const float radius = radii[i]; + const f32 radius = radii[i]; cv::circle(rgba, center, static_cast(radius), circle_color, 1); - cv::line(rgba, center + cv::Point2f(-2, 0), center + cv::Point2f(2, 0), center_color, 1); - cv::line(rgba, center + cv::Point2f(0, -2), center + cv::Point2f(0, 2), center_color, 1); + cv::line(rgba, center + cv::Point2f(-2.0f, 0.0f), center + cv::Point2f(2.0f, 0.0f), center_color, 1); + cv::line(rgba, center + cv::Point2f(0.0f, -2.0f), center + cv::Point2f(0.0f, 2.0f), center_color, 1); } } } @@ -525,16 +565,16 @@ void ps_move_tracker::process_contours(ps_move_info& info, u #endif template -std::tuple ps_move_tracker::hsv_to_rgb(u16 hue, float saturation, float value) +std::tuple ps_move_tracker::hsv_to_rgb(u16 hue, f32 saturation, f32 value) { - const float h = hue / 60.0f; - const float chroma = value * saturation; - const float x = chroma * (1.0f - std::abs(std::fmod(h, 2.0f) - 1.0f)); - const float m = value - chroma; + const f32 h = hue / 60.0f; + const f32 chroma = value * saturation; + const f32 x = chroma * (1.0f - std::abs(std::fmod(h, 2.0f) - 1.0f)); + const f32 m = value - chroma; - float r = 0.0f; - float g = 0.0f; - float b = 0.0f; + f32 r = 0.0f; + f32 g = 0.0f; + f32 b = 0.0f; switch (static_cast(std::ceil(h))) { @@ -581,12 +621,12 @@ std::tuple ps_move_tracker::hsv_to_rgb(u16 hue, } template -std::tuple ps_move_tracker::rgb_to_hsv(float r, float g, float b) +std::tuple ps_move_tracker::rgb_to_hsv(f32 r, f32 g, f32 b) { - const float cmax = std::max({r, g, b}); // V (of HSV) - const float cmin = std::min({r, g, b}); - const float delta = cmax - cmin; - const float saturation = cmax ? (delta / cmax) : 0.0f; // S (of HSV) + const f32 cmax = std::max({r, g, b}); // V (of HSV) + const f32 cmin = std::min({r, g, b}); + const f32 delta = cmax - cmin; + const f32 saturation = cmax ? (delta / cmax) : 0.0f; // S (of HSV) s16 hue; // H (of HSV) diff --git a/rpcs3/Input/ps_move_tracker.h b/rpcs3/Input/ps_move_tracker.h index 5ca91fd893..5c9b9df9c7 100644 --- a/rpcs3/Input/ps_move_tracker.h +++ b/rpcs3/Input/ps_move_tracker.h @@ -52,8 +52,8 @@ public: const std::vector& gray() { return m_image_gray; } const std::vector& binary(u32 index) { return ::at32(m_image_binary, index); } - static std::tuple hsv_to_rgb(u16 hue, float saturation, float value); - static std::tuple rgb_to_hsv(float r, float g, float b); + static std::tuple hsv_to_rgb(u16 hue, f32 saturation, f32 value); + static std::tuple rgb_to_hsv(f32 r, f32 g, f32 b); private: struct ps_move_config @@ -73,6 +73,8 @@ private: void set_valid(ps_move_info& info, u32 index, bool valid); + void draw_sphere_size_range(f32 result_radius); + u32 m_width = 0; u32 m_height = 0; s32 m_format = 0; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 9a196dd8af..f311845462 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -104,6 +104,7 @@ + @@ -621,6 +622,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 584787892a..c516f50756 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1312,6 +1312,9 @@ Emu\GPU\RSX\Host Mini-Driver + + Emu\GPU\RSX\Host Mini-Driver + @@ -2644,6 +2647,9 @@ Emu\GPU\RSX\Host Mini-Driver + + Emu\GPU\RSX\Host Mini-Driver + diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 1973831ab3..755370a4c7 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -2069,6 +2069,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 0e2eae3a00..4cdbcedc2e 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -190,6 +190,9 @@ {f8a98f7b-dc23-47c0-8a5f-d0b76eaf0df5} + + {f6b701aa-7f4a-4816-b05f-80d24cb70e13} + @@ -1806,5 +1809,8 @@ CI + + Darwin + \ No newline at end of file diff --git a/rpcs3/rpcs3qt/category.h b/rpcs3/rpcs3qt/category.h index 641af991b8..d87ebc1092 100644 --- a/rpcs3/rpcs3qt/category.h +++ b/rpcs3/rpcs3qt/category.h @@ -13,6 +13,7 @@ enum Category Home, Media, Data, + OS, Unknown_Cat, Others, }; @@ -50,5 +51,6 @@ namespace cat const QStringList psp_games = { cat_psp_game, cat_psp_mini, cat_psp_rema }; const QStringList media = { cat_app_photo, cat_app_video, cat_bc_video, cat_app_music, cat_app_store, cat_app_tv, cat_web_tv }; const QStringList data = { cat_ps3_data, cat_ps2_data, cat_ps3_save, cat_psp_save }; - const QStringList others = { cat_network, cat_store_fe, cat_ps3_os }; + const QStringList os = { cat_ps3_os }; + const QStringList others = { cat_network, cat_store_fe }; } diff --git a/rpcs3/rpcs3qt/cheat_manager.cpp b/rpcs3/rpcs3qt/cheat_manager.cpp index 5fa0d60ba6..27e0860232 100644 --- a/rpcs3/rpcs3qt/cheat_manager.cpp +++ b/rpcs3/rpcs3qt/cheat_manager.cpp @@ -15,6 +15,7 @@ #include "Emu/IdManager.h" #include "Emu/Cell/PPUAnalyser.h" #include "Emu/Cell/PPUFunction.h" +#include "Emu/Cell/lv2/sys_sync.h" #include "util/yaml.hpp" #include "util/asm.hpp" @@ -441,7 +442,7 @@ bool cheat_engine::is_addr_safe(const u32 offset) if (Emu.IsStopped()) return false; - const auto ppum = g_fxo->try_get(); + const auto ppum = g_fxo->try_get>(); if (!ppum) { diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index d515751523..56b1ccb0a4 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -54,14 +54,14 @@ extern bool is_using_interpreter(thread_class t_class) } } -extern std::shared_ptr make_disasm(const cpu_thread* cpu, std::shared_ptr handle) +extern std::shared_ptr make_disasm(const cpu_thread* cpu, shared_ptr handle) { if (!handle) { switch (cpu->get_class()) { - case thread_class::ppu: handle = idm::get>(cpu->id); break; - case thread_class::spu: handle = idm::get>(cpu->id); break; + case thread_class::ppu: handle = idm::get_unlocked>(cpu->id); break; + case thread_class::spu: handle = idm::get_unlocked>(cpu->id); break; default: break; } } @@ -850,7 +850,7 @@ std::function debugger_frame::make_check_cpu(cpu_thread* cpu, boo const auto type = cpu ? cpu->get_class() : thread_class::general; - std::shared_ptr shared; + shared_ptr shared; if (g_fxo->is_init>>() && g_fxo->is_init>>()) { @@ -869,11 +869,11 @@ std::function debugger_frame::make_check_cpu(cpu_thread* cpu, boo { if (type == thread_class::ppu) { - shared = idm::get>(cpu->id); + shared = idm::get_unlocked>(cpu->id); } else if (type == thread_class::spu) { - shared = idm::get>(cpu->id); + shared = idm::get_unlocked>(cpu->id); } } } @@ -1049,8 +1049,15 @@ void debugger_frame::UpdateUnitList() if (emu_state != system_state::stopped) { - idm::select>(on_select, idm::unlocked); - idm::select>(on_select, idm::unlocked); + if (g_fxo->is_init>>()) + { + idm::select>(on_select, idm::unlocked); + } + + if (g_fxo->is_init>>()) + { + idm::select>(on_select, idm::unlocked); + } if (const auto render = g_fxo->try_get(); render && render->ctrl) { @@ -1153,7 +1160,7 @@ void debugger_frame::OnSelectUnit() { case 1: { - m_cpu = idm::get>(cpu_id); + m_cpu = idm::get_unlocked>(cpu_id); if (selected == m_cpu.get()) { @@ -1164,7 +1171,7 @@ void debugger_frame::OnSelectUnit() } case 2: { - m_cpu = idm::get>(cpu_id); + m_cpu = idm::get_unlocked>(cpu_id); if (selected == m_cpu.get()) { @@ -1179,7 +1186,7 @@ void debugger_frame::OnSelectUnit() if (get_cpu()) { - m_disasm = make_disasm(m_rsx, nullptr); + m_disasm = make_disasm(m_rsx, null_ptr); } break; diff --git a/rpcs3/rpcs3qt/debugger_frame.h b/rpcs3/rpcs3qt/debugger_frame.h index c09716a1f8..ee685231c5 100644 --- a/rpcs3/rpcs3qt/debugger_frame.h +++ b/rpcs3/rpcs3qt/debugger_frame.h @@ -1,6 +1,7 @@ #pragma once #include "util/types.hpp" +#include "util/shared_ptr.hpp" #include "custom_dock_widget.h" @@ -75,7 +76,7 @@ class debugger_frame : public custom_dock_widget bool m_thread_list_pending_update = false; std::shared_ptr m_disasm; // Only shared to allow base/derived functionality - std::shared_ptr m_cpu; + shared_ptr m_cpu; rsx::thread* m_rsx = nullptr; std::shared_ptr m_spu_disasm_memory; u32 m_spu_disasm_origin_eal = 0; diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index f6b6268bd3..9eec1956ed 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -103,6 +103,7 @@ enum class emu_settings_type DisableMSLFastMath, OutputScalingMode, ForceHwMSAAResolve, + DisableAsyncHostMM, // Performance Overlay PerfOverlayEnabled, @@ -294,6 +295,7 @@ inline static const std::map settings_location { emu_settings_type::DisableMSLFastMath, { "Video", "Disable MSL Fast Math"}}, { emu_settings_type::OutputScalingMode, { "Video", "Output Scaling Mode"}}, { emu_settings_type::ForceHwMSAAResolve, { "Video", "Force Hardware MSAA Resolve"}}, + { emu_settings_type::DisableAsyncHostMM, { "Video", "Disable Asynchronous Memory Manager"}}, // Vulkan { emu_settings_type::VulkanAsyncTextureUploads, { "Video", "Vulkan", "Asynchronous Texture Streaming 2"}}, diff --git a/rpcs3/rpcs3qt/flow_layout.cpp b/rpcs3/rpcs3qt/flow_layout.cpp index 579ae59404..92fe956b28 100644 --- a/rpcs3/rpcs3qt/flow_layout.cpp +++ b/rpcs3/rpcs3qt/flow_layout.cpp @@ -79,10 +79,14 @@ flow_layout::~flow_layout() void flow_layout::clear() { + // We can't use a ranged loop here, since deleting the widget will call takeAt on the layout. So let's also use takeAt. while (QLayoutItem* item = takeAt(0)) { - delete item->widget(); - delete item; + if (item) + { + delete item->widget(); + delete item; + } } m_item_list.clear(); m_positions.clear(); @@ -185,8 +189,8 @@ int flow_layout::doLayout(const QRect& rect, bool testOnly) const int x = effectiveRect.x(); int y = effectiveRect.y(); int lineHeight = 0; - int rows = 0; - int cols = 0; + int row_count = 0; + int col_count = 0; if (m_dynamic_spacing) { @@ -259,8 +263,8 @@ int flow_layout::doLayout(const QRect& rect, bool testOnly) const pos.row = row; pos.col = col++; - rows = std::max(rows, pos.row + 1); - cols = std::max(cols, pos.col + 1); + row_count = std::max(row_count, pos.row + 1); + col_count = std::max(col_count, pos.col + 1); if (!testOnly) item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); @@ -269,8 +273,8 @@ int flow_layout::doLayout(const QRect& rect, bool testOnly) const lineHeight = qMax(lineHeight, item->sizeHint().height()); } - m_rows = rows; - m_cols = cols; + m_rows = row_count; + m_cols = col_count; return y + lineHeight - rect.y() + bottom; } diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 486720c66a..12886b8664 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -2347,7 +2347,7 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set const std::shared_ptr> periodic_func = std::make_shared>(); - *periodic_func = [=]() + *periodic_func = [=, this]() { if (should_wait_cb && should_wait_cb()) { diff --git a/rpcs3/rpcs3qt/gui_save.h b/rpcs3/rpcs3qt/gui_save.h index 66970172f6..cbeec7b5a6 100644 --- a/rpcs3/rpcs3qt/gui_save.h +++ b/rpcs3/rpcs3qt/gui_save.h @@ -11,16 +11,11 @@ struct gui_save gui_save() { - key = ""; - name = ""; - def = QVariant(); } gui_save(const QString& k, const QString& n, const QVariant& d) + : key(k), name(n), def(d) { - key = k; - name = n; - def = d; } bool operator==(const gui_save& rhs) const noexcept diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index 54ed12391f..a79f9d9db7 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -125,6 +125,7 @@ QStringList gui_settings::GetGameListCategoryFilters(bool is_list_mode) const if (GetCategoryVisibility(Category::Home, is_list_mode)) filterList.append(cat::cat_home); if (GetCategoryVisibility(Category::Media, is_list_mode)) filterList.append(cat::media); if (GetCategoryVisibility(Category::Data, is_list_mode)) filterList.append(cat::data); + if (GetCategoryVisibility(Category::OS, is_list_mode)) filterList.append(cat::os); if (GetCategoryVisibility(Category::Unknown_Cat, is_list_mode)) filterList.append(cat::cat_unknown); if (GetCategoryVisibility(Category::Others, is_list_mode)) filterList.append(cat::others); @@ -205,7 +206,7 @@ bool gui_settings::GetBootConfirmation(QWidget* parent, const gui_save& gui_save { if (Emu.GetStatus(false) != system_state::stopping) { - ensure(info == Emu.GetEmulationIdentifier(old_status == system_state::stopping ? true : false)); + ensure(info == Emu.GetEmulationIdentifier(old_status == system_state::stopping)); return true; } @@ -344,6 +345,7 @@ gui_save gui_settings::GetGuiSaveForCategory(int cat, bool is_list_mode) case Category::PSP_Game: return is_list_mode ? gui::cat_psp_game : gui::grid_cat_psp_game; case Category::Media: return is_list_mode ? gui::cat_audio_video : gui::grid_cat_audio_video; case Category::Data: return is_list_mode ? gui::cat_game_data : gui::grid_cat_game_data; + case Category::OS: return is_list_mode ? gui::cat_os : gui::grid_cat_os; case Category::Unknown_Cat: return is_list_mode ? gui::cat_unknown : gui::grid_cat_unknown; case Category::Others: return is_list_mode ? gui::cat_other : gui::grid_cat_other; default: diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index 7a3b3535a3..82c6770d00 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -120,6 +120,7 @@ namespace gui const gui_save rg_freeze = gui_save(main_window, "recentGamesFrozen", false); const gui_save rg_entries = gui_save(main_window, "recentGamesNames", QVariant::fromValue(q_pair_list())); + const gui_save ib_skip_version = gui_save(main_window, "infoBoxSkipVersion", ""); const gui_save ib_pkg_success = gui_save(main_window, "infoBoxEnabledInstallPKG", true); const gui_save ib_pup_success = gui_save(main_window, "infoBoxEnabledInstallPUP", true); const gui_save ib_show_welcome = gui_save(main_window, "infoBoxEnabledWelcome", true); @@ -160,6 +161,7 @@ namespace gui const gui_save cat_home = gui_save(game_list, "categoryVisibleHome", true); const gui_save cat_audio_video = gui_save(game_list, "categoryVisibleAudioVideo", true); const gui_save cat_game_data = gui_save(game_list, "categoryVisibleGameData", false); + const gui_save cat_os = gui_save(game_list, "categoryVisibleOS", false); const gui_save cat_unknown = gui_save(game_list, "categoryVisibleUnknown", true); const gui_save cat_other = gui_save(game_list, "categoryVisibleOther", true); @@ -171,6 +173,7 @@ namespace gui const gui_save grid_cat_home = gui_save(game_list, "gridCategoryVisibleHome", true); const gui_save grid_cat_audio_video = gui_save(game_list, "gridCategoryVisibleAudioVideo", true); const gui_save grid_cat_game_data = gui_save(game_list, "gridCategoryVisibleGameData", false); + const gui_save grid_cat_os = gui_save(game_list, "gridCategoryVisibleOS", false); const gui_save grid_cat_unknown = gui_save(game_list, "gridCategoryVisibleUnknown", true); const gui_save grid_cat_other = gui_save(game_list, "gridCategoryVisibleOther", true); diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index a70e12cb97..e30fdff643 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -317,7 +317,7 @@ void kernel_explorer::update() add_solid_node(find_node(root, additional_nodes::process_info), qstr(fmt::format("Process Info, Sdk Version: 0x%08x, PPC SEG: %#x, SFO Category: %s (Fake: %s)", g_ps3_process_info.sdk_ver, g_ps3_process_info.ppc_seg, Emu.GetCat(), Emu.GetFakeCat()))); - auto display_program_segments = [this](QTreeWidgetItem* tree, const ppu_module& m) + auto display_program_segments = [this](QTreeWidgetItem* tree, const ppu_module& m) { for (usz i = 0; i < m.segs.size(); i++) { @@ -528,7 +528,7 @@ void kernel_explorer::update() auto& timer = static_cast(obj); u32 timer_state{SYS_TIMER_STATE_STOP}; - std::shared_ptr port; + shared_ptr port; u64 source = 0; u64 data1 = 0; u64 data2 = 0; diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index 2f6c4d19ae..9dbc9ee3f3 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -244,6 +244,8 @@ private: case localized_string_id::HOME_MENU_SETTINGS_INPUT_CAMERA_FLIP: return tr("Camera Flip", "Input"); case localized_string_id::HOME_MENU_SETTINGS_INPUT_PAD_MODE: return tr("Pad Handler Mode", "Input"); case localized_string_id::HOME_MENU_SETTINGS_INPUT_PAD_SLEEP: return tr("Pad Handler Sleep", "Input"); + case localized_string_id::HOME_MENU_SETTINGS_INPUT_FAKE_MOVE_ROTATION_CONE_H: return tr("Fake PS Move Rotation Cone (Horizontal)", "Input"); + case localized_string_id::HOME_MENU_SETTINGS_INPUT_FAKE_MOVE_ROTATION_CONE_V: return tr("Fake PS Move Rotation Cone (Vertical)", "Input"); case localized_string_id::HOME_MENU_SETTINGS_ADVANCED: return tr("Advanced"); case localized_string_id::HOME_MENU_SETTINGS_ADVANCED_PREFERRED_SPU_THREADS: return tr("Preferred SPU Threads", "Advanced"); case localized_string_id::HOME_MENU_SETTINGS_ADVANCED_MAX_CPU_PREEMPTIONS: return tr("Max Power Saving CPU-Preemptions", "Advanced"); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 09a09ce221..d3206b7bdb 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -2391,6 +2391,7 @@ void main_window::UpdateFilterActions() ui->showCatHomeAct->setChecked(m_gui_settings->GetCategoryVisibility(Category::Home, m_is_list_mode)); ui->showCatAudioVideoAct->setChecked(m_gui_settings->GetCategoryVisibility(Category::Media, m_is_list_mode)); ui->showCatGameDataAct->setChecked(m_gui_settings->GetCategoryVisibility(Category::Data, m_is_list_mode)); + ui->showCatOSAct->setChecked(m_gui_settings->GetCategoryVisibility(Category::OS, m_is_list_mode)); ui->showCatUnknownAct->setChecked(m_gui_settings->GetCategoryVisibility(Category::Unknown_Cat, m_is_list_mode)); ui->showCatOtherAct->setChecked(m_gui_settings->GetCategoryVisibility(Category::Others, m_is_list_mode)); } @@ -2551,6 +2552,7 @@ void main_window::CreateActions() m_category_visible_act_group->addAction(ui->showCatHomeAct); m_category_visible_act_group->addAction(ui->showCatAudioVideoAct); m_category_visible_act_group->addAction(ui->showCatGameDataAct); + m_category_visible_act_group->addAction(ui->showCatOSAct); m_category_visible_act_group->addAction(ui->showCatUnknownAct); m_category_visible_act_group->addAction(ui->showCatOtherAct); m_category_visible_act_group->setExclusive(false); @@ -3227,16 +3229,17 @@ void main_window::CreateConnects() const auto get_cats = [this](QAction* act, int& id) -> QStringList { QStringList categories; - if (act == ui->showCatHDDGameAct) { categories += cat::cat_hdd_game; id = Category::HDD_Game; } - else if (act == ui->showCatDiscGameAct) { categories += cat::cat_disc_game; id = Category::Disc_Game; } - else if (act == ui->showCatPS1GamesAct) { categories += cat::cat_ps1_game; id = Category::PS1_Game; } - else if (act == ui->showCatPS2GamesAct) { categories += cat::ps2_games; id = Category::PS2_Game; } - else if (act == ui->showCatPSPGamesAct) { categories += cat::psp_games; id = Category::PSP_Game; } - else if (act == ui->showCatHomeAct) { categories += cat::cat_home; id = Category::Home; } - else if (act == ui->showCatAudioVideoAct) { categories += cat::media; id = Category::Media; } - else if (act == ui->showCatGameDataAct) { categories += cat::data; id = Category::Data; } - else if (act == ui->showCatUnknownAct) { categories += cat::cat_unknown; id = Category::Unknown_Cat; } - else if (act == ui->showCatOtherAct) { categories += cat::others; id = Category::Others; } + if (act == ui->showCatHDDGameAct) { categories.append(cat::cat_hdd_game); id = Category::HDD_Game; } + else if (act == ui->showCatDiscGameAct) { categories.append(cat::cat_disc_game); id = Category::Disc_Game; } + else if (act == ui->showCatPS1GamesAct) { categories.append(cat::cat_ps1_game); id = Category::PS1_Game; } + else if (act == ui->showCatPS2GamesAct) { categories.append(cat::ps2_games); id = Category::PS2_Game; } + else if (act == ui->showCatPSPGamesAct) { categories.append(cat::psp_games); id = Category::PSP_Game; } + else if (act == ui->showCatHomeAct) { categories.append(cat::cat_home); id = Category::Home; } + else if (act == ui->showCatAudioVideoAct) { categories.append(cat::media); id = Category::Media; } + else if (act == ui->showCatGameDataAct) { categories.append(cat::data); id = Category::Data; } + else if (act == ui->showCatOSAct) { categories.append(cat::os); id = Category::OS; } + else if (act == ui->showCatUnknownAct) { categories.append(cat::cat_unknown); id = Category::Unknown_Cat; } + else if (act == ui->showCatOtherAct) { categories.append(cat::others); id = Category::Others; } else { gui_log.warning("categoryVisibleActGroup: category action not found"); } return categories; }; @@ -3276,6 +3279,7 @@ void main_window::CreateConnects() set_cat_count(ui->showCatHomeAct, tr("Home")); set_cat_count(ui->showCatAudioVideoAct, tr("Audio/Video")); set_cat_count(ui->showCatGameDataAct, tr("Game Data")); + set_cat_count(ui->showCatOSAct, tr("Operating System")); set_cat_count(ui->showCatUnknownAct, tr("Unknown")); set_cat_count(ui->showCatOtherAct, tr("Other")); }); diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui index 2d0396c499..ba29696974 100644 --- a/rpcs3/rpcs3qt/main_window.ui +++ b/rpcs3/rpcs3qt/main_window.ui @@ -355,6 +355,7 @@ + @@ -883,9 +884,6 @@ true - - true - HDD Games @@ -894,9 +892,6 @@ true - - true - Disc Games @@ -905,9 +900,6 @@ true - - true - PS1 Games @@ -916,9 +908,6 @@ true - - true - PS2 Games @@ -927,9 +916,6 @@ true - - true - PSP Games @@ -938,9 +924,6 @@ true - - true - Home @@ -949,9 +932,6 @@ true - - true - Audio/Video @@ -960,9 +940,6 @@ true - - true - Game Data @@ -971,9 +948,6 @@ true - - true - Unknown @@ -1090,9 +1064,6 @@ true - - true - Other @@ -1402,6 +1373,14 @@ PS Move + + + true + + + Operating System + + diff --git a/rpcs3/rpcs3qt/memory_viewer_panel.cpp b/rpcs3/rpcs3qt/memory_viewer_panel.cpp index c6c466155c..f9f246fbda 100644 --- a/rpcs3/rpcs3qt/memory_viewer_panel.cpp +++ b/rpcs3/rpcs3qt/memory_viewer_panel.cpp @@ -660,11 +660,11 @@ std::string memory_viewer_panel::getHeaderAtAddr(u32 addr) const if (spu_boundary <= addr + m_colcount * 4 - 1) { - std::shared_ptr> spu; + shared_ptr> spu; if (const u32 raw_spu_index = (spu_boundary - RAW_SPU_BASE_ADDR) / SPU_LS_SIZE; raw_spu_index < 5) { - spu = idm::get>(spu_thread::find_raw_spu(raw_spu_index)); + spu = idm::get_unlocked>(spu_thread::find_raw_spu(raw_spu_index)); if (spu && spu->get_type() == spu_type::threaded) { @@ -673,7 +673,7 @@ std::string memory_viewer_panel::getHeaderAtAddr(u32 addr) const } else if (const u32 spu_index = (spu_boundary - SPU_FAKE_BASE_ADDR) / SPU_LS_SIZE; spu_index < spu_thread::id_count) { - spu = idm::get>(spu_thread::id_base | spu_index); + spu = idm::get_unlocked>(spu_thread::id_base | spu_index); if (spu && spu->get_type() != spu_type::threaded) { diff --git a/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp b/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp index a553656c43..45fbe6f59e 100644 --- a/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp +++ b/rpcs3/rpcs3qt/ps_move_tracker_dialog.cpp @@ -362,8 +362,7 @@ void ps_move_tracker_dialog::update_saturation_threshold(bool update_slider) } void ps_move_tracker_dialog::update_min_radius(bool update_slider) { - const f32 min_radius = std::clamp(g_cfg_move.min_radius / min_radius_conversion, g_cfg_move.min_radius.min, g_cfg_move.min_radius.max); - ui->minRadiusGb->setTitle(tr("Min Radius: %0 %").arg(min_radius)); + ui->minRadiusGb->setTitle(tr("Min Radius: %0 %").arg(g_cfg_move.min_radius)); if (update_slider) { @@ -373,8 +372,7 @@ void ps_move_tracker_dialog::update_min_radius(bool update_slider) void ps_move_tracker_dialog::update_max_radius(bool update_slider) { - const f32 max_radius = std::clamp(g_cfg_move.max_radius / max_radius_conversion, g_cfg_move.max_radius.min, g_cfg_move.max_radius.max); - ui->maxRadiusGb->setTitle(tr("Max Radius: %0 %").arg(max_radius)); + ui->maxRadiusGb->setTitle(tr("Max Radius: %0 %").arg(g_cfg_move.max_radius)); if (update_slider) { @@ -467,8 +465,8 @@ void ps_move_tracker_dialog::process_camera_frame() } m_ps_move_tracker->set_image_data(m_frame_frozen ? m_image_data_frozen.data() : m_image_data.data(), m_image_data.size(), width, height, m_camera_handler->format()); - m_ps_move_tracker->set_min_radius(static_cast(g_cfg_move.min_radius.get() / g_cfg_move.min_radius.max)); - m_ps_move_tracker->set_max_radius(static_cast(g_cfg_move.max_radius.get() / g_cfg_move.max_radius.max)); + m_ps_move_tracker->set_min_radius(static_cast(g_cfg_move.min_radius) / 100.0f); + m_ps_move_tracker->set_max_radius(static_cast(g_cfg_move.max_radius) / 100.0f); m_ps_move_tracker->set_filter_small_contours(m_filter_small_contours); m_ps_move_tracker->set_show_all_contours(m_show_all_contours); m_ps_move_tracker->set_draw_contours(m_draw_contours); diff --git a/rpcs3/rpcs3qt/qt_camera_handler.cpp b/rpcs3/rpcs3qt/qt_camera_handler.cpp index f0d11f937c..88d8c15963 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.cpp +++ b/rpcs3/rpcs3qt/qt_camera_handler.cpp @@ -47,6 +47,7 @@ void qt_camera_handler::set_camera(const QCameraDevice& camera_info) { if (camera_info.isNull()) { + set_expected_state(camera_handler_state::closed); reset(); return; } @@ -57,9 +58,9 @@ void qt_camera_handler::set_camera(const QCameraDevice& camera_info) camera_log.success("Using camera: id=\"%s\", description=\"%s\", front_facing=%d", camera_info.id().toStdString(), camera_info.description(), front_facing); // Create camera and video surface - m_media_capture_session.reset(new QMediaCaptureSession(nullptr)); - m_video_sink.reset(new qt_camera_video_sink(front_facing, nullptr)); - m_camera.reset(new QCamera(camera_info)); + m_media_capture_session = std::make_unique(nullptr); + m_video_sink = std::make_unique(front_facing, nullptr); + m_camera = std::make_unique(camera_info); connect(m_camera.get(), &QCamera::activeChanged, this, &qt_camera_handler::handle_camera_active); connect(m_camera.get(), &QCamera::errorOccurred, this, &qt_camera_handler::handle_camera_error); @@ -76,14 +77,37 @@ void qt_camera_handler::handle_camera_active(bool is_active) { camera_log.notice("Camera active status changed to %d", is_active); - if (is_active) + // Check if the camera does what it's supposed to do. + const camera_handler_state expected_state = get_expected_state(); + + switch (expected_state) { - m_state = camera_handler_state::running; - } - else + case camera_handler_state::closed: + case camera_handler_state::open: { - m_state = camera_handler_state::closed; + if (is_active) + { + // This is not supposed to happen and indicates an unexpected QCamera issue + camera_log.error("Camera started unexpectedly"); + set_state(camera_handler_state::running); + return; + } + break; } + case camera_handler_state::running: + { + if (!is_active) + { + // This is not supposed to happen and indicates an unexpected QCamera issue + camera_log.error("Camera stopped unexpectedly"); + set_state(camera_handler_state::open); + return; + } + break; + } + } + + set_state(expected_state); } void qt_camera_handler::handle_camera_error(QCamera::Error error, const QString& errorString) @@ -100,7 +124,11 @@ void qt_camera_handler::open_camera() { camera_log.notice("Switching camera from %s to %s", m_camera_id, camera_id); camera_log.notice("Stopping old camera..."); - if (m_camera) m_camera->stop(); + if (m_camera) + { + set_expected_state(camera_handler_state::open); + m_camera->stop(); + } m_camera_id = camera_id; } @@ -129,7 +157,7 @@ void qt_camera_handler::open_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } @@ -148,7 +176,7 @@ void qt_camera_handler::open_camera() // Update camera and view finder settings update_camera_settings(); - m_state = camera_handler_state::open; + set_state(camera_handler_state::open); } void qt_camera_handler::close_camera() @@ -159,11 +187,12 @@ void qt_camera_handler::close_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } // Unload/close camera + set_expected_state(camera_handler_state::closed); m_camera->stop(); } @@ -175,7 +204,7 @@ void qt_camera_handler::start_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } @@ -206,6 +235,7 @@ void qt_camera_handler::start_camera() #endif // Start camera. We will start receiving frames now. + set_expected_state(camera_handler_state::running); m_camera->start(); } @@ -217,7 +247,7 @@ void qt_camera_handler::stop_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } @@ -228,6 +258,7 @@ void qt_camera_handler::stop_camera() } // Stop camera. The camera will still be drawing power. + set_expected_state(camera_handler_state::open); m_camera->stop(); } @@ -284,26 +315,26 @@ camera_handler_base::camera_handler_state qt_camera_handler::get_image(u8* buf, m_camera_id != camera_id) { camera_log.notice("Switching cameras"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return camera_handler_state::closed; } if (m_camera_id.empty()) { camera_log.notice("Camera disabled"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return camera_handler_state::closed; } if (!m_camera || !m_video_sink) { camera_log.fatal("Error: camera invalid"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return camera_handler_state::closed; } // Backup current state. State may change through events. - const camera_handler_state current_state = m_state; + const camera_handler_state current_state = get_state(); if (current_state == camera_handler_state::running) { diff --git a/rpcs3/rpcs3qt/qt_camera_handler.h b/rpcs3/rpcs3qt/qt_camera_handler.h index d828bd6c84..0759d739c6 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.h +++ b/rpcs3/rpcs3qt/qt_camera_handler.h @@ -17,8 +17,6 @@ public: qt_camera_handler(); virtual ~qt_camera_handler(); - void set_camera(const QCameraDevice& camera_info); - void open_camera() override; void close_camera() override; void start_camera() override; @@ -31,11 +29,12 @@ public: camera_handler_state get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) override; private: + void set_camera(const QCameraDevice& camera_info); void reset(); void update_camera_settings(); std::string m_camera_id; - std::shared_ptr m_camera; + std::unique_ptr m_camera; std::unique_ptr m_media_capture_session; std::unique_ptr m_video_sink; diff --git a/rpcs3/rpcs3qt/recvmessage_dialog_frame.cpp b/rpcs3/rpcs3qt/recvmessage_dialog_frame.cpp index 6b549d3e23..b617d74d95 100644 --- a/rpcs3/rpcs3qt/recvmessage_dialog_frame.cpp +++ b/rpcs3/rpcs3qt/recvmessage_dialog_frame.cpp @@ -12,7 +12,7 @@ LOG_CHANNEL(recvmessage_dlg_log, "recvmessage dlg"); -void recvmessage_callback(void* param, std::shared_ptr> new_msg, u64 msg_id) +void recvmessage_callback(void* param, shared_ptr> new_msg, u64 msg_id) { auto* dlg = static_cast(param); dlg->callback_handler(std::move(new_msg), msg_id); @@ -132,7 +132,7 @@ error_code recvmessage_dialog_frame::Exec(SceNpBasicMessageMainType type, SceNpB return result; } -void recvmessage_dialog_frame::add_message(const std::shared_ptr>& msg, u64 msg_id) +void recvmessage_dialog_frame::add_message(const shared_ptr>& msg, u64 msg_id) { ensure(msg); auto new_item = new QListWidgetItem(QString::fromStdString(msg->first)); @@ -145,7 +145,7 @@ void recvmessage_dialog_frame::slot_new_message(recvmessage_signal_struct msg_an add_message(msg_and_id.msg, msg_and_id.msg_id); } -void recvmessage_dialog_frame::callback_handler(std::shared_ptr> new_msg, u64 msg_id) +void recvmessage_dialog_frame::callback_handler(shared_ptr> new_msg, u64 msg_id) { recvmessage_signal_struct signal_struct = { .msg = new_msg, diff --git a/rpcs3/rpcs3qt/recvmessage_dialog_frame.h b/rpcs3/rpcs3qt/recvmessage_dialog_frame.h index f17f3afd73..28255253dd 100644 --- a/rpcs3/rpcs3qt/recvmessage_dialog_frame.h +++ b/rpcs3/rpcs3qt/recvmessage_dialog_frame.h @@ -9,7 +9,7 @@ struct recvmessage_signal_struct { - std::shared_ptr> msg; + shared_ptr> msg; u64 msg_id; }; @@ -23,10 +23,10 @@ public: recvmessage_dialog_frame() = default; ~recvmessage_dialog_frame(); error_code Exec(SceNpBasicMessageMainType type, SceNpBasicMessageRecvOptions options, SceNpBasicMessageRecvAction& recv_result, u64& chosen_msg_id) override; - void callback_handler(const std::shared_ptr> new_msg, u64 msg_id) override; + void callback_handler(const shared_ptr> new_msg, u64 msg_id) override; private: - void add_message(const std::shared_ptr>& msg, u64 msg_id); + void add_message(const shared_ptr>& msg, u64 msg_id); Q_SIGNALS: void signal_new_message(const recvmessage_signal_struct msg_and_id); diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index aa3245ba8d..6d17c7e9a5 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -94,7 +94,7 @@ void remove_item(QComboBox* box, int data_value, int def_value) extern const std::map g_prx_list; -settings_dialog::settings_dialog(std::shared_ptr gui_settings, std::shared_ptr emu_settings, const int& tab_index, QWidget* parent, const GameInfo* game, bool create_cfg_from_global_cfg) +settings_dialog::settings_dialog(std::shared_ptr gui_settings, std::shared_ptr emu_settings, int tab_index, QWidget* parent, const GameInfo* game, bool create_cfg_from_global_cfg) : QDialog(parent) , m_tab_index(tab_index) , ui(new Ui::settings_dialog) @@ -1593,6 +1593,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std ui->disableMslFastMath->setVisible(false); #endif + m_emu_settings->EnhanceCheckBox(ui->disableAsyncHostMM, emu_settings_type::DisableAsyncHostMM); + SubscribeTooltip(ui->disableAsyncHostMM, tooltips.settings.disable_async_host_mm); + // Comboboxes m_emu_settings->EnhanceComboBox(ui->maxSPURSThreads, emu_settings_type::MaxSPURSThreads, true); @@ -2604,14 +2607,11 @@ void settings_dialog::ApplyStylesheet(bool reset) } } -int settings_dialog::exec() +void settings_dialog::open() { - // singleShot Hack to fix following bug: - // If we use setCurrentIndex now we will miraculously see a resize of the dialog as soon as we - // switch to the cpu tab after conjuring the settings_dialog with another tab opened first. - // Weirdly enough this won't happen if we change the tab order so that anything else is at index 0. - ui->tab_widget_settings->setCurrentIndex(0); - QTimer::singleShot(0, [this]{ ui->tab_widget_settings->setCurrentIndex(m_tab_index); }); + QDialog::open(); + + ui->tab_widget_settings->setCurrentIndex(m_tab_index); // Open a dialog if your config file contained invalid entries QTimer::singleShot(10, [this] @@ -2637,8 +2637,6 @@ int settings_dialog::exec() } } }); - - return QDialog::exec(); } void settings_dialog::SubscribeDescription(QLabel* description) diff --git a/rpcs3/rpcs3qt/settings_dialog.h b/rpcs3/rpcs3qt/settings_dialog.h index 203fd1c8f9..0513227e80 100644 --- a/rpcs3/rpcs3qt/settings_dialog.h +++ b/rpcs3/rpcs3qt/settings_dialog.h @@ -21,9 +21,9 @@ class settings_dialog : public QDialog Q_OBJECT public: - explicit settings_dialog(std::shared_ptr gui_settings, std::shared_ptr emu_settings, const int& tab_index = 0, QWidget* parent = nullptr, const GameInfo* game = nullptr, bool create_cfg_from_global_cfg = true); + explicit settings_dialog(std::shared_ptr gui_settings, std::shared_ptr emu_settings, int tab_index = 0, QWidget* parent = nullptr, const GameInfo* game = nullptr, bool create_cfg_from_global_cfg = true); ~settings_dialog(); - int exec() override; + void open() override; Q_SIGNALS: void GuiStylesheetRequest(); void GuiRepaintRequest(); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 74c5629092..66b3b32088 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -2695,6 +2695,13 @@ + + + + Disable Asynchronous Memory Manager + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 99de286ec2..c6bfa15cf7 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -40,6 +40,7 @@ public: const QString allow_host_labels = tr("Allows the host GPU to synchronize with CELL directly. This incurs a performance penalty, but exposes the true state of GPU objects to the guest CPU. Can help eliminate visual noise and glitching at the cost of performance. Use with caution."); const QString force_hw_MSAA = tr("Forces MSAA to use the host GPU's resolve capabilities for all sampling operations.\nThis option incurs a performance penalty as well as the risk of visual artifacts but can yield crisper visuals when MSAA is enabled."); const QString disable_vertex_cache = tr("Disables the vertex cache.\nMight resolve missing or flickering graphics output.\nMay degrade performance."); + const QString disable_async_host_mm = tr("Force host memory management calls to be inlined instead of handled asynchronously.\nThis can cause severe performance degradation and stuttering in some games.\nThis option is only needed by developers to debug problems with texture cache memory protection."); const QString zcull_operation_mode = tr("Changes ZCULL report synchronization behaviour. Experiment to find the best option for your game. Approximate mode is recommended for most games.\n· Precise is the most accurate to PS3 behaviour. Required for accurate visuals in some titles such as Demon's Souls and The Darkness.\n· Approximate is a much faster way to generate occlusion data which may not always match what the PS3 would generate. Works well with most PS3 games.\n· Relaxed changes the synchronization method completely and can greatly improve performance in some games or completely break others."); const QString max_spurs_threads = tr("Limits the maximum number of SPURS threads in each thread group.\nMay improve performance in some cases, especially on systems with limited number of hardware threads.\nLimiting the number of threads is likely to cause crashes; it's recommended to keep this at the default value."); const QString sleep_timers_accuracy = tr("Changes the sleep period accuracy.\n'As Host' uses default accuracy of the underlying operating system, while 'All Timers' attempts to improve it.\n'Usleep Only' limits the adjustments to usleep syscall only.\nCan affect performance in unexpected ways."); diff --git a/rpcs3/rpcs3qt/update_manager.cpp b/rpcs3/rpcs3qt/update_manager.cpp index 7d15aadbdd..cdd7b4a0e1 100644 --- a/rpcs3/rpcs3qt/update_manager.cpp +++ b/rpcs3/rpcs3qt/update_manager.cpp @@ -13,6 +13,7 @@ #include "util/types.hpp" #include +#include #include #include #include @@ -232,29 +233,31 @@ bool update_manager::handle_json(bool automatic, bool check_only, bool auto_acce const Localized localized; - m_new_version = latest["version"].toString().toStdString(); + const QString new_version = latest["version"].toString(); + m_new_version = new_version.toStdString(); const QString support_message = tr("
You can empower our project at RPCS3 Patreon.
"); if (hash_found) { - m_old_version = current["version"].toString().toStdString(); + const QString old_version = current["version"].toString(); + m_old_version = old_version.toStdString(); if (diff_msec < 0) { // This usually means that the current version was marked as broken and won't be shipped anymore, so we need to downgrade to avoid certain bugs. m_update_message = tr("A better version of RPCS3 is available!

Current version: %0 (%1)
Better version: %2 (%3)
%4
Do you want to update?") - .arg(current["version"].toString()) + .arg(old_version) .arg(cur_str) - .arg(latest["version"].toString()) + .arg(new_version) .arg(lts_str) .arg(support_message); } else { m_update_message = tr("A new version of RPCS3 is available!

Current version: %0 (%1)
Latest version: %2 (%3)
Your version is %4 behind.
%5
Do you want to update?") - .arg(current["version"].toString()) + .arg(old_version) .arg(cur_str) - .arg(latest["version"].toString()) + .arg(new_version) .arg(lts_str) .arg(localized.GetVerboseTimeByMs(diff_msec, true)) .arg(support_message); @@ -265,7 +268,7 @@ bool update_manager::handle_json(bool automatic, bool check_only, bool auto_acce m_old_version = fmt::format("%s-%s-%s", rpcs3::get_full_branch(), rpcs3::get_branch(), rpcs3::get_version().to_string()); m_update_message = tr("You're currently using a custom or PR build.

Latest version: %0 (%1)
The latest version is %2 old.
%3
Do you want to update to the latest official RPCS3 version?") - .arg(latest["version"].toString()) + .arg(new_version) .arg(lts_str) .arg(localized.GetVerboseTimeByMs(std::abs(diff_msec), true)) .arg(support_message); @@ -285,6 +288,13 @@ bool update_manager::handle_json(bool automatic, bool check_only, bool auto_acce if (!auto_accept) { + if (automatic && m_gui_settings->GetValue(gui::ib_skip_version).toString() == new_version) + { + update_log.notice("Skipping automatic update notification for version '%s' due to user preference", new_version); + m_downloader->close_progress_dialog(); + return true; + } + const auto& changelog = json_data["changelog"]; if (changelog.isArray()) @@ -372,6 +382,7 @@ void update_manager::update(bool auto_accept) QMessageBox mb(QMessageBox::Icon::Question, tr("Update Available"), m_update_message, QMessageBox::Yes | QMessageBox::No, m_downloader->get_progress_dialog() ? m_downloader->get_progress_dialog() : m_parent); mb.setTextFormat(Qt::RichText); + mb.setCheckBox(new QCheckBox(tr("Don't show again for this version"))); if (!changelog_content.isEmpty()) { @@ -397,6 +408,13 @@ void update_manager::update(bool auto_accept) if (mb.exec() == QMessageBox::No) { update_log.notice("Aborting update: User declined update"); + + if (mb.checkBox()->isChecked()) + { + update_log.notice("User requested to skip further automatic update notifications for version '%s'", m_new_version); + m_gui_settings->SetValue(gui::ib_skip_version, QString::fromStdString(m_new_version)); + } + m_downloader->close_progress_dialog(); return; } diff --git a/rpcs3/rpcs3qt/user_account.h b/rpcs3/rpcs3qt/user_account.h index 46991f7565..dd2e1a3d3c 100644 --- a/rpcs3/rpcs3qt/user_account.h +++ b/rpcs3/rpcs3qt/user_account.h @@ -14,9 +14,9 @@ class user_account public: explicit user_account(const std::string& user_id = "00000001"); - std::string GetUserId() const { return m_user_id; } - std::string GetUserDir() const { return m_user_dir; } - std::string GetUsername() const { return m_username; } + const std::string& GetUserId() const { return m_user_id; } + const std::string& GetUserDir() const { return m_user_dir; } + const std::string& GetUsername() const { return m_username; } static std::map GetUserAccounts(const std::string& base_dir); diff --git a/rpcs3/util/logs.cpp b/rpcs3/util/logs.cpp index 764dbc7efc..79ae9e8f4c 100644 --- a/rpcs3/util/logs.cpp +++ b/rpcs3/util/logs.cpp @@ -789,7 +789,7 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st case level::trace: text = reinterpret_cast(u8"·T "); break; } - // Print µs timestamp + // Print microsecond timestamp const u64 hours = stamp / 3600'000'000; const u64 mins = (stamp % 3600'000'000) / 60'000'000; const u64 secs = (stamp % 60'000'000) / 1'000'000; diff --git a/rpcs3/util/serialization.hpp b/rpcs3/util/serialization.hpp index a231a22ee8..120c70c606 100644 --- a/rpcs3/util/serialization.hpp +++ b/rpcs3/util/serialization.hpp @@ -96,6 +96,29 @@ public: return m_is_writing; } + void add_padding(usz padding) + { + if (m_is_writing) return; + pos += padding; + } + + // Add padding needed between two members + template + void add_padding(T T2::*const first, T3 T2::*const second) + { + if (m_is_writing) return; + + const u32 offset1 = ::offset32(first) + sizeof(T); + const u32 offset2 = ::offset32(second); + + AUDIT(::offset32(first) <= ::offset32(second)); + + if (offset2 > offset1) + { + pos += offset2 - offset1; + } + } + void set_expect_little_data(bool value) { m_expect_little_data = value; @@ -436,10 +459,16 @@ public: m_file_handler.reset(); } - usz seek_end(usz backwards = 0) + usz seek_end() { - ensure(data.size() + data_offset >= backwards); - pos = data.size() + data_offset - backwards; + pos = data.size() + data_offset; + return pos; + } + + usz trunc(usz count) + { + data.resize(data.size() - count); + seek_end(); return pos; } diff --git a/rpcs3/util/shared_ptr.hpp b/rpcs3/util/shared_ptr.hpp index 70bac278e3..06f1d2a380 100644 --- a/rpcs3/util/shared_ptr.hpp +++ b/rpcs3/util/shared_ptr.hpp @@ -2,13 +2,14 @@ #include #include +#include #include "atomic.hpp" #include "bless.hpp" namespace stx { template - constexpr bool same_ptr_implicit_v = std::is_convertible_v ? is_same_ptr() : false; + constexpr bool same_ptr_implicit_v = std::is_convertible_v ? PtrSame : false; template class single_ptr; @@ -126,7 +127,7 @@ namespace stx r.m_ptr = nullptr; } - ~single_ptr() + ~single_ptr() noexcept { reset(); } @@ -153,6 +154,7 @@ namespace stx if (m_ptr) [[likely]] { const auto o = d(); + ensure(o->refs == 1); o->destroy.load()(o); m_ptr = nullptr; } @@ -168,7 +170,7 @@ namespace stx return m_ptr; } - decltype(auto) operator*() const noexcept requires (!std::is_void_v) + element_type& operator*() const noexcept requires (!std::is_void_v) { return *m_ptr; } @@ -178,16 +180,9 @@ namespace stx return m_ptr; } - decltype(auto) operator[](std::ptrdiff_t idx) const noexcept requires (!std::is_void_v) + element_type& operator[](std::ptrdiff_t idx) const noexcept requires (!std::is_void_v && std::is_array_v) { - if constexpr (std::is_array_v) - { - return m_ptr[idx]; - } - else - { - return *m_ptr; - } + return m_ptr[idx]; } template requires (std::is_invocable_v) @@ -196,11 +191,6 @@ namespace stx return std::invoke(*m_ptr, std::forward(args)...); } - operator element_type*() const noexcept - { - return m_ptr; - } - explicit constexpr operator bool() const noexcept { return m_ptr != nullptr; @@ -214,6 +204,12 @@ namespace stx r.m_ptr = static_cast(std::exchange(m_ptr, nullptr)); return r; } + + template requires same_ptr_implicit_v + bool operator==(const single_ptr& r) const noexcept + { + return get() == r.get(); + } }; #ifndef _MSC_VER @@ -222,7 +218,8 @@ namespace stx #endif template - static std::enable_if_t) && (Init || !sizeof...(Args)), single_ptr> make_single(Args&&... args) noexcept + requires(!std::is_unbounded_array_v && (Init || std::is_array_v) && (Init || !sizeof...(Args))) + static single_ptr make_single(Args&&... args) noexcept { static_assert(offsetof(shared_data, m_data) - offsetof(shared_data, m_ctr) == sizeof(shared_counter)); @@ -230,7 +227,7 @@ namespace stx shared_data* ptr = nullptr; - if constexpr (Init && !std::is_array_v) + if constexpr (!std::is_array_v) { ptr = new shared_data(std::forward(args)...); } @@ -258,7 +255,8 @@ namespace stx } template )> - static std::enable_if_t, single_ptr> make_single(usz count) noexcept + requires (std::is_unbounded_array_v && std::is_default_constructible_v>) + static single_ptr make_single(usz count) noexcept { static_assert(sizeof(shared_data) - offsetof(shared_data, m_ctr) == sizeof(shared_counter)); @@ -397,7 +395,7 @@ namespace stx r.m_ptr = nullptr; } - ~shared_ptr() + ~shared_ptr() noexcept { reset(); } @@ -440,32 +438,31 @@ namespace stx // Set to null void reset() noexcept { - const auto o = d(); - - if (m_ptr && !--o->refs) [[unlikely]] + if (m_ptr) [[unlikely]] { - o->destroy(o); + const auto o = d(); + + if (!--o->refs) + { + o->destroy(o); + } + m_ptr = nullptr; } } - // Converts to unique (single) ptr if reference is 1, otherwise returns null. Nullifies self. + // Converts to unique (single) ptr if reference is 1. Nullifies self on success. template requires PtrSame - explicit operator single_ptr() && noexcept + single_ptr try_convert_to_single_ptr() noexcept { - const auto o = d(); - - if (m_ptr && !--o->refs) + if (const auto o = m_ptr ? d() : nullptr; o && o->refs == 1u) { // Convert last reference to single_ptr instance. - o->refs.release(1); - single_ptr r; + single_ptr r; r.m_ptr = static_cast(std::exchange(m_ptr, nullptr)); return r; } - // Otherwise, both pointers are gone. Didn't seem right to do it in the constructor. - m_ptr = nullptr; return {}; } @@ -479,7 +476,7 @@ namespace stx return m_ptr; } - decltype(auto) operator*() const noexcept requires (!std::is_void_v) + element_type& operator*() const noexcept requires (!std::is_void_v) { return *m_ptr; } @@ -489,16 +486,9 @@ namespace stx return m_ptr; } - decltype(auto) operator[](std::ptrdiff_t idx) const noexcept requires (!std::is_void_v) + element_type& operator[](std::ptrdiff_t idx) const noexcept requires (!std::is_void_v && std::is_array_v) { - if constexpr (std::is_array_v) - { - return m_ptr[idx]; - } - else - { - return *m_ptr; - } + return m_ptr[idx]; } template requires (std::is_invocable_v) @@ -519,11 +509,6 @@ namespace stx } } - operator element_type*() const noexcept - { - return m_ptr; - } - explicit constexpr operator bool() const noexcept { return m_ptr != nullptr; @@ -551,21 +536,30 @@ namespace stx r.m_ptr = static_cast(std::exchange(m_ptr, nullptr)); return r; } + + template requires same_ptr_implicit_v + bool operator==(const shared_ptr& r) const noexcept + { + return get() == r.get(); + } }; - template - static std::enable_if_t && (!Init || !sizeof...(Args)), shared_ptr> make_shared(Args&&... args) noexcept + template + requires(!std::is_unbounded_array_v && std::is_constructible_v, Args&& ...>) + static shared_ptr make_shared(Args&&... args) noexcept { - return make_single(std::forward(args)...); + return make_single(std::forward(args)...); } template - static std::enable_if_t, shared_ptr> make_shared(usz count) noexcept + requires (std::is_unbounded_array_v && std::is_default_constructible_v>) + static shared_ptr make_shared(usz count) noexcept { return make_single(count); } template + requires (std::is_constructible_v, T&&>) static shared_ptr> make_shared_value(T&& value) { return make_single_value(std::forward(value)); @@ -577,7 +571,7 @@ namespace stx { mutable atomic_t m_val{0}; - static shared_counter* d(uptr val) + static shared_counter* d(uptr val) noexcept { return std::launder(reinterpret_cast((val >> c_ref_size) - sizeof(shared_counter))); } @@ -587,9 +581,32 @@ namespace stx return d(m_val); } + static uptr to_val(const volatile std::remove_extent_t* ptr) noexcept + { + return (reinterpret_cast(ptr) << c_ref_size); + } + + static std::remove_extent_t* ptr_to(uptr val) noexcept + { + return reinterpret_cast*>(val >> c_ref_size); + } + template friend class atomic_ptr; + // Helper struct to check if a type is an instance of a template + template class Template> + struct is_instance_of : std::false_type {}; + + template class Template> + struct is_instance_of, Template> : std::true_type {}; + + template + static constexpr bool is_stx_pointer = false + || is_instance_of, shared_ptr>::value + || is_instance_of, single_ptr>::value + || is_instance_of, atomic_ptr>::value; + public: using element_type = std::remove_extent_t; @@ -598,11 +615,14 @@ namespace stx constexpr atomic_ptr() noexcept = default; // Optimized value construct - template requires (!(sizeof...(Args) == 1 && (std::is_same_v, shared_type> || ...)) && std::is_constructible_v) + template requires (true + && sizeof...(Args) != 0 + && !(sizeof...(Args) == 1 && (is_stx_pointer || ...)) + && std::is_constructible_v) explicit atomic_ptr(Args&&... args) noexcept { shared_type r = make_single(std::forward(args)...); - m_val = reinterpret_cast(std::exchange(r.m_ptr, nullptr)) << c_ref_size; + m_val.raw() = to_val(std::exchange(r.m_ptr, nullptr)); d()->refs.raw() += c_ref_mask; } @@ -610,50 +630,60 @@ namespace stx atomic_ptr(const shared_ptr& r) noexcept { // Obtain a ref + as many refs as an atomic_ptr can additionally reference - m_val = reinterpret_cast(r.m_ptr) << c_ref_size; - if (m_val) - d()->refs += c_ref_mask + 1; + if (uptr rval = to_val(r.m_ptr)) + { + m_val.raw() = rval; + d(rval)->refs += c_ref_mask + 1; + } } template requires same_ptr_implicit_v atomic_ptr(shared_ptr&& r) noexcept { - m_val = reinterpret_cast(r.m_ptr) << c_ref_size; - r.m_ptr = nullptr; + if (uptr rval = to_val(r.m_ptr)) + { + m_val.raw() = rval; + d(rval)->refs += c_ref_mask; + } - if (m_val) - d()->refs += c_ref_mask; + r.m_ptr = nullptr; } template requires same_ptr_implicit_v atomic_ptr(single_ptr&& r) noexcept { - m_val = reinterpret_cast(r.m_ptr) << c_ref_size; - r.m_ptr = nullptr; + if (uptr rval = to_val(r.m_ptr)) + { + m_val.raw() = rval; + d(rval)->refs += c_ref_mask; + } - if (m_val) - d()->refs += c_ref_mask; + r.m_ptr = nullptr; } - ~atomic_ptr() + ~atomic_ptr() noexcept { const uptr v = m_val.raw(); - const auto o = d(v); - if (v >> c_ref_size && !o->refs.sub_fetch(c_ref_mask + 1 - (v & c_ref_mask))) + if (v >> c_ref_size) { - o->destroy.load()(o); + const auto o = d(v); + + if (!o->refs.sub_fetch(c_ref_mask + 1 - (v & c_ref_mask))) + { + o->destroy.load()(o); + } } } // Optimized value assignment - atomic_ptr& operator=(std::remove_cv_t value) noexcept + atomic_ptr& operator=(std::remove_cv_t value) noexcept requires (!is_stx_pointer) { shared_type r = make_single(std::move(value)); r.d()->refs.raw() += c_ref_mask; atomic_ptr old; - old.m_val.raw() = m_val.exchange(reinterpret_cast(std::exchange(r.m_ptr, nullptr)) << c_ref_size); + old.m_val.raw() = m_val.exchange(to_val(std::exchange(r.m_ptr, nullptr))); return *this; } @@ -706,7 +736,7 @@ namespace stx } // Set referenced pointer - r.m_ptr = std::launder(reinterpret_cast(prev >> c_ref_size)); + r.m_ptr = std::launder(ptr_to(prev)); r.d()->refs++; // Dereference if still the same pointer @@ -751,7 +781,7 @@ namespace stx // Set fake unreferenced pointer if (did_ref) { - r.m_ptr = std::launder(reinterpret_cast(prev >> c_ref_size)); + r.m_ptr = std::launder(ptr_to(prev)); } // Result temp storage @@ -807,14 +837,17 @@ namespace stx // Create an object from variadic args // If a type needs shared_type to be constructed, std::reference_wrapper can be used - template requires (!(sizeof...(Args) == 1 && (std::is_same_v, shared_type> || ...)) && std::is_constructible_v) + template requires (true + && sizeof...(Args) != 0 + && !(sizeof...(Args) == 1 && (is_stx_pointer || ...)) + && std::is_constructible_v) void store(Args&&... args) noexcept { shared_type r = make_single(std::forward(args)...); r.d()->refs.raw() += c_ref_mask; atomic_ptr old; - old.m_val.raw() = m_val.exchange(reinterpret_cast(std::exchange(r.m_ptr, nullptr)) << c_ref_size); + old.m_val.raw() = m_val.exchange(to_val(std::exchange(r.m_ptr, nullptr))); } void store(shared_type value) noexcept @@ -826,20 +859,23 @@ namespace stx } atomic_ptr old; - old.m_val.raw() = m_val.exchange(reinterpret_cast(std::exchange(value.m_ptr, nullptr)) << c_ref_size); + old.m_val.raw() = m_val.exchange(to_val(std::exchange(value.m_ptr, nullptr))); } - template requires (!(sizeof...(Args) == 1 && (std::is_same_v, shared_type> || ...)) && std::is_constructible_v) + template requires (true + && sizeof...(Args) != 0 + && !(sizeof...(Args) == 1 && (is_stx_pointer || ...)) + && std::is_constructible_v) [[nodiscard]] shared_type exchange(Args&&... args) noexcept { shared_type r = make_single(std::forward(args)...); r.d()->refs.raw() += c_ref_mask; atomic_ptr old; - old.m_val.raw() += m_val.exchange(reinterpret_cast(r.m_ptr) << c_ref_size); + old.m_val.raw() = m_val.exchange(to_val(r.m_ptr)); old.m_val.raw() += 1; - r.m_ptr = std::launder(reinterpret_cast(old.m_val >> c_ref_size)); + r.m_ptr = std::launder(ptr_to(old.m_val)); return r; } @@ -852,10 +888,10 @@ namespace stx } atomic_ptr old; - old.m_val.raw() += m_val.exchange(reinterpret_cast(value.m_ptr) << c_ref_size); + old.m_val.raw() = m_val.exchange(to_val(value.m_ptr)); old.m_val.raw() += 1; - value.m_ptr = std::launder(reinterpret_cast(old.m_val >> c_ref_size)); + value.m_ptr = std::launder(ptr_to(old.m_val)); return value; } @@ -900,10 +936,10 @@ namespace stx } atomic_ptr old_exch; - old_exch.m_val.raw() = reinterpret_cast(std::exchange(exch.m_ptr, nullptr)) << c_ref_size; + old_exch.m_val.raw() = to_val(std::exchange(exch.m_ptr, nullptr)); // Set to reset old cmp_and_old value - old.m_val.raw() = (reinterpret_cast(cmp_and_old.m_ptr) << c_ref_size) | c_ref_mask; + old.m_val.raw() = to_val(cmp_and_old.m_ptr) | c_ref_mask; if (!_val) { @@ -911,7 +947,7 @@ namespace stx } // Set referenced pointer - cmp_and_old.m_ptr = std::launder(reinterpret_cast(_val >> c_ref_size)); + cmp_and_old.m_ptr = std::launder(ptr_to(_val)); cmp_and_old.d()->refs++; // Dereference if still the same pointer @@ -979,7 +1015,7 @@ namespace stx } // Failure (return references) - old.m_val.raw() = reinterpret_cast(std::exchange(exch.m_ptr, nullptr)) << c_ref_size; + old.m_val.raw() = to_val(std::exchange(exch.m_ptr, nullptr)); return false; } @@ -1035,9 +1071,9 @@ namespace stx } // Simple atomic load is much more effective than load(), but it's a non-owning reference - const volatile void* observe() const noexcept + T* observe() const noexcept { - return reinterpret_cast(m_val >> c_ref_size); + return reinterpret_cast(m_val >> c_ref_size); } explicit constexpr operator bool() const noexcept @@ -1048,13 +1084,13 @@ namespace stx template requires same_ptr_implicit_v bool is_equal(const shared_ptr& r) const noexcept { - return observe() == r.get(); + return static_cast(observe()) == r.get(); } template requires same_ptr_implicit_v bool is_equal(const single_ptr& r) const noexcept { - return observe() == r.get(); + return static_cast(observe()) == r.get(); } void wait(std::nullptr_t, atomic_wait_timeout timeout = atomic_wait_timeout::inf) @@ -1099,11 +1135,6 @@ namespace stx return false; } - constexpr operator std::nullptr_t() const noexcept - { - return nullptr; - } - constexpr std::nullptr_t get() const noexcept { return nullptr; @@ -1112,10 +1143,29 @@ namespace stx } null_ptr; } +template +struct std::hash> +{ + usz operator()(const stx::single_ptr& x) const noexcept + { + return std::hash()(x.get()); + } +}; + +template +struct std::hash> +{ + usz operator()(const stx::shared_ptr& x) const noexcept + { + return std::hash()(x.get()); + } +}; + using stx::null_ptr; using stx::single_ptr; using stx::shared_ptr; using stx::atomic_ptr; using stx::make_single; +using stx::make_shared; using stx::make_single_value; using stx::make_shared_value; diff --git a/rpcs3/util/simd.hpp b/rpcs3/util/simd.hpp index d357c800ab..750bb97fd1 100644 --- a/rpcs3/util/simd.hpp +++ b/rpcs3/util/simd.hpp @@ -21,6 +21,7 @@ #include #endif +#include #include #include #include @@ -1967,6 +1968,15 @@ inline v128 gv_mulfs(const v128& a, const v128& b) #endif } +inline v128 gv_mulfs(const v128& a, f32 b) +{ +#if defined(ARCH_X64) + return _mm_mul_ps(a, _mm_set_ps1(b)); +#elif defined(ARCH_ARM64) + return vmulq_n_f32(a, b); +#endif +} + inline v128 gv_hadds8x2(const v128& a) { #if defined(__SSSE3__) @@ -2979,6 +2989,23 @@ inline v128 gv_rol16(const v128& a, const v128& b) #endif } +// For each 16-bit element, r = rotate a by count +template +inline v128 gv_rol16(const v128& a) +{ + constexpr u8 count = Count & 0xf; +#if defined(ARCH_X64) + return _mm_or_si128(_mm_srli_epi16(a, 16 - count), _mm_slli_epi16(a, count)); +#elif defined(ARCH_ARM64) + return vorrq_u16(vshrq_n_u16(a, 16 - count), vshlq_n_u16(a, count)); +#else + v128 r; + for (u32 i = 0; i < 8; i++) + r._u16[i] = std::rotl(a._u16[i], count); + return r; +#endif +} + // For each 32-bit element, r = rotate a by b inline v128 gv_rol32(const v128& a, const v128& b) { @@ -2997,15 +3024,16 @@ inline v128 gv_rol32(const v128& a, const v128& b) } // For each 32-bit element, r = rotate a by count -inline v128 gv_rol32(const v128& a, u32 count) +template +inline v128 gv_rol32(const v128& a) { - count %= 32; -#if defined(ARCH_X64) - return _mm_or_epi32(_mm_srli_epi32(a, 32 - count), _mm_slli_epi32(a, count)); + constexpr u8 count = Count & 0x1f; +#if defined(__AVX512VL__) + return _mm_rol_epi32(a, count); +#elif defined(ARCH_X64) + return _mm_or_si128(_mm_srli_epi32(a, 32 - count), _mm_slli_epi32(a, count)); #elif defined(ARCH_ARM64) - const auto amt1 = vdupq_n_s32(count); - const auto amt2 = vdupq_n_s32(count - 32); - return vorrq_u32(vshlq_u32(a, amt1), vshlq_u32(a, amt2)); + return vorrq_u32(vshrq_n_u32(a, 32 - count), vshlq_n_u32(a, count)); #else v128 r; for (u32 i = 0; i < 4; i++) @@ -3107,6 +3135,139 @@ inline auto gv_shuffle_right(A&& a) FOR_X64(unary_op, kIdPsrldq, kIdVpsrldq, std::forward(a), Count); } +// Load 32-bit integer into the first element of a new vector, set other elements to zero +inline v128 gv_loadu32(const void* ptr) +{ +#if defined(ARCH_X64) + return _mm_loadu_si32(ptr); +#elif defined(ARCH_ARM64) + return vld1q_lane_u32(static_cast(ptr), vdupq_n_u32(0), 0); +#endif +} + +// Load 16-bit integer into an existing vector at the position specified by Index +template +inline v128 gv_insert16(const v128& vec, u16 value) +{ +#if defined(ARCH_X64) + return _mm_insert_epi16(vec, value, Index); +#elif defined(ARCH_ARM64) + return vsetq_lane_u16(value, vec, Index & 0x7); +#endif +} + +// For each 8-bit element, +// if ctrl >= 0 && ctrl < 16 then r = vec[ctrl], +// else if ctrl < 0 then r = 0 +inline v128 gv_shuffle8(const v128& vec, const v128& ctrl) +{ + AUDIT(std::ranges::none_of(ctrl._chars, [](s8 i){ return i >= static_cast(sizeof(v128)); }), "All indices must be in the range [0, 15] or negative, since PSHUFB and TBL behave differently otherwise"); +#if defined(__SSSE3__) + return _mm_shuffle_epi8(vec, ctrl); +#elif defined(ARCH_ARM64) + return vqtbl1q_s8(vec, ctrl); +#else + v128 r; + for (s32 i = 0; i < 16; i++) + r._s8[i] = ctrl._s8[i] < 0 ? 0 : vec._s8[ctrl._s8[i] & 0xf]; + return r; +#endif +} + +// For each 2-bit index in Control, r = vec[index] +template +inline v128 gv_shuffle32(const v128& vec) +{ +#if defined(ARCH_X64) + return _mm_shuffle_epi32(vec, Control); +#elif defined(ARCH_ARM64) + constexpr u8 idx0 = (Control & 3) * sizeof(s32); + constexpr u8 idx1 = (Control >> 2 & 3) * sizeof(s32); + constexpr u8 idx2 = (Control >> 4 & 3) * sizeof(s32); + constexpr u8 idx3 = (Control >> 6 & 3) * sizeof(s32); + + constexpr uint8x16_t idx_vec = { idx0, idx0 + 1, idx0 + 2, idx0 + 3, idx1, idx1 + 1, idx1 + 2, idx1 + 3, idx2, idx2 + 1, idx2 + 2, idx2 + 3, idx3, idx3 + 1, idx3 + 2, idx3 + 3 }; + + return vqtbl1q_s8(vec, idx_vec); +#endif +} + +// For each index, r = vec[index & 3] +template +inline v128 gv_shuffle32(const v128& vec) +{ +#if defined(ARCH_X64) + return _mm_shuffle_epi32(vec, (Index0 & 3) | (Index1 & 3) << 2 | (Index2 & 3) << 4 | (Index3 & 3) << 6); +#elif defined(ARCH_ARM64) + constexpr u8 idx0 = (Index0 & 3) * sizeof(s32); + constexpr u8 idx1 = (Index1 & 3) * sizeof(s32); + constexpr u8 idx2 = (Index2 & 3) * sizeof(s32); + constexpr u8 idx3 = (Index3 & 3) * sizeof(s32); + + constexpr uint8x16_t idx_vec = { idx0, idx0 + 1, idx0 + 2, idx0 + 3, idx1, idx1 + 1, idx1 + 2, idx1 + 3, idx2, idx2 + 1, idx2 + 2, idx2 + 3, idx3, idx3 + 1, idx3 + 2, idx3 + 3 }; + + return vqtbl1q_s8(vec, idx_vec); +#endif +} + +// For the first two 2-bit indices in Control, r = a[index], +// for the last two indices, r = b[index] +template +inline v128 gv_shufflefs(const v128& a, const v128& b) +{ +#if defined(ARCH_X64) + return _mm_shuffle_ps(a, b, Control); +#elif defined(ARCH_ARM64) + constexpr u8 idx0 = (Control & 3) * sizeof(s32); + constexpr u8 idx1 = (Control >> 2 & 3) * sizeof(s32); + constexpr u8 idx2 = (Control >> 4 & 3) * sizeof(s32) + sizeof(v128); + constexpr u8 idx3 = (Control >> 6 & 3) * sizeof(s32) + sizeof(v128); + + constexpr uint8x16_t idx_vec = { idx0, idx0 + 1, idx0 + 2, idx0 + 3, idx1, idx1 + 1, idx1 + 2, idx1 + 3, idx2, idx2 + 1, idx2 + 2, idx2 + 3, idx3, idx3 + 1, idx3 + 2, idx3 + 3 }; + + return vqtbl2q_s8({ a, b }, idx_vec); +#endif +} + +// For the first two indices, r = a[index & 3], +// for the last two indices, r = b[index & 3] +template +inline v128 gv_shufflefs(const v128& a, const v128& b) +{ +#if defined(ARCH_X64) + return _mm_shuffle_ps(a, b, (Index0 & 3) | (Index1 & 3) << 2 | (Index2 & 3) << 4 | (Index3 & 3) << 6); +#elif defined(ARCH_ARM64) + constexpr u8 idx0 = (Index0 & 3) * sizeof(s32); + constexpr u8 idx1 = (Index1 & 3) * sizeof(s32); + constexpr u8 idx2 = (Index2 & 3) * sizeof(s32) + sizeof(v128); + constexpr u8 idx3 = (Index3 & 3) * sizeof(s32) + sizeof(v128); + + constexpr uint8x16_t idx_vec = { idx0, idx0 + 1, idx0 + 2, idx0 + 3, idx1, idx1 + 1, idx1 + 2, idx1 + 3, idx2, idx2 + 1, idx2 + 2, idx2 + 3, idx3, idx3 + 1, idx3 + 2, idx3 + 3 }; + + return vqtbl2q_s8({ a, b }, idx_vec); +#endif +} + +// For each 32-bit element, reverse byte order +inline v128 gv_rev32(const v128& vec) +{ +#if defined(__SSSE3__) + return _mm_shuffle_epi8(vec, _mm_setr_epi8(3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12)); +#elif defined(ARCH_ARM64) + return vrev32q_u8(vec); +#else + return gv_rol32<16>(gv_rol16<8>(vec)); +#endif +} + +// For each 32-bit element, convert between big-endian and native-endian +inline v128 gv_to_be32(const v128& vec) +{ + if constexpr (std::endian::native == std::endian::little) + return gv_rev32(vec); + return vec; +} + #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index 42c900898f..f01e558e92 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -989,14 +989,14 @@ template requires (std::is_integral_v; constexpr bool is_to_signed = std::is_signed_v; - constexpr auto from_mask = is_from_signed > is_to_signed ? UnFrom{umax} >> 1 : UnFrom{umax}; - constexpr auto to_mask = is_to_signed > is_from_signed ? UnTo{umax} >> 1 : UnTo{umax}; + constexpr auto from_mask = (is_from_signed && !is_to_signed) ? UnFrom{umax} >> 1 : UnFrom{umax}; + constexpr auto to_mask = (is_to_signed && !is_from_signed) ? UnTo{umax} >> 1 : UnTo{umax}; constexpr auto mask = ~(from_mask & to_mask); // Signed to unsigned always require test // Otherwise, this is bit-wise narrowing or conversion between types of different signedness of the same size - if constexpr (is_from_signed > is_to_signed || to_mask < from_mask) + if constexpr ((is_from_signed && !is_to_signed) || to_mask < from_mask) { // Try to optimize test if both are of the same signedness if (is_from_signed != is_to_signed ? !!(value & mask) : static_cast(value) != value) [[unlikely]]