Qt: Rearchitect game closing codepath
Jeffrey Pfau jeffrey@endrift.com
Tue, 30 Aug 2016 23:43:50 -0700
6 files changed,
25 insertions(+),
19 deletions(-)
M
src/platform/qt/AudioProcessor.h
→
src/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.h
→
src/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.h
→
src/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.cpp
→
src/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.h
→
src/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();