From a3a70e56acfde2cf75dfd02a6c2f1828d28efe02 Mon Sep 17 00:00:00 2001
From: Sacha <xsacha@gmail.com>
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 <QHBoxLayout>
 #include <QKeyEvent>
+#include <QApplication>
 
 #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 <xsacha@gmail.com>
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 <QMutex>
 #include <QThread>
 #include <QGLWidget>
 #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 <xsacha@gmail.com>
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 <QMutex>
 #include <QThread>
 #include <QGLWidget>
+#include <atomic>
 #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<bool> stop_run;
 
     GRenderWindow* render_window;