Host: Expose RunOnUIThread() to core

I hate this, but sadly needed for RAIntegration...
This commit is contained in:
Stenzek 2025-04-11 21:41:13 +10:00
parent f0d4816de7
commit c1e01af511
No known key found for this signature in database
8 changed files with 51 additions and 48 deletions

View File

@ -78,6 +78,9 @@ bool ChangeLanguage(const char* new_language);
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);
/// Safely executes a function on the main/UI thread.
void RunOnUIThread(std::function<void()> function, bool block = false);
/// Called when the core is creating a render device.
/// This could also be fullscreen transition.
std::optional<WindowInfo> AcquireRenderWindow(RenderAPI render_api, bool fullscreen, bool exclusive_fullscreen,

View File

@ -77,11 +77,9 @@ static bool SetDataDirectory();
static bool SetCriticalFolders();
static void SetDefaultSettings(SettingsInterface& si, bool system, bool controller);
static std::string GetResourcePath(std::string_view name, bool allow_override);
static void ProcessCPUThreadEvents(bool block);
static bool PerformEarlyHardwareChecks();
static bool EarlyProcessStartup();
static void WarnAboutInterface();
static void RunOnUIThread(std::function<void()> func);
static void StartCPUThread();
static void StopCPUThread();
static void ProcessCPUThreadEvents(bool block);
@ -580,7 +578,7 @@ std::optional<WindowInfo> Host::AcquireRenderWindow(RenderAPI render_api, bool f
std::optional<WindowInfo> wi;
MiniHost::RunOnUIThread([render_api, fullscreen, error, &wi]() {
Host::RunOnUIThread([render_api, fullscreen, error, &wi]() {
const std::string window_title = GetWindowTitle(System::GetGameTitle());
const SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_title.c_str());
@ -656,7 +654,7 @@ void Host::ReleaseRenderWindow()
if (!s_state.sdl_window)
return;
MiniHost::RunOnUIThread([]() {
Host::RunOnUIThread([]() {
if (!s_state.fullscreen.load(std::memory_order_acquire))
{
int window_x = SDL_WINDOWPOS_UNDEFINED, window_y = SDL_WINDOWPOS_UNDEFINED;
@ -909,17 +907,6 @@ void MiniHost::ProcessSDLEvent(const SDL_Event* ev)
}
}
void MiniHost::RunOnUIThread(std::function<void()> func)
{
std::function<void()>* pfunc = new std::function<void()>(std::move(func));
SDL_Event ev;
ev.user = {};
ev.type = s_state.func_event_id;
ev.user.data1 = pfunc;
SDL_PushEvent(&ev);
}
void MiniHost::ProcessCPUThreadPlatformMessages()
{
// This is lame. On Win32, we need to pump messages, even though *we* don't have any windows
@ -1038,7 +1025,7 @@ void MiniHost::CPUThreadEntryPoint()
System::CPUThreadShutdown();
// Tell the UI thread to shut down.
RunOnUIThread([]() { s_state.ui_thread_running = false; });
Host::RunOnUIThread([]() { s_state.ui_thread_running = false; });
}
void MiniHost::CPUThreadMainLoop()
@ -1211,6 +1198,19 @@ void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false
s_state.cpu_thread_event_done.wait(lock, []() { return s_state.blocking_cpu_events_pending == 0; });
}
void Host::RunOnUIThread(std::function<void()> function, bool block /* = false */)
{
using namespace MiniHost;
std::function<void()>* pfunc = new std::function<void()>(std::move(function));
SDL_Event ev;
ev.user = {};
ev.type = s_state.func_event_id;
ev.user.data1 = pfunc;
SDL_PushEvent(&ev);
}
void Host::RefreshGameListAsync(bool invalidate_cache)
{
using namespace MiniHost;

View File

@ -661,7 +661,7 @@ void DebuggerWindow::toggleBreakpoint(VirtualMemoryAddress address)
return;
}
QtHost::RunOnUIThread([this, address, new_bp_state, bps = CPU::CopyBreakpointList()]() {
Host::RunOnUIThread([this, address, new_bp_state, bps = CPU::CopyBreakpointList()]() {
m_code_model->setBreakpointState(address, new_bp_state);
refreshBreakpointList(bps);
});
@ -715,7 +715,7 @@ bool DebuggerWindow::scrollToMemoryAddress(VirtualMemoryAddress address)
void DebuggerWindow::refreshBreakpointList()
{
Host::RunOnCPUThread(
[this]() { QtHost::RunOnUIThread([this, bps = CPU::CopyBreakpointList()]() { refreshBreakpointList(bps); }); });
[this]() { Host::RunOnUIThread([this, bps = CPU::CopyBreakpointList()]() { refreshBreakpointList(bps); }); });
}
void DebuggerWindow::refreshBreakpointList(const CPU::BreakpointList& bps)
@ -743,7 +743,7 @@ void DebuggerWindow::addBreakpoint(CPU::BreakpointType type, u32 address)
{
Host::RunOnCPUThread([this, address, type]() {
const bool result = CPU::AddBreakpoint(type, address);
QtHost::RunOnUIThread([this, address, type, result, bps = CPU::CopyBreakpointList()]() {
Host::RunOnUIThread([this, address, type, result, bps = CPU::CopyBreakpointList()]() {
if (!result)
{
QMessageBox::critical(this, windowTitle(),
@ -763,7 +763,7 @@ void DebuggerWindow::removeBreakpoint(CPU::BreakpointType type, u32 address)
{
Host::RunOnCPUThread([this, address, type]() {
const bool result = CPU::RemoveBreakpoint(type, address);
QtHost::RunOnUIThread([this, address, type, result, bps = CPU::CopyBreakpointList()]() {
Host::RunOnUIThread([this, address, type, result, bps = CPU::CopyBreakpointList()]() {
if (!result)
{
QMessageBox::critical(this, windowTitle(), tr("Failed to remove breakpoint. This breakpoint may not exist."));

View File

@ -1037,7 +1037,7 @@ void MainWindow::populateCheatsMenu(QMenu* menu)
if (Cheats::AreCheatsEnabled() && names.empty())
return;
QtHost::RunOnUIThread([menu, names = std::move(names)]() {
Host::RunOnUIThread([menu, names = std::move(names)]() {
if (names.empty())
{
QAction* action = menu->addAction(tr("Cheats are not enabled."));
@ -2368,9 +2368,9 @@ void MainWindow::openGamePropertiesForCurrentGame(const char* category /* = null
if (path.empty() || serial.empty())
return;
QtHost::RunOnUIThread([title = std::string(System::GetGameTitle()), path = std::string(path),
serial = std::string(serial), hash = System::GetGameHash(), region = System::GetDiscRegion(),
category]() {
Host::RunOnUIThread([title = std::string(System::GetGameTitle()), path = std::string(path),
serial = std::string(serial), hash = System::GetGameHash(), region = System::GetDiscRegion(),
category]() {
SettingsWindow::openGamePropertiesDialog(path, title, std::move(serial), hash, region, category);
});
});

View File

@ -1149,7 +1149,7 @@ void EmuThread::confirmActionIfMemoryCardBusy(const QString& action, bool cancel
return;
}
QtHost::RunOnUIThread([action, cancel_resume_on_accept, callback = std::move(callback)]() mutable {
Host::RunOnUIThread([action, cancel_resume_on_accept, callback = std::move(callback)]() mutable {
auto lock = g_main_window->pauseAndLockSystem();
const bool result =
@ -1378,7 +1378,7 @@ void EmuThread::startControllerTest()
return;
}
QtHost::RunOnUIThread([path = std::move(path)]() mutable {
Host::RunOnUIThread([path = std::move(path)]() mutable {
{
auto lock = g_main_window->pauseAndLockSystem();
if (QMessageBox::question(
@ -1397,7 +1397,7 @@ void EmuThread::startControllerTest()
});
}
void EmuThread::runOnEmuThread(std::function<void()> callback)
void EmuThread::runOnEmuThread(const std::function<void()>& callback)
{
callback();
}
@ -1411,11 +1411,11 @@ void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false
Q_ARG(std::function<void()>, std::move(function)));
}
void QtHost::RunOnUIThread(const std::function<void()>& func, bool block /*= false*/)
void Host::RunOnUIThread(std::function<void()> function, bool block /* = false*/)
{
// main window always exists, so it's fine to attach it to that.
QMetaObject::invokeMethod(g_main_window, "runOnUIThread", block ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
Q_ARG(const std::function<void()>&, func));
Q_ARG(std::function<void()>, std::move(function)));
}
QtAsyncTask::QtAsyncTask(WorkCallback callback)
@ -1432,7 +1432,7 @@ void QtAsyncTask::create(QObject* owner, WorkCallback callback)
connect(task, &QtAsyncTask::completed, owner, [task]() { std::get<CompletionCallback>(task->m_callback)(); });
System::QueueAsyncTask([task]() {
task->m_callback = std::get<WorkCallback>(task->m_callback)();
QtHost::RunOnUIThread([task]() {
Host::RunOnUIThread([task]() {
emit task->completed(task);
delete task;
});
@ -1710,10 +1710,9 @@ void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directo
}
}
QtHost::RunOnUIThread([title = QtUtils::StringViewToQString(title), select_directory, callback = std::move(callback),
filters_str = std::move(filters_str),
initial_directory = QtUtils::StringViewToQString(initial_directory),
from_cpu_thread]() mutable {
Host::RunOnUIThread([title = QtUtils::StringViewToQString(title), select_directory, callback = std::move(callback),
filters_str = std::move(filters_str),
initial_directory = QtUtils::StringViewToQString(initial_directory), from_cpu_thread]() mutable {
auto lock = g_main_window->pauseAndLockSystem();
QString path;
@ -2103,9 +2102,9 @@ void Host::ConfirmMessageAsync(std::string_view title, std::string_view message,
else
{
// Otherwise, use the desktop UI.
QtHost::RunOnUIThread([title = QtUtils::StringViewToQString(title), message = QtUtils::StringViewToQString(message),
callback = std::move(callback), yes_text = QtUtils::StringViewToQString(yes_text),
no_text = QtUtils::StringViewToQString(no_text), needs_pause]() mutable {
Host::RunOnUIThread([title = QtUtils::StringViewToQString(title), message = QtUtils::StringViewToQString(message),
callback = std::move(callback), yes_text = QtUtils::StringViewToQString(yes_text),
no_text = QtUtils::StringViewToQString(no_text), needs_pause]() mutable {
auto lock = g_main_window->pauseAndLockSystem();
bool result;
@ -2136,14 +2135,14 @@ void Host::ConfirmMessageAsync(std::string_view title, std::string_view message,
void Host::OpenURL(std::string_view url)
{
QtHost::RunOnUIThread([url = QtUtils::StringViewToQString(url)]() { QtUtils::OpenURL(g_main_window, QUrl(url)); });
Host::RunOnUIThread([url = QtUtils::StringViewToQString(url)]() { QtUtils::OpenURL(g_main_window, QUrl(url)); });
}
std::string Host::GetClipboardText()
{
// Hope this doesn't deadlock...
std::string ret;
QtHost::RunOnUIThread(
Host::RunOnUIThread(
[&ret]() {
QClipboard* clipboard = QGuiApplication::clipboard();
if (clipboard)
@ -2155,7 +2154,7 @@ std::string Host::GetClipboardText()
bool Host::CopyTextToClipboard(std::string_view text)
{
QtHost::RunOnUIThread([text = QtUtils::StringViewToQString(text)]() {
Host::RunOnUIThread([text = QtUtils::StringViewToQString(text)]() {
QClipboard* clipboard = QGuiApplication::clipboard();
if (clipboard)
clipboard->setText(text);
@ -2543,7 +2542,7 @@ void QtHost::QueueSettingsSave()
{
if (!QThread::isMainThread())
{
QtHost::RunOnUIThread(QueueSettingsSave);
Host::RunOnUIThread(QueueSettingsSave);
return;
}

View File

@ -225,7 +225,7 @@ private Q_SLOTS:
void onDisplayWindowKeyEvent(int key, bool pressed);
void onDisplayWindowTextEntered(const QString& text);
void doBackgroundControllerPoll();
void runOnEmuThread(std::function<void()> callback);
void runOnEmuThread(const std::function<void()>& callback);
void processAuxiliaryRenderWindowInputEvent(void* userdata, quint32 event, quint32 param1, quint32 param2,
quint32 param3);
@ -358,9 +358,6 @@ bool IsRunningOnWayland();
/// Returns true if rendering to the main window should be allowed.
bool CanRenderToMainWindow();
/// Executes a function on the UI thread.
void RunOnUIThread(const std::function<void()>& func, bool block = false);
/// Default language for the platform.
const char* GetDefaultLanguage();

View File

@ -225,7 +225,7 @@ std::span<const std::pair<const char*, const char*>> Host::GetAvailableLanguageL
bool Host::ChangeLanguage(const char* new_language)
{
QtHost::RunOnUIThread([new_language = std::string(new_language)]() {
Host::RunOnUIThread([new_language = std::string(new_language)]() {
Host::SetBaseStringSettingValue("Main", "Language", new_language.c_str());
Host::CommitBaseSettingChanges();
QtHost::UpdateApplicationLanguage(g_main_window);
@ -283,8 +283,7 @@ void QtHost::UpdateGlyphRangesAndClearCache(QWidget* dialog_parent, std::string_
// If we don't have any specific glyph range, assume Central European, except if English, then keep the size down.
if ((!gi || !gi->used_glyphs) && language != "en")
{
glyph_ranges.insert(glyph_ranges.end(), std::begin(s_central_european_ranges),
std::end(s_central_european_ranges));
glyph_ranges.insert(glyph_ranges.end(), std::begin(s_central_european_ranges), std::end(s_central_european_ranges));
}
// List terminator.

View File

@ -381,6 +381,11 @@ void RegTestHost::ProcessCPUThreadEvents()
}
}
void Host::RunOnUIThread(std::function<void()> function, bool block /* = false */)
{
RunOnCPUThread(std::move(function), block);
}
void Host::RequestResizeHostDisplay(s32 width, s32 height)
{
//