all repos — mgba @ e078e42c8374d61f49a23abaea9258d623e3182f

mGBA Game Boy Advance Emulator

Qt: Rearchitect game closing codepath
Jeffrey Pfau jeffrey@endrift.com
Tue, 30 Aug 2016 23:43:50 -0700
commit

e078e42c8374d61f49a23abaea9258d623e3182f

parent

f15bb076b826c7b3a993a7faf3c14bcae2bcc7ab

M CHANGESCHANGES

@@ -85,6 +85,7 @@ - GUI: Only reload config if manually saved

- GBA Serialize: Savestates now store if CPU was halted - PSP2: Stop underclocking when menuing - GUI: Increase scrolling speed + - Qt: Rearchitect game closing codepath 0.4.1: (2016-07-11) Bugfixes:
M src/platform/qt/AudioProcessor.hsrc/platform/qt/AudioProcessor.h

@@ -29,11 +29,12 @@ static void setDriver(Driver driver) { s_driver = driver; }

AudioProcessor(QObject* parent = nullptr); - virtual void setInput(mCoreThread* input); int getBufferSamples() const { return m_samples; } virtual unsigned sampleRate() const = 0; public slots: + virtual void setInput(mCoreThread* input); + virtual bool start() = 0; virtual void pause() = 0;
M src/platform/qt/AudioProcessorQt.hsrc/platform/qt/AudioProcessorQt.h

@@ -19,10 +19,10 @@

public: AudioProcessorQt(QObject* parent = nullptr); - virtual void setInput(mCoreThread* input) override; virtual unsigned sampleRate() const override; public slots: + virtual void setInput(mCoreThread* input) override; virtual bool start() override; virtual void pause() override;
M src/platform/qt/AudioProcessorSDL.hsrc/platform/qt/AudioProcessorSDL.h

@@ -22,10 +22,10 @@ public:

AudioProcessorSDL(QObject* parent = nullptr); ~AudioProcessorSDL(); - virtual void setInput(mCoreThread* input) override; virtual unsigned sampleRate() const override; public slots: + virtual void setInput(mCoreThread* input) override; virtual bool start() override; virtual void pause() override;
M src/platform/qt/GameController.cppsrc/platform/qt/GameController.cpp

@@ -84,9 +84,6 @@ setLuminanceLevel(0);

m_threadContext.startCallback = [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - if (controller->m_audioProcessor) { - controller->m_audioProcessor->setInput(context); - } mRTCGenericSourceInit(&controller->m_rtc, context->core); context->core->setRTC(context->core, &controller->m_rtc.d); context->core->setRotation(context->core, controller->m_inputController->rotationSource());

@@ -132,9 +129,9 @@ if (mCoreLoadState(context->core, 0, controller->m_loadStateFlags)) {

mCoreDeleteState(context->core, 0); } - mCoreThreadInterruptFromThread(context); - QMetaObject::invokeMethod(controller, "gameStarted", Qt::BlockingQueuedConnection, Q_ARG(mCoreThread*, context), Q_ARG(const QString&, controller->m_fname)); - mCoreThreadContinue(context); + controller->m_gameOpen = true; + QMetaObject::invokeMethod(controller, "gameStarted", Q_ARG(mCoreThread*, context), Q_ARG(const QString&, controller->m_fname)); + QMetaObject::invokeMethod(controller, "startAudio"); }; m_threadContext.resetCallback = [](mCoreThread* context) {

@@ -157,6 +154,7 @@

m_threadContext.cleanCallback = [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); QMetaObject::invokeMethod(controller, "gameStopped", Q_ARG(mCoreThread*, context)); + QMetaObject::invokeMethod(controller, "cleanGame"); }; m_threadContext.frameCallback = [](mCoreThread* context) {

@@ -238,6 +236,7 @@ m_audioThread->setObjectName("Audio Thread");

m_audioThread->start(QThread::TimeCriticalPriority); m_audioProcessor->moveToThread(m_audioThread); connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause())); + connect(this, SIGNAL(gameStarted(mCoreThread*, const QString&)), m_audioProcessor, SLOT(setInput(mCoreThread*))); connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(pollEvents())); connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(updateAutofire())); }

@@ -330,6 +329,13 @@ void GameController::openGame(bool biosOnly) {

if (biosOnly && (!m_useBios || m_bios.isNull())) { return; } + if (m_gameOpen) { + // We need to delay if the game is still cleaning up + QTimer::singleShot(10, [this, biosOnly]() { + openGame(biosOnly); + }); + return; + } if (!biosOnly) { if (m_vf) {

@@ -344,8 +350,6 @@

if (!m_threadContext.core) { return; } - - m_gameOpen = true; m_pauseAfterFrame = false;

@@ -413,10 +417,7 @@ }

m_vf = nullptr; if (!mCoreThreadStart(&m_threadContext)) { - m_gameOpen = false; emit gameFailed(); - } else if (m_audioProcessor) { - startAudio(); } }

@@ -520,16 +521,16 @@ void GameController::closeGame() {

if (!m_gameOpen) { return; } - m_gameOpen = false; if (mCoreThreadIsPaused(&m_threadContext)) { mCoreThreadUnpause(&m_threadContext); } + mCoreThreadEnd(&m_threadContext); m_audioProcessor->pause(); - mCoreThreadEnd(&m_threadContext); +} + +void GameController::cleanGame() { mCoreThreadJoin(&m_threadContext); - // Make sure the event queue clears out before the thread is reused - QCoreApplication::processEvents(); delete[] m_drawContext; delete[] m_frontBuffer;

@@ -537,10 +538,11 @@

m_patch = QString(); m_threadContext.core->deinit(m_threadContext.core); + m_gameOpen = false; } void GameController::crashGame(const QString& crashMessage) { - closeGame(); + cleanGame(); emit gameCrashed(crashMessage); emit gameStopped(&m_threadContext); }

@@ -1002,6 +1004,7 @@ m_audioProcessor->requestSampleRate(sampleRate);

} m_audioProcessor->moveToThread(m_audioThread); connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause())); + connect(this, SIGNAL(gameStarted(mCoreThread*, const QString&)), m_audioProcessor, SLOT(setInput(mCoreThread*))); if (isLoaded()) { m_audioProcessor->setInput(&m_threadContext); startAudio();
M src/platform/qt/GameController.hsrc/platform/qt/GameController.h

@@ -163,6 +163,7 @@

private slots: void openGame(bool bios = false); void crashGame(const QString& crashMessage); + void cleanGame(); void pollEvents(); void updateAutofire();