1
0
mirror of https://github.com/RPCS3/rpcs3 synced 2024-07-08 19:56:08 +00:00

Emu: Implement BlockingCallFromMainThread

Reduces some copy-paste clutter throughout the project
This commit is contained in:
Megamouse 2022-06-24 19:58:26 +02:00 committed by Ivan
parent 7842812e24
commit 9cf7a63c77
13 changed files with 95 additions and 223 deletions

View File

@ -1627,19 +1627,11 @@ void camera_context::operator()()
else
{
std::lock_guard lock(mutex);
atomic_t<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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);
}
}
}

View File

@ -214,8 +214,6 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
}
}
atomic_t<bool> result = false;
osk->on_osk_close = [wptr = std::weak_ptr<OskDialogBase>(osk)](s32 status)
{
cellOskDialog.notice("on_osk_close(status=%d)", status);
@ -531,26 +529,19 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> 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_info>().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<osk_info>().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;
}

View File

@ -983,23 +983,15 @@ error_code sceNpBasicSendMessageGui(vm::cptr<SceNpBasicMessageDetails> msg, sys_
msg_data.data.assign(msg->data.get_ptr(), msg->data.get_ptr() + msg->size);
}
atomic_t<bool> 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<bool> 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<SceNpBasicMessageMainType>(mainType), static_cast<SceNpBasicMessageRecvOptions>(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<SceNpBasicMessageMainType>(mainType), static_cast<SceNpBasicMessageRecvOptions>(recvOptions), recv_result, chosen_msg_id);
});
input::SetIntercepted(false);

View File

@ -130,6 +130,37 @@ void fmt_class_string<cfg_mode>::format(std::string& out, u64 arg)
});
}
void Emulator::CallFromMainThread(std::function<void()>&& func, atomic_t<bool>* 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<void()> 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<void()>&& func) const
{
atomic_t<bool> 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();

View File

@ -56,7 +56,7 @@ enum class cfg_mode
struct EmuCallbacks
{
std::function<void(std::function<void()>)> call_from_main_thread;
std::function<void(std::function<void()>, atomic_t<bool>*)> call_from_main_thread;
std::function<void(bool)> on_run; // (start_playtime) continuing or going ingame, so start the clock
std::function<void()> on_pause;
std::function<void()> on_resume;
@ -136,23 +136,10 @@ public:
}
// Call from the GUI thread
void CallFromMainThread(std::function<void()>&& 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<void()>&& func, atomic_t<bool>* wake_up = nullptr, bool track_emu_state = true, u64 stop_ctr = umax) const;
std::function<void()> 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<void()>&& func) const;
enum class stop_counter_t : u64{};
@ -163,7 +150,7 @@ public:
void CallFromMainThread(std::function<void()>&& func, stop_counter_t counter) const
{
CallFromMainThread(std::move(func), true, static_cast<u64>(counter));
CallFromMainThread(std::move(func), nullptr, true, static_cast<u64>(counter));
}
/** Set emulator mode to running unconditionnaly.

View File

@ -58,9 +58,9 @@ void headless_application::InitializeCallbacks()
return false;
};
callbacks.call_from_main_thread = [this](std::function<void()> func)
callbacks.call_from_main_thread = [this](std::function<void()> func, atomic_t<bool>* 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<void()>& func)
void headless_application::CallFromMainThread(const std::function<void()>& func, atomic_t<bool>* wake_up)
{
func();
if (wake_up)
{
*wake_up = true;
wake_up->notify_one();
}
}

View File

@ -3,6 +3,7 @@
#include <QCoreApplication>
#include "main_application.h"
#include "util/atomic.hpp"
#include <functional>
@ -29,8 +30,8 @@ private:
}
Q_SIGNALS:
void RequestCallFromMainThread(std::function<void()> func);
void RequestCallFromMainThread(std::function<void()> func, atomic_t<bool>* wake_up);
private Q_SLOTS:
static void CallFromMainThread(const std::function<void()>& func);
static void CallFromMainThread(const std::function<void()>& func, atomic_t<bool>* wake_up);
};

View File

@ -338,9 +338,9 @@ void gui_application::InitializeCallbacks()
return false;
};
callbacks.call_from_main_thread = [this](std::function<void()> func)
callbacks.call_from_main_thread = [this](std::function<void()> func, atomic_t<bool>* 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<void()>& func)
void gui_application::CallFromMainThread(const std::function<void()>& func, atomic_t<bool>* wake_up)
{
func();
if (wake_up)
{
*wake_up = true;
wake_up->notify_one();
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "util/types.hpp"
#include "util/atomic.hpp"
#include <QApplication>
#include <QElapsedTimer>
@ -95,8 +96,8 @@ Q_SIGNALS:
void OnEnableDiscEject(bool enabled);
void OnEnableDiscInsert(bool enabled);
void RequestCallFromMainThread(const std::function<void()>& func);
void RequestCallFromMainThread(std::function<void()> func, atomic_t<bool>* wake_up);
private Q_SLOTS:
static void CallFromMainThread(const std::function<void()>& func);
static void CallFromMainThread(const std::function<void()>& func, atomic_t<bool>* wake_up);
};

View File

@ -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())

View File

@ -23,23 +23,13 @@ qt_camera_handler::qt_camera_handler() : camera_handler_base()
qt_camera_handler::~qt_camera_handler()
{
atomic_t<bool> 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)

View File

@ -20,30 +20,20 @@ qt_music_handler::qt_music_handler()
qt_music_handler::~qt_music_handler()
{
atomic_t<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> wake_up = false;
Emu.CallFromMainThread([&wake_up, &volume, this]()
Emu.BlockingCallFromMainThread([&volume, this]()
{
const int new_volume = std::max<int>(0, std::min<int>(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<bool> 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;
}

View File

@ -40,25 +40,17 @@ s32 save_data_dialog::ShowSaveDataList(std::vector<SaveDataEntry>& save_entries,
}
// Fall back to front-end GUI
atomic_t<bool> dlg_result(false);
atomic_t<s32> 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);