diff options
Diffstat (limited to 'src/citra_qt/main.cpp')
| -rw-r--r-- | src/citra_qt/main.cpp | 68 |
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) | |||
| 199 | void GMainWindow::BootGame(std::string filename) { | 196 | void 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 | ||
| 220 | void GMainWindow::ShutdownGame() { | 230 | void 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 | ||