GBA Thread: Split GBASync into a separate file

This commit is contained in:
Jeffrey Pfau 2015-06-10 01:06:09 -07:00
parent 79e06612cb
commit 40ae214a7d
8 changed files with 174 additions and 155 deletions

View File

@ -63,6 +63,7 @@ Misc:
- Qt: Replace pause-after-frame mutex with an atomic
- Util: Allow disabling the threading code entirely
- GBA: SIO logging layer
- GBA Thread: Split GBASync into a separate file
0.2.1: (2015-05-13)
Bugfixes:

126
src/gba/supervisor/sync.c Normal file
View File

@ -0,0 +1,126 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "thread.h"
static void _changeVideoSync(struct GBASync* sync, bool frameOn) {
// Make sure the video thread can process events while the GBA thread is paused
MutexLock(&sync->videoFrameMutex);
if (frameOn != sync->videoFrameOn) {
sync->videoFrameOn = frameOn;
ConditionWake(&sync->videoFrameAvailableCond);
}
MutexUnlock(&sync->videoFrameMutex);
}
void GBASyncPostFrame(struct GBASync* sync) {
if (!sync) {
return;
}
MutexLock(&sync->videoFrameMutex);
++sync->videoFramePending;
--sync->videoFrameSkip;
if (sync->videoFrameSkip < 0) {
do {
ConditionWake(&sync->videoFrameAvailableCond);
if (sync->videoFrameWait) {
ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
}
} while (sync->videoFrameWait && sync->videoFramePending);
}
MutexUnlock(&sync->videoFrameMutex);
}
void GBASyncForceFrame(struct GBASync* sync) {
if (!sync) {
return;
}
MutexLock(&sync->videoFrameMutex);
ConditionWake(&sync->videoFrameAvailableCond);
MutexUnlock(&sync->videoFrameMutex);
}
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) {
if (!sync) {
return true;
}
MutexLock(&sync->videoFrameMutex);
ConditionWake(&sync->videoFrameRequiredCond);
if (!sync->videoFrameOn && !sync->videoFramePending) {
return false;
}
if (sync->videoFrameOn) {
if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) {
return false;
}
}
sync->videoFramePending = 0;
sync->videoFrameSkip = frameskip;
return true;
}
void GBASyncWaitFrameEnd(struct GBASync* sync) {
if (!sync) {
return;
}
MutexUnlock(&sync->videoFrameMutex);
}
bool GBASyncDrawingFrame(struct GBASync* sync) {
if (!sync) {
return true;
}
return sync->videoFrameSkip <= 0;
}
void GBASyncSetVideoSync(struct GBASync* sync, bool wait) {
if (!sync) {
return;
}
_changeVideoSync(sync, wait);
}
void GBASyncProduceAudio(struct GBASync* sync, bool wait) {
if (!sync) {
return;
}
if (sync->audioWait && wait) {
// TODO loop properly in event of spurious wakeups
ConditionWait(&sync->audioRequiredCond, &sync->audioBufferMutex);
}
MutexUnlock(&sync->audioBufferMutex);
}
void GBASyncLockAudio(struct GBASync* sync) {
if (!sync) {
return;
}
MutexLock(&sync->audioBufferMutex);
}
void GBASyncUnlockAudio(struct GBASync* sync) {
if (!sync) {
return;
}
MutexUnlock(&sync->audioBufferMutex);
}
void GBASyncConsumeAudio(struct GBASync* sync) {
if (!sync) {
return;
}
ConditionWake(&sync->audioRequiredCond);
MutexUnlock(&sync->audioBufferMutex);
}

39
src/gba/supervisor/sync.h Normal file
View File

