diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index c67e720b6f..9b6d250c19 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -106,6 +106,11 @@ thread_local u64 g_tls_wait_fail = 0; thread_local bool g_tls_access_violation_recovered = false; extern thread_local std::string(*g_tls_log_prefix)(); +namespace stx +{ + atomic_t g_launch_retainer{0}; +} + // Report error and call std::abort(), defined in main.cpp [[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true); diff --git a/Utilities/Thread.h b/Utilities/Thread.h index da5b25ce96..02e5db56ff 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -465,6 +465,8 @@ public: namespace stx { struct launch_retainer; + + extern atomic_t g_launch_retainer; } // Derived from the callable object Context, possibly a lambda @@ -481,6 +483,11 @@ class named_thread final : public Context, result_storage, thread_base u64 entry_point2() { + while (u32 value = stx::g_launch_retainer) + { + stx::g_launch_retainer.wait(value); + } + thread::initialize([]() { if constexpr (!result::empty) diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 9710af94f5..d858735edf 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -659,7 +659,7 @@ void cpu_thread::operator()() } case thread_class::spu: { - if (g_cfg.core.spu_prof) + if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) { g_fxo->get().registered.push(id); } @@ -1546,7 +1546,7 @@ void cpu_thread::flush_profilers() noexcept return; } - if (g_cfg.core.spu_prof) + if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) { g_fxo->get().registered.push(0); } @@ -1585,22 +1585,30 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve idm::select>([&](u32 id, spu_thread& spu) { - spu_list.emplace_back(ensure(idm::get_unlocked>(id))); + if (give_up) + { + return; + } - if (spu.current_func && spu.unsavable) + if (spu.current_func && spu.unsavable && !force_collect) { const u64 start = spu.start_time; - // Automatically give up if it is asleep 15 seconds or more - if (start && current > start && current - start >= 15'000'000) + // Automatically give up if it is asleep 5 seconds or more + if (start && current > start && current - start >= 5'000'000) { give_up = true; + return; } } + + spu_list.emplace_back(ensure(idm::get_unlocked>(id))); }); - if (!force_collect && give_up) + if (give_up) { + spu_list.clear(); + old_counter = umax; return decltype(&spu_list){}; } @@ -1625,6 +1633,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve } else if (get_system_time() - start >= 150'000) { + std::this_thread::sleep_for(1ms); passed_count++; start = 0; continue; @@ -1636,37 +1645,29 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve if (!spu_list) { // Give up for now - std::this_thread::sleep_for(10ms); + std::this_thread::sleep_for(50ms); passed_count++; start = 0; continue; } // Avoid using suspend_all when more than 2 threads known to be unsavable - u32 unsavable_threads = 0; + u32 savable_threads = 0; for (auto& spu : *spu_list) { - if (spu->unsavable) + if (!spu->unsavable) { - unsavable_threads++; - - if (unsavable_threads >= 3) - { - break; - } + savable_threads++; } } - if (unsavable_threads >= 3) + if (!savable_threads) { std::this_thread::yield(); continue; } - // Flag for optimization - bool paused_anyone = false; - if (cpu_thread::suspend_all(nullptr, {}, [&]() { if (!get_spus(false, true)) @@ -1695,19 +1696,13 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve break; } } - else - { - paused_anyone = true; - ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause)); - } } - if (failed && paused_anyone) + for (auto& spu : *spu_list) { - // For faster signalling, first remove state flags then batch notifications - for (auto& spu : *spu_list) + if (!failed && !is_emu_paused) { - spu->state -= cpu_flag::dbg_global_pause; + ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause)); } } @@ -1719,13 +1714,6 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve return false; } - if (!paused_anyone) - { - // Need not do anything - std::this_thread::yield(); - continue; - } - for (auto& spu : *spu_list) { if (spu->state & cpu_flag::wait) @@ -1755,7 +1743,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve { spu->state.notify_one(); } - }; + } return false; } diff --git a/rpcs3/Emu/Cell/Modules/cellAtracXdec.cpp b/rpcs3/Emu/Cell/Modules/cellAtracXdec.cpp index 8b4285cc15..c55cf7b60f 100644 --- a/rpcs3/Emu/Cell/Modules/cellAtracXdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAtracXdec.cpp @@ -111,8 +111,6 @@ void AtracXdecDecoder::alloc_avcodec() fmt::throw_exception("avcodec_find_decoder() failed"); } - //ensure(!(codec->capabilities & AV_CODEC_CAP_SUBFRAMES)); - packet = av_packet_alloc(); if (!packet) { @@ -154,7 +152,7 @@ void AtracXdecDecoder::init_avcodec() { fmt::throw_exception("avcodec_alloc_context3() failed"); } - + // Allows FFmpeg to output directly into guest memory ctx->opaque = this; ctx->thread_type = FF_THREAD_SLICE; // Silences a warning by FFmpeg about requesting frame threading with a custom get_buffer2(). Default is FF_THREAD_FRAME & FF_THREAD_SLICE diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 9d39b3c7eb..c50c93fc44 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -361,7 +361,7 @@ public: case move_handler::mouse: case move_handler::raw_mouse: { - auto& handler = g_fxo->get(); + auto& handler = *ensure(g_fxo->try_get()); std::lock_guard mouse_lock(handler.mutex); const MouseInfo& info = handler.GetInfo(); @@ -374,7 +374,7 @@ public: #ifdef HAVE_LIBEVDEV case move_handler::gun: { - gun_thread& gun = g_fxo->get(); + gun_thread& gun = *ensure(g_fxo->try_get()); std::scoped_lock lock(gun.handler.mutex); gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; @@ -505,7 +505,7 @@ public: case move_handler::mouse: case move_handler::raw_mouse: { - auto& handler = g_fxo->get(); + auto& handler = *ensure(g_fxo->try_get()); std::lock_guard mouse_lock(handler.mutex); // Make sure that the mouse handler is initialized @@ -522,7 +522,7 @@ public: #ifdef HAVE_LIBEVDEV case move_handler::gun: { - gun_thread& gun = g_fxo->get(); + gun_thread& gun = *ensure(g_fxo->try_get()); std::scoped_lock lock(gun.handler.mutex); gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; connected_controllers = std::min(std::min(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices); diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 6b4b456f3d..946deacf01 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -186,7 +186,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func) c->cmp(SPU_OFF_32(state), 0); c->jnz(label_stop); - if (g_cfg.core.spu_prof && g_cfg.core.spu_verification) + if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification) { c->mov(x86::rax, m_hash_start & -0xffff); c->mov(SPU_OFF_64(block_hash), x86::rax); @@ -755,7 +755,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func) c->add(SPU_OFF_64(block_counter), ::size32(words) / (words_align / 4)); // Set block hash for profiling (if enabled) - if (g_cfg.core.spu_prof) + if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) { c->mov(x86::rax, m_hash_start | 0xffff); c->mov(SPU_OFF_64(block_hash), x86::rax); @@ -1199,7 +1199,7 @@ void spu_recompiler::branch_set_link(u32 target) c->movdqa(x86::dqword_ptr(*cpu, *qw1, 0, ::offset32(&spu_thread::stack_mirror)), x86::xmm0); // Set block hash for profiling (if enabled) - if (g_cfg.core.spu_prof) + if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) { c->mov(x86::rax, m_hash_start | 0xffff); c->mov(SPU_OFF_64(block_hash), x86::rax); diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 169d01a09d..91ed1d43ef 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -1636,7 +1636,7 @@ public: m_ir->SetInsertPoint(label_test); // Set block hash for profiling (if enabled) - if (g_cfg.core.spu_prof && g_cfg.core.spu_verification) + if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification) m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536)), spu_ptr(&spu_thread::block_hash)); if (!g_cfg.core.spu_verification) @@ -1993,7 +1993,7 @@ public: set_function(m_functions[m_entry].chunk); // Set block hash for profiling (if enabled) - if (g_cfg.core.spu_prof) + if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (m_entry >> 2)), spu_ptr(&spu_thread::block_hash)); m_finfo = &m_functions[m_entry]; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index cc21e2ebb8..f8848a9781 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1612,10 +1612,14 @@ std::string spu_thread::dump_misc() const fmt::append(ret, "Block Weight: %u (Retreats: %u)", block_counter, block_failure); - if (g_cfg.core.spu_prof) + if (u64 hash = atomic_storage::load(block_hash)) { // Get short function hash and position in chunk - fmt::append(ret, "\nCurrent block: %s", spu_block_hash{atomic_storage::load(block_hash)}); + fmt::append(ret, "\nCurrent block: %s", spu_block_hash{hash}); + } + else if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) + { + fmt::append(ret, "\nCurrent block: N/A"); } const u32 offset = group ? SPU_FAKE_BASE_ADDR + (id & 0xffffff) * SPU_LS_SIZE : RAW_SPU_BASE_ADDR + index * RAW_SPU_OFFSET; diff --git a/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp b/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp index e026f9813d..46edb42175 100644 --- a/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp +++ b/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp @@ -589,7 +589,7 @@ namespace rsx { if (REGS(m_ctx)->clip_planes_mask() == 0) [[ likely ]] { - *reinterpret_cast(buffer) = 0u; + *reinterpret_cast(buffer) = 0b0101010101010101; return; } @@ -631,7 +631,7 @@ namespace rsx break; case rsx::user_clip_plane_op::less_than: - clip_configuration_field |= CLIP_DISTANCE_FACTOR(2) << shift_offset; + clip_configuration_field |= CLIP_DISTANCE_FACTOR(-1) << shift_offset; break; } } diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp index 0ae8ab8993..afebcce7ed 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp @@ -182,7 +182,7 @@ namespace glsl OS << "#define CLIP_PLANE_DISABLED 1\n" "#define is_user_clip_enabled(idx) (_get_bits(get_user_clip_config(), idx * 2, 2) != CLIP_PLANE_DISABLED)\n" - "#define user_clip_factor(idx) float(_get_bits(get_user_clip_config(), idx * 2, 2) - 1)\n\n"; + "#define user_clip_factor(idx) (float(_get_bits(get_user_clip_config(), idx * 2, 2)) - 1.f)\n\n"; } if (props.domain == glsl::program_domain::glsl_fragment_program) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index bdb75531e7..cc91e52750 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -837,7 +837,7 @@ namespace rsx { while (Emu.IsReady()) { - thread_ctrl::wait_for(1000); + Emu.WaitReady(); } do diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 2721cff539..26b5bfff03 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -221,13 +221,19 @@ void init_fxo_for_exec(utils::serial* ar, bool full = false) Emu.ConfigurePPUCache(); + stx::g_launch_retainer = 1; + g_fxo->init(false, ar, [](){ Emu.ExecPostponedInitCode(); }); Emu.GetCallbacks().init_gs_render(ar); - Emu.GetCallbacks().init_pad_handler(Emu.GetTitleID()); Emu.GetCallbacks().init_kb_handler(); Emu.GetCallbacks().init_mouse_handler(); + stx::g_launch_retainer = 0; + stx::g_launch_retainer.notify_all(); + + Emu.GetCallbacks().init_pad_handler(Emu.GetTitleID()); + usz pos = 0; if (ar) @@ -859,6 +865,7 @@ bool Emulator::BootRsxCapture(const std::string& path) GetCallbacks().on_run(false); m_state = system_state::starting; + m_state.notify_all(); ensure(g_fxo->init>("RSX Replay", std::move(frame))); @@ -2472,6 +2479,7 @@ void Emulator::Run(bool start_playtime) rpcs3::utils::configure_logs(); m_state = system_state::starting; + m_state.notify_all(); if (g_cfg.misc.prevent_display_sleep) { @@ -3254,6 +3262,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s } // Signal threads + m_state.notify_all(); if (auto rsx = g_fxo->try_get()) { diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index fcdb60cf8d..41dd6229bd 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -439,6 +439,7 @@ public: bool IsStopped(bool test_fully = false) const { return test_fully ? m_state == system_state::stopped : m_state <= system_state::stopping; } bool IsReady() const { return m_state == system_state::ready; } bool IsStarting() const { return m_state == system_state::starting; } + void WaitReady() const { m_state.wait(system_state::ready); } auto GetStatus(bool fixup = true) const { system_state state = m_state; return fixup && state == system_state::frozen ? system_state::paused : fixup && state == system_state::stopping ? system_state::stopped : state; } bool HasGui() const { return m_has_gui; } diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index 8bb2bb5c34..1e84a51ed9 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -332,7 +332,7 @@ private: case localized_string_id::EMULATION_RESUMING: return tr("Resuming...!"); case localized_string_id::EMULATION_FROZEN: return tr("The PS3 application has likely crashed, you can close it."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_SAVEDATA: return tr("SaveState failed: Game saving is in progress, wait until finished."); - case localized_string_id::SAVESTATE_FAILED_DUE_TO_VDEC: return tr("SaveState failed: VDEC-base video/cutscenes are in order, wait for them to end or enable libvdec.sprx."); + case localized_string_id::SAVESTATE_FAILED_DUE_TO_VDEC: return tr("SaveState failed: VDEC-based video/cutscenes are in order, wait for them to end or enable libvdec.sprx."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_MISSING_SPU_SETTING: return tr("SaveState failed: Failed to lock SPU state, enabling SPU-Compatible mode may fix it."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_SPU: return tr("SaveState failed: Failed to lock SPU state, using SPU ASMJIT will fix it."); case localized_string_id::INVALID: return tr("Invalid");