Qt: Fix 100% CPU usage while downloading files

The wonders of having fast internet, you never realize when this happens
because it completes too quickly...
This commit is contained in:
Stenzek 2024-09-20 21:46:09 +10:00
parent 5f80cb1188
commit d07c7e4b68
No known key found for this signature in database
4 changed files with 58 additions and 31 deletions

View File

@ -544,11 +544,13 @@ void AutoUpdaterDialog::downloadUpdateClicked()
m_http_poll_timer->stop();
// Block until completion.
while (m_http->HasAnyRequests())
{
QApplication::processEvents(QEventLoop::AllEvents, HTTP_POLL_INTERVAL);
m_http->PollRequests();
}
QtUtils::ProcessEventsWithSleep(
QEventLoop::AllEvents,
[this]() {
m_http->PollRequests();
return m_http->HasAnyRequests();
},
HTTP_POLL_INTERVAL);
if (download_result.value_or(false))
{

View File

@ -281,7 +281,7 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
m_display_widget->setFocus();
updateWindowState();
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return m_display_widget->getWindowInfo();
}
@ -710,8 +710,7 @@ void MainWindow::quit()
if (s_system_valid)
{
g_emu_thread->shutdownSystem(false, true);
while (s_system_valid)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents, []() { return s_system_valid; });
}
// Big picture might still be active.
@ -749,9 +748,8 @@ void MainWindow::recreate()
if (was_display_created)
{
g_emu_thread->setSurfaceless(true);
while (m_display_widget || !g_emu_thread->isSurfaceless())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents,
[this]() { return (m_display_widget || !g_emu_thread->isSurfaceless()); });
m_display_created = false;
}
@ -2005,8 +2003,8 @@ void MainWindow::switchToGameListView()
// switch to surfaceless. we have to wait until the display widget is gone before we swap over.
g_emu_thread->setSurfaceless(true);
while (m_display_widget)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents,
[this]() { return static_cast<bool>(m_display_widget); });
}
}
@ -2915,12 +2913,11 @@ MainWindow::SystemLock MainWindow::pauseAndLockSystem()
g_emu_thread->setFullscreen(false, false);
// Container could change... thanks Wayland.
QWidget* container;
while (s_system_valid &&
(g_emu_thread->isFullscreen() || !(container = getDisplayContainer()) || container->isFullScreen()))
{
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents, [this]() {
QWidget* container;
return (s_system_valid &&
(g_emu_thread->isFullscreen() || !(container = getDisplayContainer()) || container->isFullScreen()));
});
}
if (!was_paused)
@ -2928,8 +2925,7 @@ MainWindow::SystemLock MainWindow::pauseAndLockSystem()
g_emu_thread->setSystemPaused(true);
// Need to wait for the pause to go through, and make the main window visible if needed.
while (!s_system_paused)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents, []() { return !s_system_paused; });
// Ensure it's visible before we try to create any dialogs parented to us.
QApplication::sync();

View File

@ -311,11 +311,13 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
&progress);
// Block until completion.
while (http->HasAnyRequests())
{
QApplication::processEvents(QEventLoop::AllEvents, HTTP_POLL_INTERVAL);
http->PollRequests();
}
QtUtils::ProcessEventsWithSleep(
QEventLoop::AllEvents,
[http = http.get()]() {
http->PollRequests();
return http->HasAnyRequests();
},
HTTP_POLL_INTERVAL);
return download_result;
}
@ -806,9 +808,8 @@ void EmuThread::stopFullscreenUI()
QMetaObject::invokeMethod(this, &EmuThread::stopFullscreenUI, Qt::QueuedConnection);
// wait until the host display is gone
while (!QtHost::IsSystemValid() && g_gpu_device)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents,
[]() { return (!QtHost::IsSystemValid() && g_gpu_device); });
return;
}
@ -1742,8 +1743,7 @@ void EmuThread::stop()
AssertMsg(!g_emu_thread->isOnThread(), "Not called on the emu thread");
QMetaObject::invokeMethod(g_emu_thread, &EmuThread::stopInThread, Qt::QueuedConnection);
while (g_emu_thread->isRunning())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QtUtils::ProcessEventsWithSleep(QEventLoop::ExcludeUserInputEvents, []() { return (g_emu_thread->isRunning()); });
}
void EmuThread::stopInThread()

View File

@ -8,8 +8,11 @@
#include "common/types.h"
#include <QtCore/QByteArray>
#include <QtCore/QCoreApplication>
#include <QtCore/QEventLoop>
#include <QtCore/QMetaType>
#include <QtCore/QString>
#include <QtCore/QTimer>
#include <QtGui/QIcon>
#include <QtWidgets/QWidget>
#include <functional>
@ -121,4 +124,30 @@ bool SaveWindowGeometry(std::string_view window_name, QWidget* widget, bool auto
/// Restores a window's geometry from configuration. Returns false if it was not found in the configuration.
bool RestoreWindowGeometry(std::string_view window_name, QWidget* widget);
/// CPU-friendly way of blocking the UI thread while some predicate holds true.
template<typename Predicate>
[[maybe_unused]] static void ProcessEventsWithSleep(QEventLoop::ProcessEventsFlags flags, const Predicate& pred,
int sleep_time_ms = 10)
{
if (sleep_time_ms == 0)
{
while (pred())
QCoreApplication::processEvents(flags);
}
if (!pred())
return;
QEventLoop loop;
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, &timer, [&loop, &pred]() {
if (pred())
return;
loop.exit();
});
timer.start(sleep_time_ms);
loop.exec(flags);
}
} // namespace QtUtils