@ -0,0 +1,39 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GBA_SYNC_H
#define GBA_SYNC_H
#include "util/common.h"
#include "util/threading.h"
struct GBASync {
int videoFramePending;
bool videoFrameWait;
int videoFrameSkip;
bool videoFrameOn;
Mutex videoFrameMutex;
Condition videoFrameAvailableCond;
Condition videoFrameRequiredCond;
bool audioWait;
Condition audioRequiredCond;
Mutex audioBufferMutex;
};
void GBASyncPostFrame(struct GBASync* sync);
void GBASyncForceFrame(struct GBASync* sync);
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip);
void GBASyncWaitFrameEnd(struct GBASync* sync);
bool GBASyncDrawingFrame(struct GBASync* sync);
void GBASyncSetVideoSync(struct GBASync* sync, bool wait);
void GBASyncProduceAudio(struct GBASync* sync, bool wait);
void GBASyncLockAudio(struct GBASync* sync);
void GBASyncUnlockAudio(struct GBASync* sync);
void GBASyncConsumeAudio(struct GBASync* sync);
#endif

View File

@ -93,19 +93,7 @@ static void _pauseThread(struct GBAThread* threadContext, bool onThread) {
_waitUntilNotState(threadContext, THREAD_PAUSING);
}
}
#endif
static void _changeVideoSync(struct GBASync* sync, bool frameOn) {
// Make sure the video thread can process events while the GBA thread is paused
MutexLock(&sync->videoFrameMutex);
if (frameOn != sync->videoFrameOn) {
sync->videoFrameOn = frameOn;
ConditionWake(&sync->videoFrameAvailableCond);
}
MutexUnlock(&sync->videoFrameMutex);
}
#ifndef DISABLE_THREADING
static THREAD_ENTRY _GBAThreadRun(void* context) {
#ifdef USE_PTHREADS
pthread_once(&_contextOnce, _createTLS);
@ -631,7 +619,7 @@ void GBAThreadPause(struct GBAThread* threadContext) {
}
MutexUnlock(&threadContext->stateMutex);
_changeVideoSync(&threadContext->sync, frameOn);
GBASyncSetVideoSync(&threadContext->sync, frameOn);
}
void GBAThreadUnpause(struct GBAThread* threadContext) {
@ -645,7 +633,7 @@ void GBAThreadUnpause(struct GBAThread* threadContext) {
}
MutexUnlock(&threadContext->stateMutex);
_changeVideoSync(&threadContext->sync, frameOn);
GBASyncSetVideoSync(&threadContext->sync, frameOn);
}
bool GBAThreadIsPaused(struct GBAThread* threadContext) {
@ -672,7 +660,7 @@ void GBAThreadTogglePause(struct GBAThread* threadContext) {
}
MutexUnlock(&threadContext->stateMutex);
_changeVideoSync(&threadContext->sync, frameOn);
GBASyncSetVideoSync(&threadContext->sync, frameOn);
}
void GBAThreadPauseFromThread(struct GBAThread* threadContext) {
@ -685,7 +673,7 @@ void GBAThreadPauseFromThread(struct GBAThread* threadContext) {
}
MutexUnlock(&threadContext->stateMutex);
_changeVideoSync(&threadContext->sync, frameOn);
GBASyncSetVideoSync(&threadContext->sync, frameOn);
}
#ifdef USE_PTHREADS
@ -722,113 +710,3 @@ struct GBAThread* GBAThreadGetContext(void) {
return 0;
}
#endif
void GBASyncPostFrame(struct GBASync* sync) {
if (!sync) {
return;
}
MutexLock(&sync->videoFrameMutex);
++sync->videoFramePending;
--sync->videoFrameSkip;
if (sync->videoFrameSkip < 0) {
do {
ConditionWake(&sync->videoFrameAvailableCond);
if (sync->videoFrameWait) {
ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
}
} while (sync->videoFrameWait && sync->videoFramePending);
}
MutexUnlock(&sync->videoFrameMutex);
}
void GBASyncForceFrame(struct GBASync* sync) {
if (!sync) {
return;
}
MutexLock(&sync->videoFrameMutex);
ConditionWake(&sync->videoFrameAvailableCond);
MutexUnlock(&sync->videoFrameMutex);
}
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) {
if (!sync) {
return true;
}
MutexLock(&sync->videoFrameMutex);
ConditionWake(&sync->videoFrameRequiredCond);
if (!sync->videoFrameOn && !sync->videoFramePending) {
return false;
}
if (sync->videoFrameOn) {
if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) {
return false;
}
}
sync->videoFramePending = 0;
sync->videoFrameSkip = frameskip;
return true;
}
void GBASyncWaitFrameEnd(struct GBASync* sync) {
if (!sync) {
return;
}
MutexUnlock(&sync->videoFrameMutex);
}
bool GBASyncDrawingFrame(struct GBASync* sync) {
if (!sync) {
return true;
}
return sync->videoFrameSkip <= 0;
}
void GBASyncSetVideoSync(struct GBASync* sync, bool wait) {
if (!sync) {
return;
}
_changeVideoSync(sync, wait);
}
void GBASyncProduceAudio(struct GBASync* sync, bool wait) {
if (!sync) {
return;
}
if (sync->audioWait && wait) {
// TODO loop properly in event of spurious wakeups
ConditionWait(&sync->audioRequiredCond, &sync->audioBufferMutex);
}
MutexUnlock(&sync->audioBufferMutex);
}
void GBASyncLockAudio(struct GBASync* sync) {
if (!sync) {
return;
}
MutexLock(&sync->audioBufferMutex);
}
void GBASyncUnlockAudio(struct GBASync* sync) {
if (!sync) {
return;
}
MutexUnlock(&sync->audioBufferMutex);
}
void GBASyncConsumeAudio(struct GBASync* sync) {
if (!sync) {
return;
}
ConditionWake(&sync->audioRequiredCond);
MutexUnlock(&sync->audioBufferMutex);
}

