Core: Make threading optionally opaque

This commit is contained in:
Vicki Pfau 2017-06-22 19:57:52 -07:00
parent dc60c28bf1
commit e1325b0373
9 changed files with 315 additions and 278 deletions

View File

@ -11,15 +11,40 @@
CXX_GUARD_START CXX_GUARD_START
#include <mgba/core/log.h> #include <mgba/core/log.h>
#include <mgba/core/rewind.h>
#include <mgba/core/sync.h>
#include <mgba-util/threading.h>
struct mCoreThread; struct mCoreThread;
struct mCore; struct mCore;
typedef void (*ThreadCallback)(struct mCoreThread* threadContext); typedef void (*ThreadCallback)(struct mCoreThread* threadContext);
struct mCoreThread;
struct mThreadLogger {
struct mLogger d;
struct mCoreThread* p;
};
struct mCoreThreadInternal;
struct mCoreThread {
// Input
struct mCore* core;
struct mThreadLogger logger;
ThreadCallback startCallback;
ThreadCallback resetCallback;
ThreadCallback cleanCallback;
ThreadCallback frameCallback;
ThreadCallback sleepCallback;
void* userData;
void (*run)(struct mCoreThread*);
struct mCoreThreadInternal* impl;
};
#ifndef OPAQUE_THREADING
#include <mgba/core/rewind.h>
#include <mgba/core/sync.h>
#include <mgba-util/threading.h>
enum mCoreThreadState { enum mCoreThreadState {
THREAD_INITIALIZED = -1, THREAD_INITIALIZED = -1,
THREAD_RUNNING = 0, THREAD_RUNNING = 0,
@ -37,17 +62,7 @@ enum mCoreThreadState {
THREAD_CRASHED THREAD_CRASHED
}; };
struct mCoreThread; struct mCoreThreadInternal {
struct mThreadLogger {
struct mLogger d;
struct mCoreThread* p;
};
struct mCoreThread {
// Input
struct mCore* core;
// Threading state
Thread thread; Thread thread;
enum mCoreThreadState state; enum mCoreThreadState state;
@ -57,19 +72,12 @@ struct mCoreThread {
int interruptDepth; int interruptDepth;
bool frameWasOn; bool frameWasOn;
struct mThreadLogger logger;
ThreadCallback startCallback;
ThreadCallback resetCallback;
ThreadCallback cleanCallback;
ThreadCallback frameCallback;
ThreadCallback sleepCallback;
void* userData;
void (*run)(struct mCoreThread*);
struct mCoreSync sync; struct mCoreSync sync;
struct mCoreRewindContext rewind; struct mCoreRewindContext rewind;
}; };
#endif
bool mCoreThreadStart(struct mCoreThread* threadContext); bool mCoreThreadStart(struct mCoreThread* threadContext);
bool mCoreThreadHasStarted(struct mCoreThread* threadContext); bool mCoreThreadHasStarted(struct mCoreThread* threadContext);
bool mCoreThreadHasExited(struct mCoreThread* threadContext); bool mCoreThreadHasExited(struct mCoreThread* threadContext);

View File

@ -38,7 +38,7 @@ static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) {
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args); static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args);
static void _changeState(struct mCoreThread* threadContext, enum mCoreThreadState newState, bool broadcast) { static void _changeState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState newState, bool broadcast) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->stateMutex);
threadContext->state = newState; threadContext->state = newState;
if (broadcast) { if (broadcast) {
@ -47,13 +47,13 @@ static void _changeState(struct mCoreThread* threadContext, enum mCoreThreadStat
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->stateMutex);
} }
static void _waitOnInterrupt(struct mCoreThread* threadContext) { static void _waitOnInterrupt(struct mCoreThreadInternal* threadContext) {
while (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) { while (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
} }
} }
static void _waitUntilNotState(struct mCoreThread* threadContext, enum mCoreThreadState oldState) { static void _waitUntilNotState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState oldState) {
MutexLock(&threadContext->sync.videoFrameMutex); MutexLock(&threadContext->sync.videoFrameMutex);
bool videoFrameWait = threadContext->sync.videoFrameWait; bool videoFrameWait = threadContext->sync.videoFrameWait;
threadContext->sync.videoFrameWait = false; threadContext->sync.videoFrameWait = false;
@ -81,7 +81,7 @@ static void _waitUntilNotState(struct mCoreThread* threadContext, enum mCoreThre
MutexUnlock(&threadContext->sync.videoFrameMutex); MutexUnlock(&threadContext->sync.videoFrameMutex);
} }
static void _pauseThread(struct mCoreThread* threadContext) { static void _pauseThread(struct mCoreThreadInternal* threadContext) {
threadContext->state = THREAD_PAUSING; threadContext->state = THREAD_PAUSING;
_waitUntilNotState(threadContext, THREAD_PAUSING); _waitUntilNotState(threadContext, THREAD_PAUSING);
} }
@ -92,11 +92,11 @@ void _frameStarted(void* context) {
return; return;
} }
if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) { if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) {
if (thread->state != THREAD_REWINDING) { if (thread->impl->state != THREAD_REWINDING) {
mCoreRewindAppend(&thread->rewind, thread->core); mCoreRewindAppend(&thread->impl->rewind, thread->core);
} else if (thread->state == THREAD_REWINDING) { } else if (thread->impl->state == THREAD_REWINDING) {
if (!mCoreRewindRestore(&thread->rewind, thread->core)) { if (!mCoreRewindRestore(&thread->impl->rewind, thread->core)) {
mCoreRewindAppend(&thread->rewind, thread->core); mCoreRewindAppend(&thread->impl->rewind, thread->core);
} }
} }
} }
@ -117,7 +117,7 @@ void _crashed(void* context) {
if (!thread) { if (!thread) {
return; return;
} }
_changeState(thread, THREAD_CRASHED, true); _changeState(thread->impl, THREAD_CRASHED, true);
} }
void _coreSleep(void* context) { void _coreSleep(void* context) {
@ -157,7 +157,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
.context = threadContext .context = threadContext
}; };
core->addCoreCallbacks(core, &callbacks); core->addCoreCallbacks(core, &callbacks);
core->setSync(core, &threadContext->sync); core->setSync(core, &threadContext->impl->sync);
core->reset(core); core->reset(core);
struct mLogFilter filter; struct mLogFilter filter;
@ -168,11 +168,11 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
} }
if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) { if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) {
mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity, true); mCoreRewindContextInit(&threadContext->impl->rewind, core->opts.rewindBufferCapacity, true);
threadContext->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0; threadContext->impl->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0;
} }
_changeState(threadContext, THREAD_RUNNING, true); _changeState(threadContext->impl, THREAD_RUNNING, true);
if (threadContext->startCallback) { if (threadContext->startCallback) {
threadContext->startCallback(threadContext); threadContext->startCallback(threadContext);
@ -181,49 +181,50 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
threadContext->resetCallback(threadContext); threadContext->resetCallback(threadContext);
} }
while (threadContext->state < THREAD_EXITING) { struct mCoreThreadInternal* impl = threadContext->impl;
while (impl->state < THREAD_EXITING) {
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
struct mDebugger* debugger = core->debugger; struct mDebugger* debugger = core->debugger;
if (debugger) { if (debugger) {
mDebuggerRun(debugger); mDebuggerRun(debugger);
if (debugger->state == DEBUGGER_SHUTDOWN) { if (debugger->state == DEBUGGER_SHUTDOWN) {
_changeState(threadContext, THREAD_EXITING, false); _changeState(impl, THREAD_EXITING, false);
} }
} else } else
#endif #endif
{ {
while (threadContext->state <= THREAD_MAX_RUNNING) { while (impl->state <= THREAD_MAX_RUNNING) {
core->runLoop(core); core->runLoop(core);
} }
} }
int resetScheduled = 0; int resetScheduled = 0;
MutexLock(&threadContext->stateMutex); MutexLock(&impl->stateMutex);
while (threadContext->state > THREAD_MAX_RUNNING && threadContext->state < THREAD_EXITING) { while (impl->state > THREAD_MAX_RUNNING && impl->state < THREAD_EXITING) {
if (threadContext->state == THREAD_PAUSING) { if (impl->state == THREAD_PAUSING) {
threadContext->state = THREAD_PAUSED; impl->state = THREAD_PAUSED;
ConditionWake(&threadContext->stateCond); ConditionWake(&impl->stateCond);
} }
if (threadContext->state == THREAD_INTERRUPTING) { if (impl->state == THREAD_INTERRUPTING) {
threadContext->state = THREAD_INTERRUPTED; impl->state = THREAD_INTERRUPTED;
ConditionWake(&threadContext->stateCond); ConditionWake(&impl->stateCond);
} }
if (threadContext->state == THREAD_RUN_ON) { if (impl->state == THREAD_RUN_ON) {
if (threadContext->run) { if (threadContext->run) {
threadContext->run(threadContext); threadContext->run(threadContext);
} }
threadContext->state = threadContext->savedState; impl->state = impl->savedState;
ConditionWake(&threadContext->stateCond); ConditionWake(&impl->stateCond);
} }
if (threadContext->state == THREAD_RESETING) { if (impl->state == THREAD_RESETING) {
threadContext->state = THREAD_RUNNING; impl->state = THREAD_RUNNING;
resetScheduled = 1; resetScheduled = 1;
} }
while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_WAITING) { while (impl->state == THREAD_PAUSED || impl->state == THREAD_INTERRUPTED || impl->state == THREAD_WAITING) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); ConditionWait(&impl->stateCond, &impl->stateMutex);
} }
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&impl->stateMutex);
if (resetScheduled) { if (resetScheduled) {
core->reset(core); core->reset(core);
if (threadContext->resetCallback) { if (threadContext->resetCallback) {
@ -232,12 +233,12 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
} }
} }
while (threadContext->state < THREAD_SHUTDOWN) { while (impl->state < THREAD_SHUTDOWN) {
_changeState(threadContext, THREAD_SHUTDOWN, false); _changeState(impl, THREAD_SHUTDOWN, false);
} }
if (core->opts.rewindEnable) { if (core->opts.rewindEnable) {
mCoreRewindContextDeinit(&threadContext->rewind); mCoreRewindContextDeinit(&impl->rewind);
} }
if (threadContext->cleanCallback) { if (threadContext->cleanCallback) {
@ -251,27 +252,28 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
} }
bool mCoreThreadStart(struct mCoreThread* threadContext) { bool mCoreThreadStart(struct mCoreThread* threadContext) {
threadContext->state = THREAD_INITIALIZED; threadContext->impl = malloc(sizeof(*threadContext->impl));
threadContext->impl->state = THREAD_INITIALIZED;
threadContext->logger.p = threadContext; threadContext->logger.p = threadContext;
if (!threadContext->logger.d.log) { if (!threadContext->logger.d.log) {
threadContext->logger.d.log = _mCoreLog; threadContext->logger.d.log = _mCoreLog;
threadContext->logger.d.filter = NULL; threadContext->logger.d.filter = NULL;
} }
if (!threadContext->sync.fpsTarget) { if (!threadContext->impl->sync.fpsTarget) {
threadContext->sync.fpsTarget = _defaultFPSTarget; threadContext->impl->sync.fpsTarget = _defaultFPSTarget;
} }
MutexInit(&threadContext->stateMutex); MutexInit(&threadContext->impl->stateMutex);
ConditionInit(&threadContext->stateCond); ConditionInit(&threadContext->impl->stateCond);
MutexInit(&threadContext->sync.videoFrameMutex); MutexInit(&threadContext->impl->sync.videoFrameMutex);
ConditionInit(&threadContext->sync.videoFrameAvailableCond); ConditionInit(&threadContext->impl->sync.videoFrameAvailableCond);
ConditionInit(&threadContext->sync.videoFrameRequiredCond); ConditionInit(&threadContext->impl->sync.videoFrameRequiredCond);
MutexInit(&threadContext->sync.audioBufferMutex); MutexInit(&threadContext->impl->sync.audioBufferMutex);
ConditionInit(&threadContext->sync.audioRequiredCond); ConditionInit(&threadContext->impl->sync.audioRequiredCond);
threadContext->interruptDepth = 0; threadContext->impl->interruptDepth = 0;
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
sigset_t signals; sigset_t signals;
@ -281,271 +283,289 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
pthread_sigmask(SIG_BLOCK, &signals, 0); pthread_sigmask(SIG_BLOCK, &signals, 0);
#endif #endif
threadContext->sync.audioWait = threadContext->core->opts.audioSync; threadContext->impl->sync.audioWait = threadContext->core->opts.audioSync;
threadContext->sync.videoFrameWait = threadContext->core->opts.videoSync; threadContext->impl->sync.videoFrameWait = threadContext->core->opts.videoSync;
threadContext->sync.fpsTarget = threadContext->core->opts.fpsTarget; threadContext->impl->sync.fpsTarget = threadContext->core->opts.fpsTarget;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
ThreadCreate(&threadContext->thread, _mCoreThreadRun, threadContext); ThreadCreate(&threadContext->impl->thread, _mCoreThreadRun, threadContext);
while (threadContext->state < THREAD_RUNNING) { while (threadContext->impl->state < THREAD_RUNNING) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); ConditionWait(&threadContext->impl->stateCond, &threadContext->impl->stateMutex);
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return true; return true;
} }
bool mCoreThreadHasStarted(struct mCoreThread* threadContext) { bool mCoreThreadHasStarted(struct mCoreThread* threadContext) {
if (!threadContext->impl) {
return false;
}
bool hasStarted; bool hasStarted;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
hasStarted = threadContext->state > THREAD_INITIALIZED; hasStarted = threadContext->impl->state > THREAD_INITIALIZED;
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return hasStarted; return hasStarted;
} }
bool mCoreThreadHasExited(struct mCoreThread* threadContext) { bool mCoreThreadHasExited(struct mCoreThread* threadContext) {
if (!threadContext->impl) {
return false;
}
bool hasExited; bool hasExited;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
hasExited = threadContext->state > THREAD_EXITING; hasExited = threadContext->impl->state > THREAD_EXITING;
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return hasExited; return hasExited;
} }
bool mCoreThreadHasCrashed(struct mCoreThread* threadContext) { bool mCoreThreadHasCrashed(struct mCoreThread* threadContext) {
if (!threadContext->impl) {
return false;
}
bool hasExited; bool hasExited;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
hasExited = threadContext->state == THREAD_CRASHED; hasExited = threadContext->impl->state == THREAD_CRASHED;
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return hasExited; return hasExited;
} }
void mCoreThreadMarkCrashed(struct mCoreThread* threadContext) { void mCoreThreadMarkCrashed(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
threadContext->state = THREAD_CRASHED; threadContext->impl->state = THREAD_CRASHED;
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadEnd(struct mCoreThread* threadContext) { void mCoreThreadEnd(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
threadContext->state = THREAD_EXITING; threadContext->impl->state = THREAD_EXITING;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
MutexLock(&threadContext->sync.audioBufferMutex); MutexLock(&threadContext->impl->sync.audioBufferMutex);
threadContext->sync.audioWait = 0; threadContext->impl->sync.audioWait = 0;
ConditionWake(&threadContext->sync.audioRequiredCond); ConditionWake(&threadContext->impl->sync.audioRequiredCond);
MutexUnlock(&threadContext->sync.audioBufferMutex); MutexUnlock(&threadContext->impl->sync.audioBufferMutex);
MutexLock(&threadContext->sync.videoFrameMutex); MutexLock(&threadContext->impl->sync.videoFrameMutex);
threadContext->sync.videoFrameWait = false; threadContext->impl->sync.videoFrameWait = false;
threadContext->sync.videoFrameOn = false; threadContext->impl->sync.videoFrameOn = false;
ConditionWake(&threadContext->sync.videoFrameRequiredCond); ConditionWake(&threadContext->impl->sync.videoFrameRequiredCond);
ConditionWake(&threadContext->sync.videoFrameAvailableCond); ConditionWake(&threadContext->impl->sync.videoFrameAvailableCond);
MutexUnlock(&threadContext->sync.videoFrameMutex); MutexUnlock(&threadContext->impl->sync.videoFrameMutex);
} }
void mCoreThreadReset(struct mCoreThread* threadContext) { void mCoreThreadReset(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
if (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) { if (threadContext->impl->state == THREAD_INTERRUPTED || threadContext->impl->state == THREAD_INTERRUPTING) {
threadContext->savedState = THREAD_RESETING; threadContext->impl->savedState = THREAD_RESETING;
} else { } else {
threadContext->state = THREAD_RESETING; threadContext->impl->state = THREAD_RESETING;
} }
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadJoin(struct mCoreThread* threadContext) { void mCoreThreadJoin(struct mCoreThread* threadContext) {
ThreadJoin(threadContext->thread); if (!threadContext->impl) {
return;
}
ThreadJoin(threadContext->impl->thread);
MutexDeinit(&threadContext->stateMutex); MutexDeinit(&threadContext->impl->stateMutex);
ConditionDeinit(&threadContext->stateCond); ConditionDeinit(&threadContext->impl->stateCond);
MutexDeinit(&threadContext->sync.videoFrameMutex); MutexDeinit(&threadContext->impl->sync.videoFrameMutex);
ConditionWake(&threadContext->sync.videoFrameAvailableCond); ConditionWake(&threadContext->impl->sync.videoFrameAvailableCond);
ConditionDeinit(&threadContext->sync.videoFrameAvailableCond); ConditionDeinit(&threadContext->impl->sync.videoFrameAvailableCond);
ConditionWake(&threadContext->sync.videoFrameRequiredCond); ConditionWake(&threadContext->impl->sync.videoFrameRequiredCond);
ConditionDeinit(&threadContext->sync.videoFrameRequiredCond); ConditionDeinit(&threadContext->impl->sync.videoFrameRequiredCond);
ConditionWake(&threadContext->sync.audioRequiredCond); ConditionWake(&threadContext->impl->sync.audioRequiredCond);
ConditionDeinit(&threadContext->sync.audioRequiredCond); ConditionDeinit(&threadContext->impl->sync.audioRequiredCond);
MutexDeinit(&threadContext->sync.audioBufferMutex); MutexDeinit(&threadContext->impl->sync.audioBufferMutex);
free(threadContext->impl);
threadContext->impl = NULL;
} }
bool mCoreThreadIsActive(struct mCoreThread* threadContext) { bool mCoreThreadIsActive(struct mCoreThread* threadContext) {
return threadContext->state >= THREAD_RUNNING && threadContext->state < THREAD_EXITING; if (!threadContext->impl) {
return false;
}
return threadContext->impl->state >= THREAD_RUNNING && threadContext->impl->state < THREAD_EXITING;
} }
void mCoreThreadInterrupt(struct mCoreThread* threadContext) { void mCoreThreadInterrupt(struct mCoreThread* threadContext) {
if (!threadContext) { if (!threadContext) {
return; return;
} }
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
++threadContext->interruptDepth; ++threadContext->impl->interruptDepth;
if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { if (threadContext->impl->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) {
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return; return;
} }
threadContext->savedState = threadContext->state; threadContext->impl->savedState = threadContext->impl->state;
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
threadContext->state = THREAD_INTERRUPTING; threadContext->impl->state = THREAD_INTERRUPTING;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
_waitUntilNotState(threadContext, THREAD_INTERRUPTING); _waitUntilNotState(threadContext->impl, THREAD_INTERRUPTING);
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext) { void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext) {
if (!threadContext) { if (!threadContext) {
return; return;
} }
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
++threadContext->interruptDepth; ++threadContext->impl->interruptDepth;
if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { if (threadContext->impl->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) {
if (threadContext->state == THREAD_INTERRUPTING) { if (threadContext->impl->state == THREAD_INTERRUPTING) {
threadContext->state = THREAD_INTERRUPTED; threadContext->impl->state = THREAD_INTERRUPTED;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return; return;
} }
threadContext->savedState = threadContext->state; threadContext->impl->savedState = threadContext->impl->state;
threadContext->state = THREAD_INTERRUPTED; threadContext->impl->state = THREAD_INTERRUPTING;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadContinue(struct mCoreThread* threadContext) { void mCoreThreadContinue(struct mCoreThread* threadContext) {
if (!threadContext) { if (!threadContext) {
return; return;
} }
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
--threadContext->interruptDepth; --threadContext->impl->interruptDepth;
if (threadContext->interruptDepth < 1 && mCoreThreadIsActive(threadContext)) { if (threadContext->impl->interruptDepth < 1 && mCoreThreadIsActive(threadContext)) {
threadContext->state = threadContext->savedState; threadContext->impl->state = threadContext->impl->savedState;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)) { void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
threadContext->run = run; threadContext->run = run;
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
threadContext->savedState = threadContext->state; threadContext->impl->savedState = threadContext->impl->state;
threadContext->state = THREAD_RUN_ON; threadContext->impl->state = THREAD_RUN_ON;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
_waitUntilNotState(threadContext, THREAD_RUN_ON); _waitUntilNotState(threadContext->impl, THREAD_RUN_ON);
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadPause(struct mCoreThread* threadContext) { void mCoreThreadPause(struct mCoreThread* threadContext) {
bool frameOn = threadContext->sync.videoFrameOn; bool frameOn = threadContext->impl->sync.videoFrameOn;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
if (threadContext->state == THREAD_RUNNING) { if (threadContext->impl->state == THREAD_RUNNING) {
_pauseThread(threadContext); _pauseThread(threadContext->impl);
threadContext->frameWasOn = frameOn; threadContext->impl->frameWasOn = frameOn;
frameOn = false; frameOn = false;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn); mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn);
} }
void mCoreThreadUnpause(struct mCoreThread* threadContext) { void mCoreThreadUnpause(struct mCoreThread* threadContext) {
bool frameOn = threadContext->sync.videoFrameOn; bool frameOn = threadContext->impl->sync.videoFrameOn;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { if (threadContext->impl->state == THREAD_PAUSED || threadContext->impl->state == THREAD_PAUSING) {
threadContext->state = THREAD_RUNNING; threadContext->impl->state = THREAD_RUNNING;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
frameOn = threadContext->frameWasOn; frameOn = threadContext->impl->frameWasOn;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn); mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn);
} }
bool mCoreThreadIsPaused(struct mCoreThread* threadContext) { bool mCoreThreadIsPaused(struct mCoreThread* threadContext) {
bool isPaused; bool isPaused;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
if (threadContext->interruptDepth) { if (threadContext->impl->interruptDepth) {
isPaused = threadContext->savedState == THREAD_PAUSED; isPaused = threadContext->impl->savedState == THREAD_PAUSED;
} else { } else {
isPaused = threadContext->state == THREAD_PAUSED; isPaused = threadContext->impl->state == THREAD_PAUSED;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return isPaused; return isPaused;
} }
void mCoreThreadTogglePause(struct mCoreThread* threadContext) { void mCoreThreadTogglePause(struct mCoreThread* threadContext) {
bool frameOn = threadContext->sync.videoFrameOn; bool frameOn = threadContext->impl->sync.videoFrameOn;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { if (threadContext->impl->state == THREAD_PAUSED || threadContext->impl->state == THREAD_PAUSING) {
threadContext->state = THREAD_RUNNING; threadContext->impl->state = THREAD_RUNNING;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
frameOn = threadContext->frameWasOn; frameOn = threadContext->impl->frameWasOn;
} else if (threadContext->state == THREAD_RUNNING) { } else if (threadContext->impl->state == THREAD_RUNNING) {
_pauseThread(threadContext); _pauseThread(threadContext->impl);
threadContext->frameWasOn = frameOn; threadContext->impl->frameWasOn = frameOn;
frameOn = false; frameOn = false;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn); mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn);
} }
void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) { void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) {
bool frameOn = true; bool frameOn = true;
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
if (threadContext->state == THREAD_RUNNING || (threadContext->interruptDepth && threadContext->savedState == THREAD_RUNNING)) { if (threadContext->impl->state == THREAD_RUNNING || (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_RUNNING)) {
threadContext->state = THREAD_PAUSING; threadContext->impl->state = THREAD_PAUSING;
frameOn = false; frameOn = false;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn); mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn);
} }
void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding) { void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
if (rewinding && (threadContext->state == THREAD_REWINDING || (threadContext->interruptDepth && threadContext->savedState == THREAD_REWINDING))) { if (rewinding && (threadContext->impl->state == THREAD_REWINDING || (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_REWINDING))) {
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return; return;
} }
if (!rewinding && ((!threadContext->interruptDepth && threadContext->state != THREAD_REWINDING) || (threadContext->interruptDepth && threadContext->savedState != THREAD_REWINDING))) { if (!rewinding && ((!threadContext->impl->interruptDepth && threadContext->impl->state != THREAD_REWINDING) || (threadContext->impl->interruptDepth && threadContext->impl->savedState != THREAD_REWINDING))) {
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
return; return;
} }
_waitOnInterrupt(threadContext); _waitOnInterrupt(threadContext->impl);
if (rewinding && threadContext->state == THREAD_RUNNING) { if (rewinding && threadContext->impl->state == THREAD_RUNNING) {
threadContext->state = THREAD_REWINDING; threadContext->impl->state = THREAD_REWINDING;
} }
if (!rewinding && threadContext->state == THREAD_REWINDING) { if (!rewinding && threadContext->impl->state == THREAD_REWINDING) {
threadContext->state = THREAD_RUNNING; threadContext->impl->state = THREAD_RUNNING;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadWaitFromThread(struct mCoreThread* threadContext) { void mCoreThreadWaitFromThread(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
if (threadContext->interruptDepth && threadContext->savedState == THREAD_RUNNING) { if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_RUNNING) {
threadContext->savedState = THREAD_WAITING; threadContext->impl->savedState = THREAD_WAITING;
} else if (threadContext->state == THREAD_RUNNING) { } else if (threadContext->impl->state == THREAD_RUNNING) {
threadContext->state = THREAD_WAITING; threadContext->impl->state = THREAD_WAITING;
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
void mCoreThreadStopWaiting(struct mCoreThread* threadContext) { void mCoreThreadStopWaiting(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->impl->stateMutex);
if (threadContext->interruptDepth && threadContext->savedState == THREAD_WAITING) { if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_WAITING) {
threadContext->savedState = THREAD_RUNNING; threadContext->impl->savedState = THREAD_RUNNING;
} else if (threadContext->state == THREAD_WAITING) { } else if (threadContext->impl->state == THREAD_WAITING) {
threadContext->state = THREAD_RUNNING; threadContext->impl->state = THREAD_RUNNING;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->impl->stateCond);
} }
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->impl->stateMutex);
} }
#ifdef USE_PTHREADS #ifdef USE_PTHREADS

View File

@ -26,13 +26,13 @@ void AudioDevice::setFormat(const QAudioFormat& format) {
LOG(QT, INFO) << tr("Can't set format of context-less audio device"); LOG(QT, INFO) << tr("Can't set format of context-less audio device");
return; return;
} }
double fauxClock = GBAAudioCalculateRatio(1, m_context->sync.fpsTarget, 1); double fauxClock = GBAAudioCalculateRatio(1, m_context->impl->sync.fpsTarget, 1);
mCoreSyncLockAudio(&m_context->sync); mCoreSyncLockAudio(&m_context->impl->sync);
blip_set_rates(m_context->core->getAudioChannel(m_context->core, 0), blip_set_rates(m_context->core->getAudioChannel(m_context->core, 0),
m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock); m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock);
blip_set_rates(m_context->core->getAudioChannel(m_context->core, 1), blip_set_rates(m_context->core->getAudioChannel(m_context->core, 1),
m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock); m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock);
mCoreSyncUnlockAudio(&m_context->sync); mCoreSyncUnlockAudio(&m_context->impl->sync);
} }
void AudioDevice::setInput(mCoreThread* input) { void AudioDevice::setInput(mCoreThread* input) {
@ -49,14 +49,14 @@ qint64 AudioDevice::readData(char* data, qint64 maxSize) {
return 0; return 0;
} }
mCoreSyncLockAudio(&m_context->sync); mCoreSyncLockAudio(&m_context->impl->sync);
int available = blip_samples_avail(m_context->core->getAudioChannel(m_context->core, 0)); int available = blip_samples_avail(m_context->core->getAudioChannel(m_context->core, 0));
if (available > maxSize / sizeof(GBAStereoSample)) { if (available > maxSize / sizeof(GBAStereoSample)) {
available = maxSize / sizeof(GBAStereoSample); available = maxSize / sizeof(GBAStereoSample);
} }
blip_read_samples(m_context->core->getAudioChannel(m_context->core, 0), &reinterpret_cast<GBAStereoSample*>(data)->left, available, true); blip_read_samples(m_context->core->getAudioChannel(m_context->core, 0), &reinterpret_cast<GBAStereoSample*>(data)->left, available, true);
blip_read_samples(m_context->core->getAudioChannel(m_context->core, 1), &reinterpret_cast<GBAStereoSample*>(data)->right, available, true); blip_read_samples(m_context->core->getAudioChannel(m_context->core, 1), &reinterpret_cast<GBAStereoSample*>(data)->right, available, true);
mCoreSyncConsumeAudio(&m_context->sync); mCoreSyncConsumeAudio(&m_context->impl->sync);
return available * sizeof(GBAStereoSample); return available * sizeof(GBAStereoSample);
} }

View File

@ -69,7 +69,7 @@ void DisplayGL::startDrawing(mCoreThread* thread) {
m_painter->moveToThread(m_drawThread); m_painter->moveToThread(m_drawThread);
connect(m_drawThread, &QThread::started, m_painter, &PainterGL::start); connect(m_drawThread, &QThread::started, m_painter, &PainterGL::start);
m_drawThread->start(); m_drawThread->start();
mCoreSyncSetVideoSync(&m_context->sync, false); mCoreSyncSetVideoSync(&m_context->impl->sync, false);
lockAspectRatio(isAspectRatioLocked()); lockAspectRatio(isAspectRatioLocked());
lockIntegerScaling(isIntegerScalingLocked()); lockIntegerScaling(isIntegerScalingLocked());
@ -333,9 +333,9 @@ void PainterGL::draw() {
return; return;
} }
if (mCoreSyncWaitFrameStart(&m_context->sync) || !m_queue.isEmpty()) { if (mCoreSyncWaitFrameStart(&m_context->impl->sync) || !m_queue.isEmpty()) {
dequeue(); dequeue();
mCoreSyncWaitFrameEnd(&m_context->sync); mCoreSyncWaitFrameEnd(&m_context->impl->sync);
m_painter.begin(m_gl->context()->device()); m_painter.begin(m_gl->context()->device());
performDraw(); performDraw();
m_painter.end(); m_painter.end();
@ -349,7 +349,7 @@ void PainterGL::draw() {
m_delayTimer.restart(); m_delayTimer.restart();
} }
} else { } else {
mCoreSyncWaitFrameEnd(&m_context->sync); mCoreSyncWaitFrameEnd(&m_context->impl->sync);
} }
if (!m_queue.isEmpty()) { if (!m_queue.isEmpty()) {
QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection);

View File

@ -79,7 +79,7 @@ GameController::GameController(QObject* parent)
default: default:
break; break;
} }
controller->m_fpsTarget = context->sync.fpsTarget; controller->m_fpsTarget = context->impl->sync.fpsTarget;
if (controller->m_override) { if (controller->m_override) {
controller->m_override->identify(context->core); controller->m_override->identify(context->core);
@ -299,8 +299,8 @@ void GameController::setConfig(const mCoreConfig* config) {
if (isLoaded()) { if (isLoaded()) {
Interrupter interrupter(this); Interrupter interrupter(this);
mCoreLoadForeignConfig(m_threadContext.core, config); mCoreLoadForeignConfig(m_threadContext.core, config);
m_audioSync = m_threadContext.sync.audioWait; m_audioSync = m_threadContext.impl->sync.audioWait;
m_videoSync = m_threadContext.sync.videoFrameWait; m_videoSync = m_threadContext.impl->sync.videoFrameWait;
m_audioProcessor->setInput(&m_threadContext); m_audioProcessor->setInput(&m_threadContext);
} }
} }
@ -410,13 +410,6 @@ void GameController::openGame(bool biosOnly) {
m_pauseAfterFrame = false; m_pauseAfterFrame = false;
if (m_turbo) {
m_threadContext.sync.videoFrameWait = false;
m_threadContext.sync.audioWait = false;
} else {
m_threadContext.sync.videoFrameWait = m_videoSync;
m_threadContext.sync.audioWait = m_audioSync;
}
m_threadContext.core->init(m_threadContext.core); m_threadContext.core->init(m_threadContext.core);
mCoreInitConfig(m_threadContext.core, nullptr); mCoreInitConfig(m_threadContext.core, nullptr);
@ -483,6 +476,13 @@ void GameController::openGame(bool biosOnly) {
if (!mCoreThreadStart(&m_threadContext)) { if (!mCoreThreadStart(&m_threadContext)) {
emit gameFailed(); emit gameFailed();
} }
if (m_turbo) {
m_threadContext.impl->sync.videoFrameWait = false;
m_threadContext.impl->sync.audioWait = false;
} else {
m_threadContext.impl->sync.videoFrameWait = m_videoSync;
m_threadContext.impl->sync.audioWait = m_audioSync;
}
} }
void GameController::loadBIOS(int platform, const QString& path) { void GameController::loadBIOS(int platform, const QString& path) {
@ -704,14 +704,14 @@ void GameController::setRewind(bool enable, int capacity, bool rewindSave) {
if (m_gameOpen) { if (m_gameOpen) {
Interrupter interrupter(this); Interrupter interrupter(this);
if (m_threadContext.core->opts.rewindEnable && m_threadContext.core->opts.rewindBufferCapacity > 0) { if (m_threadContext.core->opts.rewindEnable && m_threadContext.core->opts.rewindBufferCapacity > 0) {
mCoreRewindContextDeinit(&m_threadContext.rewind); mCoreRewindContextDeinit(&m_threadContext.impl->rewind);
} }
m_threadContext.core->opts.rewindEnable = enable; m_threadContext.core->opts.rewindEnable = enable;
m_threadContext.core->opts.rewindBufferCapacity = capacity; m_threadContext.core->opts.rewindBufferCapacity = capacity;
m_threadContext.core->opts.rewindSave = rewindSave; m_threadContext.core->opts.rewindSave = rewindSave;
if (enable && capacity > 0) { if (enable && capacity > 0) {
mCoreRewindContextInit(&m_threadContext.rewind, capacity, true); mCoreRewindContextInit(&m_threadContext.impl->rewind, capacity, true);
m_threadContext.rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0; m_threadContext.impl->rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0;
} }
} }
} }
@ -722,7 +722,7 @@ void GameController::rewind(int states) {
states = INT_MAX; states = INT_MAX;
} }
for (int i = 0; i < states; ++i) { for (int i = 0; i < states; ++i) {
if (!mCoreRewindRestore(&m_threadContext.rewind, m_threadContext.core)) { if (!mCoreRewindRestore(&m_threadContext.impl->rewind, m_threadContext.core)) {
break; break;
} }
} }
@ -850,8 +850,10 @@ void GameController::startAudio() {
// Don't freeze! // Don't freeze!
m_audioSync = false; m_audioSync = false;
m_videoSync = true; m_videoSync = true;
m_threadContext.sync.audioWait = false; if (isLoaded()) {
m_threadContext.sync.videoFrameWait = true; m_threadContext.impl->sync.audioWait = false;
m_threadContext.impl->sync.videoFrameWait = true;
}
} }
} }
@ -872,9 +874,11 @@ void GameController::setVideoLayerEnabled(int layer, bool enable) {
void GameController::setFPSTarget(float fps) { void GameController::setFPSTarget(float fps) {
Interrupter interrupter(this); Interrupter interrupter(this);
m_fpsTarget = fps; m_fpsTarget = fps;
m_threadContext.sync.fpsTarget = fps; if (isLoaded()) {
if (m_turbo && m_turboSpeed > 0) { m_threadContext.impl->sync.fpsTarget = fps;
m_threadContext.sync.fpsTarget *= m_turboSpeed; if (m_turbo && m_turboSpeed > 0) {
m_threadContext.impl->sync.fpsTarget *= m_turboSpeed;
}
} }
if (m_audioProcessor) { if (m_audioProcessor) {
redoSamples(m_audioProcessor->getBufferSamples()); redoSamples(m_audioProcessor->getBufferSamples());
@ -992,22 +996,25 @@ void GameController::setTurboSpeed(float ratio) {
void GameController::enableTurbo() { void GameController::enableTurbo() {
Interrupter interrupter(this); Interrupter interrupter(this);
if (!isLoaded()) {
return;
}
bool shouldRedoSamples = false; bool shouldRedoSamples = false;
if (!m_turbo) { if (!m_turbo) {
shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget; shouldRedoSamples = m_threadContext.impl->sync.fpsTarget != m_fpsTarget;
m_threadContext.sync.fpsTarget = m_fpsTarget; m_threadContext.impl->sync.fpsTarget = m_fpsTarget;
m_threadContext.sync.audioWait = m_audioSync; m_threadContext.impl->sync.audioWait = m_audioSync;
m_threadContext.sync.videoFrameWait = m_videoSync; m_threadContext.impl->sync.videoFrameWait = m_videoSync;
} else if (m_turboSpeed <= 0) { } else if (m_turboSpeed <= 0) {
shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget; shouldRedoSamples = m_threadContext.impl->sync.fpsTarget != m_fpsTarget;
m_threadContext.sync.fpsTarget = m_fpsTarget; m_threadContext.impl->sync.fpsTarget = m_fpsTarget;
m_threadContext.sync.audioWait = false; m_threadContext.impl->sync.audioWait = false;
m_threadContext.sync.videoFrameWait = false; m_threadContext.impl->sync.videoFrameWait = false;
} else { } else {
shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget * m_turboSpeed; shouldRedoSamples = m_threadContext.impl->sync.fpsTarget != m_fpsTarget * m_turboSpeed;
m_threadContext.sync.fpsTarget = m_fpsTarget * m_turboSpeed; m_threadContext.impl->sync.fpsTarget = m_fpsTarget * m_turboSpeed;
m_threadContext.sync.audioWait = true; m_threadContext.impl->sync.audioWait = true;
m_threadContext.sync.videoFrameWait = false; m_threadContext.impl->sync.videoFrameWait = false;
} }
if (m_audioProcessor && shouldRedoSamples) { if (m_audioProcessor && shouldRedoSamples) {
redoSamples(m_audioProcessor->getBufferSamples()); redoSamples(m_audioProcessor->getBufferSamples());
@ -1017,24 +1024,30 @@ void GameController::enableTurbo() {
void GameController::setSync(bool enable) { void GameController::setSync(bool enable) {
m_turbo = false; m_turbo = false;
m_turboForced = false; m_turboForced = false;
if (!enable) { if (isLoaded()) {
m_threadContext.sync.audioWait = false; if (!enable) {
m_threadContext.sync.videoFrameWait = false; m_threadContext.impl->sync.audioWait = false;
} else { m_threadContext.impl->sync.videoFrameWait = false;
m_threadContext.sync.audioWait = m_audioSync; } else {
m_threadContext.sync.videoFrameWait = m_videoSync; m_threadContext.impl->sync.audioWait = m_audioSync;
m_threadContext.impl->sync.videoFrameWait = m_videoSync;
}
} }
m_sync = enable; m_sync = enable;
} }
void GameController::setAudioSync(bool enable) { void GameController::setAudioSync(bool enable) {
m_audioSync = enable; m_audioSync = enable;
m_threadContext.sync.audioWait = enable; if (isLoaded()) {
m_threadContext.impl->sync.audioWait = enable;
}
} }
void GameController::setVideoSync(bool enable) { void GameController::setVideoSync(bool enable) {
m_videoSync = enable; m_videoSync = enable;
m_threadContext.sync.videoFrameWait = enable; if (isLoaded()) {
m_threadContext.impl->sync.videoFrameWait = enable;
}
} }
void GameController::setAVStream(mAVStream* stream) { void GameController::setAVStream(mAVStream* stream) {

View File

@ -718,14 +718,10 @@ void Window::toggleFullScreen() {
} }
void Window::gameStarted(mCoreThread* context, const QString& fname) { void Window::gameStarted(mCoreThread* context, const QString& fname) {
MutexLock(&context->stateMutex); if (!mCoreThreadIsActive(context)) {
if (context->state < THREAD_EXITING) {
emit startDrawing(context);
} else {
MutexUnlock(&context->stateMutex);
return; return;
} }
MutexUnlock(&context->stateMutex); emit startDrawing(context);
for (QAction* action : m_gameActions) { for (QAction* action : m_gameActions) {
action->setDisabled(false); action->setDisabled(false);
} }

View File

@ -53,7 +53,7 @@ void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
SDL_Event event; SDL_Event event;
struct VideoBackend* v = &renderer->gl.d; struct VideoBackend* v = &renderer->gl.d;
while (context->state < THREAD_EXITING) { while (mCoreThreadIsActive(context)) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
mSDLHandleEvent(context, &renderer->player, &event); mSDLHandleEvent(context, &renderer->player, &event);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
@ -66,10 +66,10 @@ void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
#endif #endif
} }
if (mCoreSyncWaitFrameStart(&context->sync)) { if (mCoreSyncWaitFrameStart(&context->impl->sync)) {
v->postFrame(v, renderer->outputBuffer); v->postFrame(v, renderer->outputBuffer);
} }
mCoreSyncWaitFrameEnd(&context->sync); mCoreSyncWaitFrameEnd(&context->impl->sync);
v->drawFrame(v); v->drawFrame(v);
v->swap(v); v->swap(v);
} }

View File

@ -44,7 +44,7 @@ bool mSDLInitAudio(struct mSDLAudio* context, struct mCoreThread* threadContext)
if (threadContext) { if (threadContext) {
context->core = threadContext->core; context->core = threadContext->core;
context->sync = &threadContext->sync; context->sync = &threadContext->impl->sync;
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_PauseAudioDevice(context->deviceId, 0); SDL_PauseAudioDevice(context->deviceId, 0);

View File

@ -419,7 +419,7 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer*
return; return;
} }
if (event->keysym.sym == SDLK_TAB) { if (event->keysym.sym == SDLK_TAB) {
context->sync.audioWait = event->type != SDL_KEYDOWN; context->impl->sync.audioWait = event->type != SDL_KEYDOWN;
return; return;
} }
if (event->keysym.sym == SDLK_BACKQUOTE) { if (event->keysym.sym == SDLK_BACKQUOTE) {