Qt: Rearchitect game closing codepath

This commit is contained in:
Jeffrey Pfau 2016-08-30 23:43:50 -07:00
parent f15bb076b8
commit e078e42c83
6 changed files with 25 additions and 19 deletions

View File

@ -85,6 +85,7 @@ Misc:
- GBA Serialize: Savestates now store if CPU was halted - GBA Serialize: Savestates now store if CPU was halted
- PSP2: Stop underclocking when menuing - PSP2: Stop underclocking when menuing
- GUI: Increase scrolling speed - GUI: Increase scrolling speed
- Qt: Rearchitect game closing codepath
0.4.1: (2016-07-11) 0.4.1: (2016-07-11)
Bugfixes: Bugfixes:

View File

@ -29,11 +29,12 @@ public:
AudioProcessor(QObject* parent = nullptr); AudioProcessor(QObject* parent = nullptr);
virtual void setInput(mCoreThread* input);
int getBufferSamples() const { return m_samples; } int getBufferSamples() const { return m_samples; }
virtual unsigned sampleRate() const = 0; virtual unsigned sampleRate() const = 0;
public slots: public slots:
virtual void setInput(mCoreThread* input);
virtual bool start() = 0; virtual bool start() = 0;
virtual void pause() = 0; virtual void pause() = 0;

View File

@ -19,10 +19,10 @@ Q_OBJECT
public: public:
AudioProcessorQt(QObject* parent = nullptr); AudioProcessorQt(QObject* parent = nullptr);
virtual void setInput(mCoreThread* input) override;
virtual unsigned sampleRate() const override; virtual unsigned sampleRate() const override;
public slots: public slots:
virtual void setInput(mCoreThread* input) override;
virtual bool start() override; virtual bool start() override;
virtual void pause() override; virtual void pause() override;

View File

@ -22,10 +22,10 @@ public:
AudioProcessorSDL(QObject* parent = nullptr); AudioProcessorSDL(QObject* parent = nullptr);
~AudioProcessorSDL(); ~AudioProcessorSDL();
virtual void setInput(mCoreThread* input) override;
virtual unsigned sampleRate() const override; virtual unsigned sampleRate() const override;
public slots: public slots:
virtual void setInput(mCoreThread* input) override;
virtual bool start() override; virtual bool start() override;
virtual void pause() override; virtual void pause() override;

View File