View File

@ -11,6 +11,7 @@
#include "gba/gba.h"
#include "gba/input.h"
#include "gba/supervisor/overrides.h"
#include "gba/supervisor/sync.h"
#include "util/threading.h"
@ -35,20 +36,6 @@ enum ThreadState {
THREAD_CRASHED
};
struct GBASync {
int videoFramePending;
bool videoFrameWait;
int videoFrameSkip;
bool videoFrameOn;
Mutex videoFrameMutex;
Condition videoFrameAvailableCond;
Condition videoFrameRequiredCond;
bool audioWait;
Condition audioRequiredCond;
Mutex audioBufferMutex;
};
struct GBAThread {
// Output
enum ThreadState state;
@ -143,16 +130,4 @@ struct GBAThread* GBAThreadGetContext(void);
void GBAThreadTakeScreenshot(struct GBAThread* threadContext);
#endif
void GBASyncPostFrame(struct GBASync* sync);
void GBASyncForceFrame(struct GBASync* sync);
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip);
void GBASyncWaitFrameEnd(struct GBASync* sync);
bool GBASyncDrawingFrame(struct GBASync* sync);
void GBASyncSetVideoSync(struct GBASync* sync, bool wait);
void GBASyncProduceAudio(struct GBASync* sync, bool wait);
void GBASyncLockAudio(struct GBASync* sync);
void GBASyncUnlockAudio(struct GBASync* sync);
void GBASyncConsumeAudio(struct GBASync* sync);
#endif

View File

@ -9,7 +9,7 @@
#include "gba/io.h"
#include "gba/serialize.h"
#include "gba/supervisor/rr.h"
#include "gba/supervisor/thread.h"
#include "gba/supervisor/sync.h"
#include "util/memory.h"

View File

@ -6,7 +6,7 @@
#ifndef FFMPEG_ENCODER
#define FFMPEG_ENCODER
#include "gba/supervisor/thread.h"
#include "gba/gba.h"
#include <libavformat/avformat.h>

View File

@ -6,7 +6,7 @@
#ifndef IMAGEMAGICK_GIF_ENCODER
#define IMAGEMAGICK_GIF_ENCODER
#include "gba/supervisor/thread.h"
#include "gba/gba.h"
#define MAGICKCORE_HDRI_ENABLE 0
#define MAGICKCORE_QUANTUM_DEPTH 8