From 9cf7a63c7768e365c6b76b605577648328f90b58 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 24 Jun 2022 19:58:26 +0200 Subject: [PATCH] Emu: Implement BlockingCallFromMainThread Reduces some copy-paste clutter throughout the project --- rpcs3/Emu/Cell/Modules/cellCamera.cpp | 64 ++----------------- rpcs3/Emu/Cell/Modules/cellOskDialog.cpp | 21 ++---- rpcs3/Emu/Cell/Modules/sceNp.cpp | 40 ++++-------- rpcs3/Emu/System.cpp | 31 +++++++++ rpcs3/Emu/System.h | 23 ++----- rpcs3/headless_application.cpp | 12 +++- rpcs3/headless_application.h | 5 +- rpcs3/rpcs3qt/gui_application.cpp | 12 +++- rpcs3/rpcs3qt/gui_application.h | 5 +- rpcs3/rpcs3qt/main_window.cpp | 2 +- rpcs3/rpcs3qt/qt_camera_handler.cpp | 12 +--- rpcs3/rpcs3qt/qt_music_handler.cpp | 81 +++--------------------- rpcs3/rpcs3qt/save_data_dialog.cpp | 10 +-- 13 files changed, 95 insertions(+), 223 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp index 6d018eff16..969124579f 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -1627,19 +1627,11 @@ void camera_context::operator()() else { std::lock_guard lock(mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&]() + Emu.BlockingCallFromMainThread([&]() { send_frame_update_event = handler ? on_handler_state(handler->get_state()) : true; - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } } @@ -1704,9 +1696,8 @@ void camera_context::operator()() bool camera_context::open_camera() { bool result = true; - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, &result, this]() + Emu.BlockingCallFromMainThread([&result, this]() { handler.reset(); handler = Emu.GetCallbacks().get_camera_handler(); @@ -1715,15 +1706,8 @@ bool camera_context::open_camera() handler->open_camera(); result = on_handler_state(handler->get_state()); } - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - return result; } @@ -1738,20 +1722,11 @@ bool camera_context::start_camera() handler->set_resolution(info.width, info.height); handler->set_format(info.format, info.bytesize); - atomic_t wake_up = false; - - Emu.CallFromMainThread([&wake_up, &result, this]() + Emu.BlockingCallFromMainThread([&result, this]() { handler->start_camera(); result = on_handler_state(handler->get_state()); - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } return result; @@ -1763,19 +1738,10 @@ bool camera_context::get_camera_frame(u8* dst, u32& width, u32& height, u64& fra if (handler) { - atomic_t wake_up = false; - - Emu.CallFromMainThread([&]() + Emu.BlockingCallFromMainThread([&]() { result = on_handler_state(handler->get_image(dst, info.bytesize, width, height, frame_number, bytes_read)); - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } return result; @@ -1785,19 +1751,10 @@ void camera_context::stop_camera() { if (handler) { - atomic_t wake_up = false; - - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { handler->stop_camera(); - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } } @@ -1805,19 +1762,10 @@ void camera_context::close_camera() { if (handler) { - atomic_t wake_up = false; - - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { handler->close_camera(); - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } } diff --git a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index b6e4dd5c24..a8ba995ec6 100644 --- a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -214,8 +214,6 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia } } - atomic_t result = false; - osk->on_osk_close = [wptr = std::weak_ptr(osk)](s32 status) { cellOskDialog.notice("on_osk_close(status=%d)", status); @@ -531,26 +529,19 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia input::SetIntercepted(osk->pad_input_enabled, osk->keyboard_input_enabled, osk->mouse_input_enabled); - Emu.CallFromMainThread([=, &result, &info]() + Emu.BlockingCallFromMainThread([=, &info]() { osk->Create(get_localized_string(localized_string_id::CELL_OSK_DIALOG_TITLE), message, osk->osk_text, maxLength, prohibitFlgs, allowOskPanelFlg, firstViewPanel, info.base_color.load(), info.dimmer_enabled.load(), false); - result = true; - result.notify_one(); - - if (g_fxo->get().osk_continuous_mode.load() == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE) - { - sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED, CELL_OSKDIALOG_DISPLAY_STATUS_SHOW); - } }); + if (info.osk_continuous_mode == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE) + { + sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED, CELL_OSKDIALOG_DISPLAY_STATUS_SHOW); + } + g_fxo->get().last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED; sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0); - while (!result && !Emu.IsStopped()) - { - thread_ctrl::wait_on(result, false); - } - return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp index bb280ac9a0..2e68c3071c 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -983,23 +983,15 @@ error_code sceNpBasicSendMessageGui(vm::cptr msg, sys_ msg_data.data.assign(msg->data.get_ptr(), msg->data.get_ptr() + msg->size); } - atomic_t wake_up = false; - bool result = false; + bool result = false; input::SetIntercepted(true); - Emu.CallFromMainThread([=, &wake_up, &result, msg_data = std::move(msg_data), npids = std::move(npids)]() mutable - { - auto send_dlg = Emu.GetCallbacks().get_sendmessage_dialog(); - result = send_dlg->Exec(msg_data, npids); - wake_up = true; - wake_up.notify_one(); - }); - - while (!wake_up && !Emu.IsStopped()) + Emu.BlockingCallFromMainThread([=, &result, msg_data = std::move(msg_data), npids = std::move(npids)]() mutable { - thread_ctrl::wait_on(wake_up, false); - } + auto send_dlg = Emu.GetCallbacks().get_sendmessage_dialog(); + result = send_dlg->Exec(msg_data, npids); + }); input::SetIntercepted(false); @@ -1154,26 +1146,18 @@ error_code sceNpBasicRecvMessageCustom(u16 mainType, u32 recvOptions, sys_memory return SCE_NP_BASIC_ERROR_INVALID_ARGUMENT; } - atomic_t wake_up = false; - bool result = false; + bool result = false; input::SetIntercepted(true); - SceNpBasicMessageRecvAction recv_result; - u64 chosen_msg_id; + SceNpBasicMessageRecvAction recv_result{}; + u64 chosen_msg_id{}; - Emu.CallFromMainThread([=, &wake_up, &result, &recv_result, &chosen_msg_id]() - { - auto recv_dlg = Emu.GetCallbacks().get_recvmessage_dialog(); - result = recv_dlg->Exec(static_cast(mainType), static_cast(recvOptions), recv_result, chosen_msg_id); - wake_up = true; - wake_up.notify_one(); - }); - - while (!wake_up && !Emu.IsStopped()) + Emu.BlockingCallFromMainThread([=, &result, &recv_result, &chosen_msg_id]() { - thread_ctrl::wait_on(wake_up, false); - } + auto recv_dlg = Emu.GetCallbacks().get_recvmessage_dialog(); + result = recv_dlg->Exec(static_cast(mainType), static_cast(recvOptions), recv_result, chosen_msg_id); + }); input::SetIntercepted(false); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b0929693ad..672ce4a982 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -130,6 +130,37 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +void Emulator::CallFromMainThread(std::function&& func, atomic_t* wake_up, bool track_emu_state, u64 stop_ctr) const +{ + if (!track_emu_state) + { + m_cb.call_from_main_thread(std::move(func), wake_up); + return; + } + + std::function final_func = [this, before = IsStopped(), count = (stop_ctr == umax ? +m_stop_ctr : stop_ctr), func = std::move(func)] + { + if (count == m_stop_ctr && before == IsStopped()) + { + func(); + } + }; + + m_cb.call_from_main_thread(std::move(final_func), wake_up); +} + +void Emulator::BlockingCallFromMainThread(std::function&& func) const +{ + atomic_t wake_up = false; + + CallFromMainThread(std::move(func), &wake_up); + + while (!wake_up && !IsStopped()) + { + thread_ctrl::wait_on(wake_up, false); + } +} + void Emulator::Init(bool add_only) { jit_runtime::initialize(); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 7856dd39f5..07aabad43c 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -56,7 +56,7 @@ enum class cfg_mode struct EmuCallbacks { - std::function)> call_from_main_thread; + std::function, atomic_t*)> call_from_main_thread; std::function on_run; // (start_playtime) continuing or going ingame, so start the clock std::function on_pause; std::function on_resume; @@ -136,23 +136,10 @@ public: } // Call from the GUI thread - void CallFromMainThread(std::function&& func, bool track_emu_state = true, u64 stop_ctr = umax) const - { - if (!track_emu_state) - { - return m_cb.call_from_main_thread(std::move(func)); - } + void CallFromMainThread(std::function&& func, atomic_t* wake_up = nullptr, bool track_emu_state = true, u64 stop_ctr = umax) const; - std::function final_func = [this, before = IsStopped(), count = (stop_ctr == umax ? +m_stop_ctr : stop_ctr), func = std::move(func)] - { - if (count == m_stop_ctr && before == IsStopped()) - { - func(); - } - }; - - return m_cb.call_from_main_thread(std::move(final_func)); - } + // Blocking call from the GUI thread + void BlockingCallFromMainThread(std::function&& func) const; enum class stop_counter_t : u64{}; @@ -163,7 +150,7 @@ public: void CallFromMainThread(std::function&& func, stop_counter_t counter) const { - CallFromMainThread(std::move(func), true, static_cast(counter)); + CallFromMainThread(std::move(func), nullptr, true, static_cast(counter)); } /** Set emulator mode to running unconditionnaly. diff --git a/rpcs3/headless_application.cpp b/rpcs3/headless_application.cpp index e32c983256..e1e3a23de3 100644 --- a/rpcs3/headless_application.cpp +++ b/rpcs3/headless_application.cpp @@ -58,9 +58,9 @@ void headless_application::InitializeCallbacks() return false; }; - callbacks.call_from_main_thread = [this](std::function func) + callbacks.call_from_main_thread = [this](std::function func, atomic_t* wake_up) { - RequestCallFromMainThread(std::move(func)); + RequestCallFromMainThread(std::move(func), wake_up); }; callbacks.init_gs_render = []() @@ -156,7 +156,13 @@ void headless_application::InitializeCallbacks() /** * Using connects avoids timers being unable to be used in a non-qt thread. So, even if this looks stupid to just call func, it's succinct. */ -void headless_application::CallFromMainThread(const std::function& func) +void headless_application::CallFromMainThread(const std::function& func, atomic_t* wake_up) { func(); + + if (wake_up) + { + *wake_up = true; + wake_up->notify_one(); + } } diff --git a/rpcs3/headless_application.h b/rpcs3/headless_application.h index 5a3b07e39c..aa283b01fd 100644 --- a/rpcs3/headless_application.h +++ b/rpcs3/headless_application.h @@ -3,6 +3,7 @@ #include #include "main_application.h" +#include "util/atomic.hpp" #include @@ -29,8 +30,8 @@ private: } Q_SIGNALS: - void RequestCallFromMainThread(std::function func); + void RequestCallFromMainThread(std::function func, atomic_t* wake_up); private Q_SLOTS: - static void CallFromMainThread(const std::function& func); + static void CallFromMainThread(const std::function& func, atomic_t* wake_up); }; diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 1e4c503b5d..dd8ac2fcd9 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -338,9 +338,9 @@ void gui_application::InitializeCallbacks() return false; }; - callbacks.call_from_main_thread = [this](std::function func) + callbacks.call_from_main_thread = [this](std::function func, atomic_t* wake_up) { - RequestCallFromMainThread(std::move(func)); + RequestCallFromMainThread(std::move(func), wake_up); }; callbacks.init_gs_render = []() @@ -669,7 +669,13 @@ void gui_application::OnEmuSettingsChange() /** * Using connects avoids timers being unable to be used in a non-qt thread. So, even if this looks stupid to just call func, it's succinct. */ -void gui_application::CallFromMainThread(const std::function& func) +void gui_application::CallFromMainThread(const std::function& func, atomic_t* wake_up) { func(); + + if (wake_up) + { + *wake_up = true; + wake_up->notify_one(); + } } diff --git a/rpcs3/rpcs3qt/gui_application.h b/rpcs3/rpcs3qt/gui_application.h index 7d9fe42575..1232b903d6 100644 --- a/rpcs3/rpcs3qt/gui_application.h +++ b/rpcs3/rpcs3qt/gui_application.h @@ -1,6 +1,7 @@ #pragma once #include "util/types.hpp" +#include "util/atomic.hpp" #include #include @@ -95,8 +96,8 @@ Q_SIGNALS: void OnEnableDiscEject(bool enabled); void OnEnableDiscInsert(bool enabled); - void RequestCallFromMainThread(const std::function& func); + void RequestCallFromMainThread(std::function func, atomic_t* wake_up); private Q_SLOTS: - static void CallFromMainThread(const std::function& func); + static void CallFromMainThread(const std::function& func, atomic_t* wake_up); }; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 5c732669b3..d828b33373 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1056,7 +1056,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& Emu.CallFromMainThread([this, str = std::move(str)]() { QMessageBox::critical(this, tr("Firmware Installation Failed"), str); - }, false); + }, nullptr, false); }; if (file_path.isEmpty()) diff --git a/rpcs3/rpcs3qt/qt_camera_handler.cpp b/rpcs3/rpcs3qt/qt_camera_handler.cpp index b57044da1e..18c906bd3e 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.cpp +++ b/rpcs3/rpcs3qt/qt_camera_handler.cpp @@ -23,23 +23,13 @@ qt_camera_handler::qt_camera_handler() : camera_handler_base() qt_camera_handler::~qt_camera_handler() { - atomic_t wake_up = false; - - Emu.CallFromMainThread([&]() + Emu.BlockingCallFromMainThread([&]() { close_camera(); m_surface.reset(); m_camera.reset(); m_error_handler.reset(); - - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up) - { - thread_ctrl::wait_on(wake_up, false); - } } void qt_camera_handler::set_camera(const QCameraInfo& camera_info) diff --git a/rpcs3/rpcs3qt/qt_music_handler.cpp b/rpcs3/rpcs3qt/qt_music_handler.cpp index 9137ba87fa..283c23848c 100644 --- a/rpcs3/rpcs3qt/qt_music_handler.cpp +++ b/rpcs3/rpcs3qt/qt_music_handler.cpp @@ -20,30 +20,20 @@ qt_music_handler::qt_music_handler() qt_music_handler::~qt_music_handler() { - atomic_t wake_up = false; - - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { music_log.notice("Destroying Qt music handler..."); m_media_player->stop(); m_media_player.reset(); m_error_handler.reset(); - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } void qt_music_handler::play(const std::string& path) { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, &path, this]() + Emu.BlockingCallFromMainThread([&path, this]() { if (m_state == CELL_MUSIC_PB_STATUS_PAUSE) { @@ -57,141 +47,86 @@ void qt_music_handler::play(const std::string& path) } m_media_player->play(); - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - m_state = CELL_MUSIC_PB_STATUS_PLAY; } void qt_music_handler::stop() { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { music_log.notice("Stopping music..."); m_media_player->stop(); - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - m_state = CELL_MUSIC_PB_STATUS_STOP; } void qt_music_handler::pause() { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { music_log.notice("Pausing music..."); m_media_player->pause(); - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - m_state = CELL_MUSIC_PB_STATUS_PAUSE; } void qt_music_handler::fast_forward() { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { music_log.notice("Fast-forwarding music..."); m_media_player->setPlaybackRate(2.0); - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - m_state = CELL_MUSIC_PB_STATUS_FASTFORWARD; } void qt_music_handler::fast_reverse() { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, this]() + Emu.BlockingCallFromMainThread([this]() { music_log.notice("Fast-reversing music..."); m_media_player->setPlaybackRate(-2.0); - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - m_state = CELL_MUSIC_PB_STATUS_FASTREVERSE; } void qt_music_handler::set_volume(f32 volume) { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; - Emu.CallFromMainThread([&wake_up, &volume, this]() + Emu.BlockingCallFromMainThread([&volume, this]() { const int new_volume = std::max(0, std::min(volume * 100, 100)); music_log.notice("Setting volume to %d%%", new_volume); m_media_player->setVolume(new_volume); - wake_up = true; - wake_up.notify_one(); }); - - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } } f32 qt_music_handler::get_volume() const { std::lock_guard lock(m_mutex); - atomic_t wake_up = false; f32 volume = 0.0f; - Emu.CallFromMainThread([&wake_up, &volume, this]() + Emu.BlockingCallFromMainThread([&volume, this]() { const int current_volume = std::max(0, std::min(m_media_player->volume(), 100)); music_log.notice("Getting volume: %d%%", current_volume); volume = current_volume / 100.0f; - wake_up = true; - wake_up.notify_one(); }); - while (!wake_up && !Emu.IsStopped()) - { - thread_ctrl::wait_on(wake_up, false); - } - return volume; } diff --git a/rpcs3/rpcs3qt/save_data_dialog.cpp b/rpcs3/rpcs3qt/save_data_dialog.cpp index b5ef615c7b..31bcf35c0f 100644 --- a/rpcs3/rpcs3qt/save_data_dialog.cpp +++ b/rpcs3/rpcs3qt/save_data_dialog.cpp @@ -40,25 +40,17 @@ s32 save_data_dialog::ShowSaveDataList(std::vector& save_entries, } // Fall back to front-end GUI - atomic_t dlg_result(false); atomic_t selection = 0; input::SetIntercepted(true); - Emu.CallFromMainThread([&]() + Emu.BlockingCallFromMainThread([&]() { save_data_list_dialog sdid(save_entries, focused, op, listSet); sdid.exec(); selection = sdid.GetSelection(); - dlg_result = true; - dlg_result.notify_one(); }); - while (!dlg_result && !Emu.IsStopped()) - { - thread_ctrl::wait_on(dlg_result, false); - } - input::SetIntercepted(false); if (use_end) sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);