@ -84,9 +84,6 @@ GameController::GameController(QObject* parent)
m_threadContext.startCallback = [](mCoreThread* context) { m_threadContext.startCallback = [](mCoreThread* context) {
GameController* controller = static_cast<GameController*>(context->userData); GameController* controller = static_cast<GameController*>(context->userData);
if (controller->m_audioProcessor) {
controller->m_audioProcessor->setInput(context);
}
mRTCGenericSourceInit(&controller->m_rtc, context->core); mRTCGenericSourceInit(&controller->m_rtc, context->core);
context->core->setRTC(context->core, &controller->m_rtc.d); context->core->setRTC(context->core, &controller->m_rtc.d);
context->core->setRotation(context->core, controller->m_inputController->rotationSource()); context->core->setRotation(context->core, controller->m_inputController->rotationSource());
@ -132,9 +129,9 @@ GameController::GameController(QObject* parent)
mCoreDeleteState(context->core, 0); mCoreDeleteState(context->core, 0);
} }
mCoreThreadInterruptFromThread(context); controller->m_gameOpen = true;
QMetaObject::invokeMethod(controller, "gameStarted", Qt::BlockingQueuedConnection, Q_ARG(mCoreThread*, context), Q_ARG(const QString&, controller->m_fname)); QMetaObject::invokeMethod(controller, "gameStarted", Q_ARG(mCoreThread*, context), Q_ARG(const QString&, controller->m_fname));
mCoreThreadContinue(context); QMetaObject::invokeMethod(controller, "startAudio");
}; };
m_threadContext.resetCallback = [](mCoreThread* context) { m_threadContext.resetCallback = [](mCoreThread* context) {
@ -157,6 +154,7 @@ GameController::GameController(QObject* parent)
m_threadContext.cleanCallback = [](mCoreThread* context) { m_threadContext.cleanCallback = [](mCoreThread* context) {
GameController* controller = static_cast<GameController*>(context->userData); GameController* controller = static_cast<GameController*>(context->userData);
QMetaObject::invokeMethod(controller, "gameStopped", Q_ARG(mCoreThread*, context)); QMetaObject::invokeMethod(controller, "gameStopped", Q_ARG(mCoreThread*, context));
QMetaObject::invokeMethod(controller, "cleanGame");
}; };
m_threadContext.frameCallback = [](mCoreThread* context) { m_threadContext.frameCallback = [](mCoreThread* context) {
@ -238,6 +236,7 @@ GameController::GameController(QObject* parent)
m_audioThread->start(QThread::TimeCriticalPriority); m_audioThread->start(QThread::TimeCriticalPriority);
m_audioProcessor->moveToThread(m_audioThread); m_audioProcessor->moveToThread(m_audioThread);
connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause())); 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(pollEvents()));
connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(updateAutofire())); 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())) { if (biosOnly && (!m_useBios || m_bios.isNull())) {
return; 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 (!biosOnly) {
if (m_vf) { if (m_vf) {
@ -345,8 +351,6 @@ void GameController::openGame(bool biosOnly) {
return; return;
} }
m_gameOpen = true;
m_pauseAfterFrame = false; m_pauseAfterFrame = false;
if (m_turbo) { if (m_turbo) {
@ -413,10 +417,7 @@ void GameController::openGame(bool biosOnly) {
m_vf = nullptr; m_vf = nullptr;
if (!mCoreThreadStart(&m_threadContext)) { if (!mCoreThreadStart(&m_threadContext)) {
m_gameOpen = false;
emit gameFailed(); emit gameFailed();
} else if (m_audioProcessor) {
startAudio();
} }
} }
@ -520,16 +521,16 @@ void GameController::closeGame() {
if (!m_gameOpen) { if (!m_gameOpen) {
return; return;
} }
m_gameOpen = false;
if (mCoreThreadIsPaused(&m_threadContext)) { if (mCoreThreadIsPaused(&m_threadContext)) {
mCoreThreadUnpause(&m_threadContext); mCoreThreadUnpause(&m_threadContext);
} }
m_audioProcessor->pause();
mCoreThreadEnd(&m_threadContext); mCoreThreadEnd(&m_threadContext);
m_audioProcessor->pause();
}
void GameController::cleanGame() {
mCoreThreadJoin(&m_threadContext); mCoreThreadJoin(&m_threadContext);
// Make sure the event queue clears out before the thread is reused
QCoreApplication::processEvents();
delete[] m_drawContext; delete[] m_drawContext;
delete[] m_frontBuffer; delete[] m_frontBuffer;
@ -537,10 +538,11 @@ void GameController::closeGame() {
m_patch = QString(); m_patch = QString();
m_threadContext.core->deinit(m_threadContext.core); m_threadContext.core->deinit(m_threadContext.core);
m_gameOpen = false;
} }
void GameController::crashGame(const QString& crashMessage) { void GameController::crashGame(const QString& crashMessage) {
closeGame(); cleanGame();
emit gameCrashed(crashMessage); emit gameCrashed(crashMessage);
emit gameStopped(&m_threadContext); emit gameStopped(&m_threadContext);
} }
@ -1002,6 +1004,7 @@ void GameController::reloadAudioDriver() {
} }
m_audioProcessor->moveToThread(m_audioThread); m_audioProcessor->moveToThread(m_audioThread);
connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause())); connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause()));
connect(this, SIGNAL(gameStarted(mCoreThread*, const QString&)), m_audioProcessor, SLOT(setInput(mCoreThread*)));
if (isLoaded()) { if (isLoaded()) {
m_audioProcessor->setInput(&m_threadContext); m_audioProcessor->setInput(&m_threadContext);
startAudio(); startAudio();

View File

@ -163,6 +163,7 @@ public slots:
private slots: private slots:
void openGame(bool bios = false); void openGame(bool bios = false);
void crashGame(const QString& crashMessage); void crashGame(const QString& crashMessage);
void cleanGame();
void pollEvents(); void pollEvents();
void updateAutofire(); void updateAutofire();