summaryrefslogtreecommitdiff
path: root/src/citra_qt/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt/main.cpp')
-rw-r--r--src/citra_qt/main.cpp68
1 files changed, 46 insertions, 22 deletions
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index dd180baa4..7de2bf8ba 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -15,6 +15,7 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/logging/backend.h" 16#include "common/logging/backend.h"
17#include "common/logging/filter.h" 17#include "common/logging/filter.h"
18#include "common/make_unique.h"
18#include "common/platform.h" 19#include "common/platform.h"
19#include "common/scope_exit.h" 20#include "common/scope_exit.h"
20 21
@@ -55,14 +56,14 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
55 ui.setupUi(this); 56 ui.setupUi(this);
56 statusBar()->hide(); 57 statusBar()->hide();
57 58
58 render_window = new GRenderWindow(this, *this); 59 render_window = new GRenderWindow(this, emu_thread.get());
59 render_window->hide(); 60 render_window->hide();
60 61
61 profilerWidget = new ProfilerWidget(this); 62 profilerWidget = new ProfilerWidget(this);
62 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); 63 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
63 profilerWidget->hide(); 64 profilerWidget->hide();
64 65
65 disasmWidget = new DisassemblerWidget(this, *this); 66 disasmWidget = new DisassemblerWidget(this, emu_thread.get());
66 addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); 67 addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
67 disasmWidget->hide(); 68 disasmWidget->hide();
68 69
@@ -138,14 +139,10 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
138 connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); 139 connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode()));
139 connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); 140 connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));
140 141
141 // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues 142 connect(this, SIGNAL(EmulationStarted(EmuThread*)), disasmWidget, SLOT(OnEmulationStarted(EmuThread*)));
142 connect(emu_thread, SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); 143 connect(this, SIGNAL(EmulationStopped()), disasmWidget, SLOT(OnEmulationStopped()));
143 connect(emu_thread, SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); 144 connect(this, SIGNAL(EmulationStarted(EmuThread*)), render_window, SLOT(OnEmulationStarted(EmuThread*)));
144 connect(emu_thread, SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); 145 connect(this, SIGNAL(EmulationStopped()), render_window, SLOT(OnEmulationStopped()));
145
146 connect(emu_thread, SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
147 connect(emu_thread, SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
148 connect(emu_thread, SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
149 146
150 // Setup hotkeys 147 // Setup hotkeys
151 RegisterHotkey("Main Window", "Load File", QKeySequence::Open); 148 RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
@@ -199,35 +196,62 @@ void GMainWindow::OnDisplayTitleBars(bool show)
199void GMainWindow::BootGame(std::string filename) { 196void GMainWindow::BootGame(std::string filename) {
200 LOG_INFO(Frontend, "Citra starting...\n"); 197 LOG_INFO(Frontend, "Citra starting...\n");
201 198
199 // Initialize the core emulation
202 System::Init(render_window); 200 System::Init(render_window);
203 201
204 // Load a game or die... 202 // Load the game
205 if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { 203 if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) {
206 LOG_CRITICAL(Frontend, "Failed to load ROM!"); 204 LOG_CRITICAL(Frontend, "Failed to load ROM!");
205 System::Shutdown();
206 return;
207 } 207 }
208 208
209 disasmWidget->Init(); 209 // Create and start the emulation thread
210 registersWidget->OnDebugModeEntered(); 210 emu_thread = Common::make_unique<EmuThread>(render_window);
211 callstackWidget->OnDebugModeEntered(); 211 emit EmulationStarted(emu_thread.get());
212
213 emu_thread = new EmuThread(render_window);
214 emu_thread->start(); 212 emu_thread->start();
215 213
214 // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues
215 connect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
216 connect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
217 connect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
218 connect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
219 connect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
220 connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
221
222 // Update the GUI
223 registersWidget->OnDebugModeEntered();
224 callstackWidget->OnDebugModeEntered();
216 render_window->show(); 225 render_window->show();
226
217 OnStartGame(); 227 OnStartGame();
218} 228}
219 229
220void GMainWindow::ShutdownGame() { 230void GMainWindow::ShutdownGame() {
221 // Shutdown the emulation thread and wait for it to complete 231 // Shutdown the emulation thread
222 emu_thread->SetRunning(false); 232 emu_thread->RequestShutdown();
223 emu_thread->Shutdown(); 233
224 emu_thread->wait(); 234 // Disconnect signals that are attached to the current emulation thread
225 delete emu_thread; 235 disconnect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()));
226 emu_thread = nullptr; 236 disconnect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()));
237 disconnect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()));
238 disconnect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()));
239 disconnect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()));
240 disconnect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()));
227 241
228 // Release emu threads from any breakpoints 242 // Release emu threads from any breakpoints
243 // This belongs after RequestShutdown() and before wait() because if emulation stops on a GPU
244 // breakpoint after (or before) RequestShutdown() is called, the emulation would never be able
245 // to continue out to the main loop and terminate. Thus wait() would hang forever.
246 // TODO(bunnei): This function is not thread safe, but it's being used as if it were
229 Pica::g_debug_context->ClearBreakpoints(); 247 Pica::g_debug_context->ClearBreakpoints();
230 248
249 emit EmulationStopped();
250
251 // Wait for emulation thread to complete and delete it
252 emu_thread->wait();
253 emu_thread = nullptr;
254
231 // Shutdown the core emulation 255 // Shutdown the core emulation
232 System::Shutdown(); 256 System::Shutdown();
233 257