From a3a70e56acfde2cf75dfd02a6c2f1828d28efe02 Mon Sep 17 00:00:00 2001 From: Sacha Date: Mon, 25 Aug 2014 00:47:00 +1000 Subject: [PATCH 1/3] Fix the threading for GL Context in Qt5. Connect the emu_thread start/finish to a moveContext slot. --- src/citra_qt/bootmanager.cpp | 22 ++++++++++++++++------ src/citra_qt/bootmanager.hxx | 5 +++++ src/citra_qt/main.cpp | 3 --- src/video_core/video_core.cpp | 1 - 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b0aa1e561..73f25e691 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "common/common.h" #include "bootmanager.hxx" @@ -79,15 +80,11 @@ class GGLWidgetInternal : public QGLWidget public: GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(parent) { - doneCurrent(); parent_ = parent; } void paintEvent(QPaintEvent* ev) { - // Apparently, Windows doesn't display anything if we don't call this here. - // TODO: Breaks linux though because we aren't calling doneCurrent() ... -.- -// makeCurrent(); } void resizeEvent(QResizeEvent* ev) { parent_->SetClientAreaWidth(size().width()); @@ -118,10 +115,22 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this layout->addWidget(child); layout->setMargin(0); setLayout(layout); + QObject::connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext())); + QObject::connect(&emu_thread, SIGNAL(finished()), this, SLOT(moveContext())); BackupGeometry(); } +void GRenderWindow::moveContext() +{ + DoneCurrent(); + // We need to move GL context to the swapping thread in Qt5 +#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) + // If the thread started running, move the GL Context to the new thread. Otherwise, move it back. + child->context()->moveToThread(emu_thread.isRunning() ? &emu_thread : qApp->thread()); +#endif +} + GRenderWindow::~GRenderWindow() { emu_thread.Stop(); @@ -129,7 +138,7 @@ GRenderWindow::~GRenderWindow() void GRenderWindow::SwapBuffers() { - child->makeCurrent(); // TODO: Not necessary? + // MakeCurrent is already called in renderer_opengl child->swapBuffers(); } @@ -212,4 +221,5 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) if (!key_processed) QWidget::keyPressEvent(event); */ -} \ No newline at end of file +} + diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index b4005ccbb..c4a4299b1 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -81,6 +81,8 @@ signals: class GRenderWindow : public QWidget, public EmuWindow { + Q_OBJECT + public: GRenderWindow(QWidget* parent = NULL); ~GRenderWindow(); @@ -103,6 +105,9 @@ public: void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); +private slots: + void moveContext(); + private: QGLWidget* child; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index e5190d48a..9a16cf92d 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -142,7 +142,6 @@ void GMainWindow::BootGame(std::string filename) registersWidget->OnCPUStepped(); callstackWidget->OnCPUStepped(); - render_window->DoneCurrent(); // make sure EmuThread can access GL context render_window->GetEmuThread().SetFilename(filename); render_window->GetEmuThread().start(); @@ -204,7 +203,6 @@ void GMainWindow::ToggleWindowMode() ui.horizontalLayout->removeWidget(render_window); render_window->setParent(NULL); render_window->setVisible(true); - render_window->DoneCurrent(); render_window->RestoreGeometry(); } else if (!enable && render_window->parent() == NULL) @@ -212,7 +210,6 @@ void GMainWindow::ToggleWindowMode() render_window->BackupGeometry(); ui.horizontalLayout->addWidget(render_window); render_window->setVisible(true); - render_window->DoneCurrent(); } } diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 087b08026..a1c7b6339 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -36,7 +36,6 @@ void Init(EmuWindow* emu_window) { glewExperimental = GL_TRUE; g_emu_window = emu_window; - g_emu_window->MakeCurrent(); g_renderer = new RendererOpenGL(); g_renderer->SetWindow(g_emu_window); g_renderer->Init(); From b044510fa946f1eab7e3b5917eba518b9631835a Mon Sep 17 00:00:00 2001 From: Sacha Date: Mon, 25 Aug 2014 01:49:34 +1000 Subject: [PATCH 2/3] Fix EmuThread loop by ensuring it exits properly. Note: There is a pre-existing issue with booting a new game in that it keeps the old EmuThread. The GL code now supports this but the Core still doesn't. --- src/citra_qt/bootmanager.cpp | 33 +++++++++++++++++++++++++-------- src/citra_qt/bootmanager.hxx | 5 ++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 73f25e691..2407f3a3a 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -20,7 +20,8 @@ EmuThread::EmuThread(GRenderWindow* render_window) : exec_cpu_step(false), cpu_running(false), - render_window(render_window), filename("") + render_window(render_window), filename(""), + stop_run(false) { } @@ -31,6 +32,7 @@ void EmuThread::SetFilename(std::string filename) void EmuThread::run() { + stop_run = false; while (true) { for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) @@ -41,11 +43,17 @@ void EmuThread::run() exec_cpu_step = false; Core::SingleStep(); - if (!cpu_running) + if (!cpu_running) { emit CPUStepped(); + yieldCurrentThread(); + } } } + QMutexLocker lock(&mutex); + if (stop_run) + break; } + render_window->moveContext(); Core::Stop(); } @@ -58,16 +66,24 @@ void EmuThread::Stop() return; } + { + QMutexLocker lock(&mutex); + stop_run = true; + } + //core::g_state = core::SYS_DIE; - wait(1000); + wait(500); if (isRunning()) { WARN_LOG(MASTER_LOG, "EmuThread still running, terminating..."); - terminate(); + quit(); wait(1000); if (isRunning()) + { WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here..."); + terminate(); + } } INFO_LOG(MASTER_LOG, "EmuThread stopped"); } @@ -116,7 +132,6 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this layout->setMargin(0); setLayout(layout); QObject::connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext())); - QObject::connect(&emu_thread, SIGNAL(finished()), this, SLOT(moveContext())); BackupGeometry(); } @@ -127,13 +142,14 @@ void GRenderWindow::moveContext() // We need to move GL context to the swapping thread in Qt5 #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) // If the thread started running, move the GL Context to the new thread. Otherwise, move it back. - child->context()->moveToThread(emu_thread.isRunning() ? &emu_thread : qApp->thread()); + child->context()->moveToThread((QThread::currentThread() == qApp->thread()) ? &emu_thread : qApp->thread()); #endif } GRenderWindow::~GRenderWindow() { - emu_thread.Stop(); + if (emu_thread.isRunning()) + emu_thread.Stop(); } void GRenderWindow::SwapBuffers() @@ -144,7 +160,8 @@ void GRenderWindow::SwapBuffers() void GRenderWindow::closeEvent(QCloseEvent* event) { - emu_thread.Stop(); + if (emu_thread.isRunning()) + emu_thread.Stop(); QWidget::closeEvent(event); } diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index c4a4299b1..4c3e2f0a4 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -1,3 +1,4 @@ +#include #include #include #include "common/common.h" @@ -66,6 +67,8 @@ private: bool exec_cpu_step; bool cpu_running; + bool stop_run; + QMutex mutex; GRenderWindow* render_window; @@ -105,7 +108,7 @@ public: void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); -private slots: +public slots: void moveContext(); private: From 1b1205cf739d0913dd474779245fd59dccbf2fcf Mon Sep 17 00:00:00 2001 From: Sacha Date: Mon, 25 Aug 2014 03:42:52 +1000 Subject: [PATCH 3/3] Pass format to the QGLWidget and use atomic instead of mutex. --- src/citra_qt/bootmanager.cpp | 13 +++---------- src/citra_qt/bootmanager.hxx | 5 ++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 2407f3a3a..573060d30 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -33,7 +33,7 @@ void EmuThread::SetFilename(std::string filename) void EmuThread::run() { stop_run = false; - while (true) + while (!stop_run) { for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) { @@ -49,9 +49,6 @@ void EmuThread::run() } } } - QMutexLocker lock(&mutex); - if (stop_run) - break; } render_window->moveContext(); @@ -65,11 +62,7 @@ void EmuThread::Stop() INFO_LOG(MASTER_LOG, "EmuThread::Stop called while emu thread wasn't running, returning..."); return; } - - { - QMutexLocker lock(&mutex); - stop_run = true; - } + stop_run = true; //core::g_state = core::SYS_DIE; @@ -94,7 +87,7 @@ void EmuThread::Stop() class GGLWidgetInternal : public QGLWidget { public: - GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(parent) + GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(fmt, parent) { parent_ = parent; } diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index 4c3e2f0a4..51cb781e9 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -1,6 +1,6 @@ -#include #include #include +#include #include "common/common.h" #include "common/emu_window.h" @@ -67,8 +67,7 @@ private: bool exec_cpu_step; bool cpu_running; - bool stop_run; - QMutex mutex; + std::atomic stop_run; GRenderWindow* render_window;