GBA Thread: Kill GBAThread

This commit is contained in:
Jeffrey Pfau 2016-02-09 21:38:43 -08:00
parent d25ba2ec59
commit a75c019fab
21 changed files with 16 additions and 1305 deletions

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "config.h"
#include "gba/gba.h"
#include "util/formatting.h"
#include "util/string.h"
#include "util/vfs.h"

View File

@ -5,10 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "audio.h"
#include "core/sync.h"
#include "gba/gba.h"
#include "gba/io.h"
#include "gba/serialize.h"
#include "gba/supervisor/thread.h"
#include "gba/video.h"
const unsigned GBA_AUDIO_SAMPLES = 2048;

View File

@ -5,14 +5,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba.h"
#include "core/thread.h"
#include "arm/decoder.h"
#include "arm/isa-inlines.h"
#include "gba/bios.h"
#include "gba/cheats.h"
#include "gba/context/overrides.h"
#include "gba/io.h"
#include "gba/rr/rr.h"
#include "gba/supervisor/thread.h"
#include "gba/serialize.h"
#include "gba/sio.h"
@ -90,8 +92,6 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
gba->romVf = 0;
gba->biosVf = 0;
gba->logHandler = 0;
gba->logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;
gba->stream = 0;
gba->keyCallback = 0;
gba->stopCallback = 0;
@ -650,80 +650,12 @@ void GBAStop(struct GBA* gba) {
gba->stopCallback->stop(gba->stopCallback);
}
static void _GBAVLog(struct GBA* gba, enum GBALogLevel level, const char* format, va_list args) {
struct GBAThread* threadContext = GBAThreadGetContext();
enum GBALogLevel logLevel = GBA_LOG_ALL;
if (gba) {
logLevel = gba->logLevel;
}
if (threadContext) {
logLevel = threadContext->logLevel;
gba = threadContext->gba;
}
if (!(level & logLevel) && level != GBA_LOG_FATAL) {
return;
}
if (level == GBA_LOG_FATAL && gba) {
gba->cpu->nextEvent = 0;
}
if (threadContext) {
if (level == GBA_LOG_FATAL) {
MutexLock(&threadContext->stateMutex);
threadContext->state = THREAD_CRASHED;
MutexUnlock(&threadContext->stateMutex);
}
}
if (gba && gba->logHandler) {
gba->logHandler(threadContext, level, format, args);
return;
}
vprintf(format, args);
printf("\n");
if (level == GBA_LOG_FATAL && !threadContext) {
abort();
}
}
void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) {
va_list args;
va_start(args, format);
_GBAVLog(gba, level, format, args);
va_end(args);
// TODO: Kill GBALog
}
void GBADebuggerLogShim(struct Debugger* debugger, enum DebuggerLogLevel level, const char* format, ...) {
struct GBA* gba = 0;
if (debugger->cpu) {
gba = (struct GBA*) debugger->cpu->master;
}
enum GBALogLevel gbaLevel;
switch (level) {
default: // Avoids compiler warning
case DEBUGGER_LOG_DEBUG:
gbaLevel = GBA_LOG_DEBUG;
break;
case DEBUGGER_LOG_INFO:
gbaLevel = GBA_LOG_INFO;
break;
case DEBUGGER_LOG_WARN:
gbaLevel = GBA_LOG_WARN;
break;
case DEBUGGER_LOG_ERROR:
gbaLevel = GBA_LOG_ERROR;
break;
}
va_list args;
va_start(args, format);
_GBAVLog(gba, gbaLevel, format, args);
va_end(args);
// TODO: Kill GBADebuggerLogShim
}
bool GBAIsROM(struct VFile* vf) {
@ -879,18 +811,7 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) {
void GBAFrameStarted(struct GBA* gba) {
UNUSED(gba);
struct GBAThread* thread = GBAThreadGetContext();
if (!thread) {
return;
}
if (thread->rewindBuffer) {
--thread->rewindBufferNext;
if (thread->rewindBufferNext <= 0) {
thread->rewindBufferNext = thread->rewindBufferInterval;
GBARecordFrame(thread);
}
}
// TODO: Put back rewind
}
void GBAFrameEnded(struct GBA* gba) {
@ -970,12 +891,6 @@ void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mo
}
}
#if (!defined(USE_PTHREADS) && !defined(_WIN32)) || defined(DISABLE_THREADING)
struct GBAThread* GBAThreadGetContext(void) {
return 0;
}
#endif
static bool _setSoftwareBreakpoint(struct Debugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d, address, mode, opcode);
return true;

View File

@ -56,7 +56,6 @@ enum {
};
struct GBA;
struct GBAThread;
struct Patch;
struct VFile;
@ -114,8 +113,6 @@ struct GBA {
const char* activeFile;
GBALogHandler logHandler;
enum GBALogLevel logLevel;
struct mAVStream* stream;
struct mKeyCallback* keyCallback;
struct mStopCallback* stopCallback;

View File

@ -37,11 +37,8 @@ enum GBASIOMode {
struct GBA;
struct GBAAudio;
struct GBASIO;
struct GBAThread;
struct GBAVideoRenderer;
typedef void (*GBALogHandler)(struct GBAThread*, enum GBALogLevel, const char* format, va_list args);
extern const int GBA_LUX_LEVELS[10];
struct GBALuminanceSource {

View File

@ -5,11 +5,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "serialize.h"
#include "core/sync.h"
#include "gba/audio.h"
#include "gba/cheats.h"
#include "gba/io.h"
#include "gba/rr/rr.h"
#include "gba/supervisor/thread.h"
#include "gba/video.h"
#include "util/memory.h"
@ -356,66 +356,6 @@ static struct GBASerializedState* _loadPNGState(struct VFile* vf, struct GBAExtd
}
#endif
bool GBASaveState(struct GBAThread* threadContext, struct VDir* dir, int slot, int flags) {
struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, true);
if (!vf) {
return false;
}
bool success = GBASaveStateNamed(threadContext->gba, vf, flags);
vf->close(vf);
if (success) {
#if SAVESTATE_DEBUG
vf = GBAGetState(threadContext->gba, dir, slot, false);
if (vf) {
struct GBA* backup = anonymousMemoryMap(sizeof(*backup));
memcpy(backup, threadContext->gba, sizeof(*backup));
memset(threadContext->gba->memory.io, 0, sizeof(threadContext->gba->memory.io));
memset(threadContext->gba->timers, 0, sizeof(threadContext->gba->timers));
GBALoadStateNamed(threadContext->gba, vf, flags);
if (memcmp(backup, threadContext->gba, sizeof(*backup))) {
char suffix[16] = { '\0' };
struct VFile* vf2;
snprintf(suffix, sizeof(suffix), ".dump.0.%d", slot);
vf2 = VDirOptionalOpenFile(dir, threadContext->gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
if (vf2) {
vf2->write(vf2, backup, sizeof(*backup));
vf2->close(vf2);
}
snprintf(suffix, sizeof(suffix), ".dump.1.%d", slot);
vf2 = VDirOptionalOpenFile(dir, threadContext->gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
if (vf2) {
vf2->write(vf2, threadContext->gba, sizeof(*threadContext->gba));
vf2->close(vf2);
}
}
mappedMemoryFree(backup, sizeof(*backup));
vf->close(vf);
}
#endif
GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i saved", slot);
} else {
GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to save", slot);
}
return success;
}
bool GBALoadState(struct GBAThread* threadContext, struct VDir* dir, int slot, int flags) {
struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, false);
if (!vf) {
return false;
}
threadContext->rewindBufferSize = 0;
bool success = GBALoadStateNamed(threadContext->gba, vf, flags);
vf->close(vf);
if (success) {
GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i loaded", slot);
} else {
GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to load", slot);
}
return success;
}
bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
struct GBAExtdata extdata;
GBAExtdataInit(&extdata);
@ -671,82 +611,7 @@ void GBADeallocateState(struct GBASerializedState* state) {
mappedMemoryFree(state, sizeof(struct GBASerializedState));
}
void GBARecordFrame(struct GBAThread* thread) {
int offset = thread->rewindBufferWriteOffset;
struct GBASerializedState* state = thread->rewindBuffer[offset];
if (!state) {
state = GBAAllocateState();
thread->rewindBuffer[offset] = state;
}
GBASerialize(thread->gba, state);
if (thread->rewindScreenBuffer) {
unsigned stride;
const uint8_t* pixels = 0;
thread->gba->video.renderer->getPixels(thread->gba->video.renderer, &stride, (const void**) &pixels);
if (pixels) {
size_t y;
for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
memcpy(&thread->rewindScreenBuffer[(offset * VIDEO_VERTICAL_PIXELS + y) * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL], &pixels[y * stride * BYTES_PER_PIXEL], VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL);
}
}
}
thread->rewindBufferSize = thread->rewindBufferSize == thread->rewindBufferCapacity ? thread->rewindBufferCapacity : thread->rewindBufferSize + 1;
thread->rewindBufferWriteOffset = (offset + 1) % thread->rewindBufferCapacity;
}
void GBARewindSettingsChanged(struct GBAThread* threadContext, int newCapacity, int newInterval) {
if (newCapacity == threadContext->rewindBufferCapacity && newInterval == threadContext->rewindBufferInterval) {
return;
}
threadContext->rewindBufferInterval = newInterval;
threadContext->rewindBufferNext = threadContext->rewindBufferInterval;
threadContext->rewindBufferSize = 0;
if (threadContext->rewindBuffer) {
int i;
for (i = 0; i < threadContext->rewindBufferCapacity; ++i) {
GBADeallocateState(threadContext->rewindBuffer[i]);
}
free(threadContext->rewindBuffer);
free(threadContext->rewindScreenBuffer);
}
threadContext->rewindBufferCapacity = newCapacity;
if (threadContext->rewindBufferCapacity > 0) {
threadContext->rewindBuffer = calloc(threadContext->rewindBufferCapacity, sizeof(struct GBASerializedState*));
threadContext->rewindScreenBuffer = calloc(threadContext->rewindBufferCapacity, VIDEO_VERTICAL_PIXELS * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL);
} else {
threadContext->rewindBuffer = 0;
threadContext->rewindScreenBuffer = 0;
}
}
int GBARewind(struct GBAThread* thread, int nStates) {
if (nStates > thread->rewindBufferSize || nStates < 0) {
nStates = thread->rewindBufferSize;
}
if (nStates == 0) {
return 0;
}
int offset = thread->rewindBufferWriteOffset - nStates;
if (offset < 0) {
offset += thread->rewindBufferCapacity;
}
struct GBASerializedState* state = thread->rewindBuffer[offset];
if (!state) {
return 0;
}
thread->rewindBufferSize -= nStates;
thread->rewindBufferWriteOffset = offset;
GBADeserialize(thread->gba, state);
if (thread->rewindScreenBuffer) {
thread->gba->video.renderer->putPixels(thread->gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, &thread->rewindScreenBuffer[offset * VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL]);
}
return nStates;
}
void GBARewindAll(struct GBAThread* thread) {
GBARewind(thread, thread->rewindBufferSize);
}
// TODO: Put back rewind
void GBATakeScreenshot(struct GBA* gba, struct VDir* dir) {
#ifdef USE_PNG

View File

@ -358,13 +358,10 @@ struct GBAExtdata {
};
struct VDir;
struct GBAThread;
void GBASerialize(struct GBA* gba, struct GBASerializedState* state);
bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state);
bool GBASaveState(struct GBAThread* thread, struct VDir* dir, int slot, int flags);
bool GBALoadState(struct GBAThread* thread, struct VDir* dir, int slot, int flags);
struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write);
void GBADeleteState(struct GBA* thread, struct VDir* dir, int slot);
@ -382,11 +379,6 @@ struct GBASerializedState* GBAExtractState(struct VFile* vf, struct GBAExtdata*
struct GBASerializedState* GBAAllocateState(void);
void GBADeallocateState(struct GBASerializedState* state);
void GBARecordFrame(struct GBAThread* thread);
void GBARewindSettingsChanged(struct GBAThread* thread, int newCapacity, int newInterval);
int GBARewind(struct GBAThread* thread, int nStates);
void GBARewindAll(struct GBAThread* thread);
void GBATakeScreenshot(struct GBA* gba, struct VDir* dir);
#endif

View File

@ -7,7 +7,6 @@
#include "gba/io.h"
#include "gba/serialize.h"
#include "gba/supervisor/thread.h"
#ifdef USE_CLI_DEBUGGER

View File

@ -1,736 +0,0 @@
/* 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"
#include "arm.h"
#include "core/config.h"
#include "gba/gba.h"
#include "gba/cheats.h"
#include "gba/serialize.h"
#include "gba/rr/mgm.h"
#include "gba/rr/vbm.h"
#include "debugger/debugger.h"
#include "util/patch.h"
#include "util/vfs.h"
#include "platform/commandline.h"
#include <signal.h>
static const float _defaultFPSTarget = 60.f;
#ifndef DISABLE_THREADING
static bool _reloadDirectories(struct GBAThread* threadContext) {
mDirectorySetDetachBase(&threadContext->dirs);
char basename[PATH_MAX];
if (threadContext->fname) {
char dirname[PATH_MAX];
separatePath(threadContext->fname, dirname, basename, 0);
mDirectorySetAttachBase(&threadContext->dirs, VDirOpen(dirname));
} else {
return false;
}
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s.sav", basename);
threadContext->save = threadContext->dirs.save->openFile(threadContext->dirs.save, path, O_CREAT | O_RDWR);
if (!threadContext->patch) {
snprintf(path, sizeof(path), "%s.ups", basename);
threadContext->patch = threadContext->dirs.patch->openFile(threadContext->dirs.patch, path, O_RDONLY);
}
if (!threadContext->patch) {
snprintf(path, sizeof(path), "%s.ips", basename);
threadContext->patch = threadContext->dirs.patch->openFile(threadContext->dirs.patch, path, O_RDONLY);
}
if (!threadContext->patch) {
snprintf(path, sizeof(path), "%s.bps", basename);
threadContext->patch = threadContext->dirs.patch->openFile(threadContext->dirs.patch, path, O_RDONLY);
}
return true;
}
#ifdef USE_PTHREADS
static pthread_key_t _contextKey;
static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT;
static void _createTLS(void) {
pthread_key_create(&_contextKey, 0);
}
#elif _WIN32
static DWORD _contextKey;
static INIT_ONCE _contextOnce = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) {
UNUSED(once);
UNUSED(param);
UNUSED(context);
_contextKey = TlsAlloc();
return TRUE;
}
#endif
static void _changeState(struct GBAThread* threadContext, enum mCoreThreadState newState, bool broadcast) {
MutexLock(&threadContext->stateMutex);
threadContext->state = newState;
if (broadcast) {
ConditionWake(&threadContext->stateCond);
}
MutexUnlock(&threadContext->stateMutex);
}
static void _waitOnInterrupt(struct GBAThread* threadContext) {
while (threadContext->state == THREAD_INTERRUPTED) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
}
}
static void _waitUntilNotState(struct GBAThread* threadContext, enum mCoreThreadState oldState) {
MutexLock(&threadContext->sync.videoFrameMutex);
bool videoFrameWait = threadContext->sync.videoFrameWait;
threadContext->sync.videoFrameWait = false;
MutexUnlock(&threadContext->sync.videoFrameMutex);
while (threadContext->state == oldState) {
MutexUnlock(&threadContext->stateMutex);
if (!MutexTryLock(&threadContext->sync.videoFrameMutex)) {
ConditionWake(&threadContext->sync.videoFrameRequiredCond);
MutexUnlock(&threadContext->sync.videoFrameMutex);
}
if (!MutexTryLock(&threadContext->sync.audioBufferMutex)) {
ConditionWake(&threadContext->sync.audioRequiredCond);
MutexUnlock(&threadContext->sync.audioBufferMutex);
}
MutexLock(&threadContext->stateMutex);
ConditionWake(&threadContext->stateCond);
}
MutexLock(&threadContext->sync.videoFrameMutex);
threadContext->sync.videoFrameWait = videoFrameWait;
MutexUnlock(&threadContext->sync.videoFrameMutex);
}
static void _pauseThread(struct GBAThread* threadContext, bool onThread) {
threadContext->state = THREAD_PAUSING;
if (!onThread) {
_waitUntilNotState(threadContext, THREAD_PAUSING);
}
}
struct GBAThreadStop {
struct mStopCallback d;
struct GBAThread* p;
};
static void _stopCallback(struct mStopCallback* stop) {
struct GBAThreadStop* callback = (struct GBAThreadStop*) stop;
if (callback->p->stopCallback(callback->p)) {
_changeState(callback->p, THREAD_EXITING, false);
}
}
static THREAD_ENTRY _GBAThreadRun(void* context) {
#ifdef USE_PTHREADS
pthread_once(&_contextOnce, _createTLS);
#elif _WIN32
InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0);
#endif
struct GBA gba;
struct ARMCore cpu;
struct Patch patch;
struct GBACheatDevice cheatDevice;
struct GBAThread* threadContext = context;
struct mCPUComponent* components[GBA_COMPONENT_MAX] = { 0 };
struct GBARRContext* movie = 0;
int numComponents = GBA_COMPONENT_MAX;
ThreadSetName("CPU Thread");
#if !defined(_WIN32) && defined(USE_PTHREADS)
sigset_t signals;
sigemptyset(&signals);
pthread_sigmask(SIG_SETMASK, &signals, 0);
#endif
GBACreate(&gba);
ARMSetComponents(&cpu, &gba.d, numComponents, components);
ARMInit(&cpu);
gba.sync = &threadContext->sync;
threadContext->gba = &gba;
threadContext->cpu = &cpu;
gba.logLevel = threadContext->logLevel;
gba.logHandler = threadContext->logHandler;
gba.stream = threadContext->stream;
gba.video.frameskip = threadContext->frameskip;
struct GBAThreadStop stop;
if (threadContext->stopCallback) {
stop.d.stop = _stopCallback;
stop.p = threadContext;
gba.stopCallback = &stop.d;
}
gba.idleOptimization = threadContext->idleOptimization;
#ifdef USE_PTHREADS
pthread_setspecific(_contextKey, threadContext);
#elif _WIN32
TlsSetValue(_contextKey, threadContext);
#endif
if (threadContext->audioBuffers) {
GBAAudioResizeBuffer(&gba.audio, threadContext->audioBuffers);
} else {
threadContext->audioBuffers = GBA_AUDIO_SAMPLES;
}
if (threadContext->renderer) {
GBAVideoAssociateRenderer(&gba.video, threadContext->renderer);
}
if (threadContext->rom) {
if (GBAIsMB(threadContext->rom)) {
GBALoadMB(&gba, threadContext->rom, threadContext->fname);
} else {
GBALoadROM(&gba, threadContext->rom, threadContext->save, threadContext->fname);
}
struct GBACartridgeOverride override;
const struct GBACartridge* cart = (const struct GBACartridge*) gba.pristineRom;
memcpy(override.id, &cart->id, sizeof(override.id));
if (GBAOverrideFind(threadContext->overrides, &override)) {
GBAOverrideApply(&gba, &override);
}
if (threadContext->hasOverride) {
GBAOverrideApply(&gba, &threadContext->override);
}
if (threadContext->patch && loadPatch(threadContext->patch, &patch)) {
GBAApplyPatch(&gba, &patch);
}
}
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
GBALoadBIOS(&gba, threadContext->bios);
}
if (threadContext->movie) {
struct VDir* movieDir = VDirOpen(threadContext->movie);
if (!movieDir) {
movieDir = VDirOpenArchive(threadContext->movie);
}
if (movieDir) {
struct GBAMGMContext* mgm = malloc(sizeof(*mgm));
GBAMGMContextCreate(mgm);
if (!GBAMGMSetStream(mgm, movieDir)) {
mgm->d.destroy(&mgm->d);
} else {
movie = &mgm->d;
}
} else {
struct VFile* movieFile = VFileOpen(threadContext->movie, O_RDONLY);
if (movieFile) {
struct GBAVBMContext* vbm = malloc(sizeof(*vbm));
GBAVBMContextCreate(vbm);
if (!GBAVBMSetStream(vbm, movieFile)) {
vbm->d.destroy(&vbm->d);
} else {
movie = &vbm->d;
}
}
}
}
ARMReset(&cpu);
if (movie) {
gba.rr = movie;
movie->startPlaying(movie, false);
GBARRInitPlay(&gba);
}
if (threadContext->skipBios && gba.pristineRom) {
GBASkipBIOS(&gba);
}
if (!threadContext->cheats) {
GBACheatDeviceCreate(&cheatDevice);
threadContext->cheats = &cheatDevice;
}
if (threadContext->cheatsFile) {
GBACheatParseFile(threadContext->cheats, threadContext->cheatsFile);
}
GBACheatAttachDevice(&gba, threadContext->cheats);
if (threadContext->debugger) {
threadContext->debugger->log = GBADebuggerLogShim;
GBAAttachDebugger(&gba, threadContext->debugger);
DebuggerEnter(threadContext->debugger, DEBUGGER_ENTER_ATTACHED, 0);
}
GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers);
if (threadContext->volume == 0) {
threadContext->volume = GBA_AUDIO_VOLUME_MAX;
}
if (threadContext->mute) {
gba.audio.masterVolume = 0;
} else {
gba.audio.masterVolume = threadContext->volume;
}
gba.keySource = &threadContext->activeKeys;
if (threadContext->startCallback) {
threadContext->startCallback(threadContext);
}
_changeState(threadContext, THREAD_RUNNING, true);
while (threadContext->state < THREAD_EXITING) {
if (threadContext->debugger) {
struct Debugger* debugger = threadContext->debugger;
DebuggerRun(debugger);
if (debugger->state == DEBUGGER_SHUTDOWN) {
_changeState(threadContext, THREAD_EXITING, false);
}
} else {
while (threadContext->state == THREAD_RUNNING) {
ARMRunLoop(&cpu);
}
}
int resetScheduled = 0;
MutexLock(&threadContext->stateMutex);
while (threadContext->state > THREAD_RUNNING && threadContext->state < THREAD_EXITING) {
if (threadContext->state == THREAD_PAUSING) {
threadContext->state = THREAD_PAUSED;
ConditionWake(&threadContext->stateCond);
}
if (threadContext->state == THREAD_INTERRUPTING) {
threadContext->state = THREAD_INTERRUPTED;
ConditionWake(&threadContext->stateCond);
}
if (threadContext->state == THREAD_RUN_ON) {
if (threadContext->run) {
threadContext->run(threadContext);
}
threadContext->state = threadContext->savedState;
ConditionWake(&threadContext->stateCond);
}
if (threadContext->state == THREAD_RESETING) {
threadContext->state = THREAD_RUNNING;
resetScheduled = 1;
}
while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
}
}
MutexUnlock(&threadContext->stateMutex);
if (resetScheduled) {
ARMReset(&cpu);
if (threadContext->skipBios && gba.pristineRom) {
GBASkipBIOS(&gba);
}
}
}
while (threadContext->state < THREAD_SHUTDOWN) {
_changeState(threadContext, THREAD_SHUTDOWN, false);
}
if (threadContext->cleanCallback) {
threadContext->cleanCallback(threadContext);
}
threadContext->gba = 0;
ARMDeinit(&cpu);
GBADestroy(&gba);
if (&cheatDevice == threadContext->cheats) {
GBACheatDeviceDestroy(&cheatDevice);
}
if (movie) {
movie->destroy(movie);
free(movie);
}
threadContext->sync.videoFrameOn = false;
ConditionWake(&threadContext->sync.videoFrameAvailableCond);
ConditionWake(&threadContext->sync.audioRequiredCond);
return 0;
}
void GBAMapOptionsToContext(const struct mCoreOptions* opts, struct GBAThread* threadContext) {
if (opts->useBios) {
threadContext->bios = VFileOpen(opts->bios, O_RDONLY);
} else {
threadContext->bios = 0;
}
threadContext->frameskip = opts->frameskip;
threadContext->volume = opts->volume;
threadContext->mute = opts->mute;
threadContext->logLevel = opts->logLevel;
if (opts->rewindEnable) {
threadContext->rewindBufferCapacity = opts->rewindBufferCapacity;
threadContext->rewindBufferInterval = opts->rewindBufferInterval;
} else {
threadContext->rewindBufferCapacity = 0;
}
threadContext->skipBios = opts->skipBios;
threadContext->sync.audioWait = opts->audioSync;
threadContext->sync.videoFrameWait = opts->videoSync;
if (opts->fpsTarget) {
threadContext->fpsTarget = opts->fpsTarget;
}
if (opts->audioBuffers) {
threadContext->audioBuffers = opts->audioBuffers;
}
mDirectorySetMapOptions(&threadContext->dirs, opts);
}
void GBAMapArgumentsToContext(const struct mArguments* args, struct GBAThread* threadContext) {
GBAThreadLoadROM(threadContext, args->fname);
threadContext->fname = args->fname;
threadContext->patch = VFileOpen(args->patch, O_RDONLY);
threadContext->cheatsFile = VFileOpen(args->cheatsFile, O_RDONLY);
threadContext->movie = args->movie;
}
bool GBAThreadStart(struct GBAThread* threadContext) {
// TODO: error check
threadContext->activeKeys = 0;
threadContext->state = THREAD_INITIALIZED;
threadContext->sync.videoFrameOn = true;
threadContext->rewindBuffer = 0;
threadContext->rewindScreenBuffer = 0;
int newCapacity = threadContext->rewindBufferCapacity;
int newInterval = threadContext->rewindBufferInterval;
threadContext->rewindBufferCapacity = 0;
threadContext->rewindBufferInterval = 0;
GBARewindSettingsChanged(threadContext, newCapacity, newInterval);
if (!threadContext->fpsTarget) {
threadContext->fpsTarget = _defaultFPSTarget;
}
bool bootBios = threadContext->bootBios && threadContext->bios;
if (threadContext->rom && (!GBAIsROM(threadContext->rom) || bootBios)) {
threadContext->rom->close(threadContext->rom);
threadContext->rom = 0;
}
if (!threadContext->rom && !bootBios) {
threadContext->state = THREAD_SHUTDOWN;
return false;
}
_reloadDirectories(threadContext);
MutexInit(&threadContext->stateMutex);
ConditionInit(&threadContext->stateCond);
MutexInit(&threadContext->sync.videoFrameMutex);
ConditionInit(&threadContext->sync.videoFrameAvailableCond);
ConditionInit(&threadContext->sync.videoFrameRequiredCond);
MutexInit(&threadContext->sync.audioBufferMutex);
ConditionInit(&threadContext->sync.audioRequiredCond);
threadContext->interruptDepth = 0;
#ifdef USE_PTHREADS
sigset_t signals;
sigemptyset(&signals);
sigaddset(&signals, SIGINT);
sigaddset(&signals, SIGTRAP);
pthread_sigmask(SIG_BLOCK, &signals, 0);
#endif
MutexLock(&threadContext->stateMutex);
ThreadCreate(&threadContext->thread, _GBAThreadRun, threadContext);
while (threadContext->state < THREAD_RUNNING) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
}
MutexUnlock(&threadContext->stateMutex);
return true;
}
bool GBAThreadHasStarted(struct GBAThread* threadContext) {
bool hasStarted;
MutexLock(&threadContext->stateMutex);
hasStarted = threadContext->state > THREAD_INITIALIZED;
MutexUnlock(&threadContext->stateMutex);
return hasStarted;
}
bool GBAThreadHasExited(struct GBAThread* threadContext) {
bool hasExited;
MutexLock(&threadContext->stateMutex);
hasExited = threadContext->state > THREAD_EXITING;
MutexUnlock(&threadContext->stateMutex);
return hasExited;
}
bool GBAThreadHasCrashed(struct GBAThread* threadContext) {
bool hasExited;
MutexLock(&threadContext->stateMutex);
hasExited = threadContext->state == THREAD_CRASHED;
MutexUnlock(&threadContext->stateMutex);
return hasExited;
}
void GBAThreadEnd(struct GBAThread* threadContext) {
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
threadContext->state = THREAD_EXITING;
if (threadContext->gba) {
threadContext->gba->cpu->halted = false;
}
ConditionWake(&threadContext->stateCond);
MutexUnlock(&threadContext->stateMutex);
MutexLock(&threadContext->sync.audioBufferMutex);
threadContext->sync.audioWait = 0;
ConditionWake(&threadContext->sync.audioRequiredCond);
MutexUnlock(&threadContext->sync.audioBufferMutex);
MutexLock(&threadContext->sync.videoFrameMutex);
threadContext->sync.videoFrameWait = false;
threadContext->sync.videoFrameOn = false;
ConditionWake(&threadContext->sync.videoFrameRequiredCond);
ConditionWake(&threadContext->sync.videoFrameAvailableCond);
MutexUnlock(&threadContext->sync.videoFrameMutex);
}
void GBAThreadReset(struct GBAThread* threadContext) {
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
threadContext->state = THREAD_RESETING;
ConditionWake(&threadContext->stateCond);
MutexUnlock(&threadContext->stateMutex);
}
void GBAThreadJoin(struct GBAThread* threadContext) {
ThreadJoin(threadContext->thread);
MutexDeinit(&threadContext->stateMutex);
ConditionDeinit(&threadContext->stateCond);
MutexDeinit(&threadContext->sync.videoFrameMutex);
ConditionWake(&threadContext->sync.videoFrameAvailableCond);
ConditionDeinit(&threadContext->sync.videoFrameAvailableCond);
ConditionWake(&threadContext->sync.videoFrameRequiredCond);
ConditionDeinit(&threadContext->sync.videoFrameRequiredCond);
ConditionWake(&threadContext->sync.audioRequiredCond);
ConditionDeinit(&threadContext->sync.audioRequiredCond);
MutexDeinit(&threadContext->sync.audioBufferMutex);
int i;
for (i = 0; i < threadContext->rewindBufferCapacity; ++i) {
if (threadContext->rewindBuffer[i]) {
GBADeallocateState(threadContext->rewindBuffer[i]);
}
}
free(threadContext->rewindBuffer);
free(threadContext->rewindScreenBuffer);
if (threadContext->rom) {
threadContext->rom->close(threadContext->rom);
threadContext->rom = 0;
}
if (threadContext->save) {
threadContext->save->close(threadContext->save);
threadContext->save = 0;
}
if (threadContext->bios) {
threadContext->bios->close(threadContext->bios);
threadContext->bios = 0;
}
if (threadContext->patch) {
threadContext->patch->close(threadContext->patch);
threadContext->patch = 0;
}
}
bool GBAThreadIsActive(struct GBAThread* threadContext) {
return threadContext->state >= THREAD_RUNNING && threadContext->state < THREAD_EXITING;
}
void GBAThreadInterrupt(struct GBAThread* threadContext) {
MutexLock(&threadContext->stateMutex);
++threadContext->interruptDepth;
if (threadContext->interruptDepth > 1 || !GBAThreadIsActive(threadContext)) {
MutexUnlock(&threadContext->stateMutex);
return;
}
threadContext->savedState = threadContext->state;
_waitOnInterrupt(threadContext);
threadContext->state = THREAD_INTERRUPTING;
threadContext->gba->cpu->nextEvent = 0;
ConditionWake(&threadContext->stateCond);
_waitUntilNotState(threadContext, THREAD_INTERRUPTING);
MutexUnlock(&threadContext->stateMutex);
}
void GBAThreadContinue(struct GBAThread* threadContext) {
MutexLock(&threadContext->stateMutex);
--threadContext->interruptDepth;
if (threadContext->interruptDepth < 1 && GBAThreadIsActive(threadContext)) {
threadContext->state = threadContext->savedState;
ConditionWake(&threadContext->stateCond);
}
MutexUnlock(&threadContext->stateMutex);
}
void GBARunOnThread(struct GBAThread* threadContext, void (*run)(struct GBAThread*)) {
MutexLock(&threadContext->stateMutex);
threadContext->run = run;
_waitOnInterrupt(threadContext);
threadContext->savedState = threadContext->state;
threadContext->state = THREAD_RUN_ON;
threadContext->gba->cpu->nextEvent = 0;
ConditionWake(&threadContext->stateCond);
_waitUntilNotState(threadContext, THREAD_RUN_ON);
MutexUnlock(&threadContext->stateMutex);
}
void GBAThreadPause(struct GBAThread* threadContext) {
bool frameOn = threadContext->sync.videoFrameOn;
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
if (threadContext->state == THREAD_RUNNING) {
_pauseThread(threadContext, false);
threadContext->frameWasOn = frameOn;
frameOn = false;
}
MutexUnlock(&threadContext->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn);
}
void GBAThreadUnpause(struct GBAThread* threadContext) {
bool frameOn = threadContext->sync.videoFrameOn;
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) {
threadContext->state = THREAD_RUNNING;
ConditionWake(&threadContext->stateCond);
frameOn = threadContext->frameWasOn;
}
MutexUnlock(&threadContext->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn);
}
bool GBAThreadIsPaused(struct GBAThread* threadContext) {
bool isPaused;
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
isPaused = threadContext->state == THREAD_PAUSED;
MutexUnlock(&threadContext->stateMutex);
return isPaused;
}
void GBAThreadTogglePause(struct GBAThread* threadContext) {
bool frameOn = threadContext->sync.videoFrameOn;
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) {
threadContext->state = THREAD_RUNNING;
ConditionWake(&threadContext->stateCond);
frameOn = threadContext->frameWasOn;
} else if (threadContext->state == THREAD_RUNNING) {
_pauseThread(threadContext, false);
threadContext->frameWasOn = frameOn;
frameOn = false;
}
MutexUnlock(&threadContext->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn);
}
void GBAThreadPauseFromThread(struct GBAThread* threadContext) {
bool frameOn = true;
MutexLock(&threadContext->stateMutex);
_waitOnInterrupt(threadContext);
if (threadContext->state == THREAD_RUNNING) {
_pauseThread(threadContext, true);
frameOn = false;
}
MutexUnlock(&threadContext->stateMutex);
mCoreSyncSetVideoSync(&threadContext->sync, frameOn);
}
void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname) {
threadContext->rom = mDirectorySetOpenPath(&threadContext->dirs, fname, GBAIsROM);
}
void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname) {
GBAUnloadROM(threadContext->gba);
if (threadContext->rom) {
threadContext->rom->close(threadContext->rom);
threadContext->rom = 0;
}
if (threadContext->save) {
threadContext->save->close(threadContext->save);
threadContext->save = 0;
}
if (threadContext->dirs.archive) {
threadContext->dirs.archive->close(threadContext->dirs.archive);
threadContext->dirs.archive = 0;
}
GBAThreadLoadROM(threadContext, fname);
threadContext->fname = fname;
_reloadDirectories(threadContext);
GBARaiseIRQ(threadContext->gba, IRQ_GAMEPAK);
GBALoadROM(threadContext->gba, threadContext->rom, threadContext->save, threadContext->fname);
}
#ifdef USE_PTHREADS
struct GBAThread* GBAThreadGetContext(void) {
pthread_once(&_contextOnce, _createTLS);
return pthread_getspecific(_contextKey);
}
#elif _WIN32
struct GBAThread* GBAThreadGetContext(void) {
InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0);
return TlsGetValue(_contextKey);
}
#endif
void GBAThreadTakeScreenshot(struct GBAThread* threadContext) {
GBATakeScreenshot(threadContext->gba, threadContext->dirs.screenshot);
}
#else
struct GBAThread* GBAThreadGetContext(void) {
return 0;
}
#endif

View File

@ -1,127 +0,0 @@
/* 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_THREAD_H
#define GBA_THREAD_H
#include "util/common.h"
#include "core/directories.h"
#include "core/sync.h"
#include "core/thread.h"
#include "gba/gba.h"
#include "gba/input.h"
#include "gba/context/overrides.h"
#include "util/threading.h"
struct GBAThread;
struct mArguments;
struct GBACheatSet;
struct mCoreOptions;
typedef void (*GBAThreadCallback)(struct GBAThread* threadContext);
typedef bool (*ThreadStopCallback)(struct GBAThread* threadContext);
struct GBAThread {
// Output
enum mCoreThreadState state;
struct GBA* gba;
struct ARMCore* cpu;
// Input
struct GBAVideoRenderer* renderer;
struct GBASIODriverSet sioDrivers;
struct Debugger* debugger;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
struct mDirectorySet dirs;
#endif
struct VFile* rom;
struct VFile* save;
struct VFile* bios;
struct VFile* patch;
struct VFile* cheatsFile;
const char* fname;
const char* movie;
int activeKeys;
struct mAVStream* stream;
struct Configuration* overrides;
enum GBAIdleLoopOptimization idleOptimization;
bool bootBios;
bool hasOverride;
struct GBACartridgeOverride override;
// Run-time options
int frameskip;
float fpsTarget;
size_t audioBuffers;
bool skipBios;
int volume;
bool mute;
// Threading state
Thread thread;
Mutex stateMutex;
Condition stateCond;
enum mCoreThreadState savedState;
int interruptDepth;
bool frameWasOn;
GBALogHandler logHandler;
int logLevel;
GBAThreadCallback startCallback;
GBAThreadCallback cleanCallback;
GBAThreadCallback frameCallback;
ThreadStopCallback stopCallback;
void* userData;
void (*run)(struct GBAThread*);
struct mCoreSync sync;
int rewindBufferSize;
int rewindBufferCapacity;
int rewindBufferInterval;
int rewindBufferNext;
struct GBASerializedState** rewindBuffer;
int rewindBufferWriteOffset;
uint8_t* rewindScreenBuffer;
struct GBACheatDevice* cheats;
};
void GBAMapOptionsToContext(const struct mCoreOptions*, struct GBAThread*);
void GBAMapArgumentsToContext(const struct mArguments*, struct GBAThread*);
bool GBAThreadStart(struct GBAThread* threadContext);
bool GBAThreadHasStarted(struct GBAThread* threadContext);
bool GBAThreadHasExited(struct GBAThread* threadContext);
bool GBAThreadHasCrashed(struct GBAThread* threadContext);
void GBAThreadEnd(struct GBAThread* threadContext);
void GBAThreadReset(struct GBAThread* threadContext);
void GBAThreadJoin(struct GBAThread* threadContext);
bool GBAThreadIsActive(struct GBAThread* threadContext);
void GBAThreadInterrupt(struct GBAThread* threadContext);
void GBAThreadContinue(struct GBAThread* threadContext);
void GBARunOnThread(struct GBAThread* threadContext, void (*run)(struct GBAThread*));
void GBAThreadPause(struct GBAThread* threadContext);
void GBAThreadUnpause(struct GBAThread* threadContext);
bool GBAThreadIsPaused(struct GBAThread* threadContext);
void GBAThreadTogglePause(struct GBAThread* threadContext);
void GBAThreadPauseFromThread(struct GBAThread* threadContext);
struct GBAThread* GBAThreadGetContext(void);
void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname);
void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname);
#ifdef USE_PNG
void GBAThreadTakeScreenshot(struct GBAThread* threadContext);
#endif
#endif

View File

@ -9,8 +9,8 @@
#include <QResizeEvent>
extern "C" {
#include "gba/supervisor/thread.h"
#include "core/core.h"
#include "core/thread.h"
#ifdef BUILD_GL
#include "platform/opengl/gl.h"
#endif

View File

@ -16,7 +16,6 @@
#include <QIcon>
extern "C" {
#include "gba/supervisor/thread.h"
#include "platform/commandline.h"
#include "util/nointro.h"
#include "util/socket.h"

View File

@ -11,10 +11,6 @@
#include "ui_LogView.h"
extern "C" {
#include "gba/supervisor/thread.h"
}
namespace QGBA {
class LogController;

View File

@ -9,7 +9,7 @@
#include "GameController.h"
extern "C" {
#include "gba/supervisor/thread.h"
#include "gba/gba.h"
}
using namespace QGBA;

View File

@ -13,6 +13,7 @@
#include <QFontDatabase>
extern "C" {
#include "core/core.h"
#include "gba/supervisor/export.h"
#include "util/vfs.h"
}

View File

@ -9,6 +9,8 @@
#include "GameController.h"
extern "C" {
#include "core/core.h"
#include "gba/gba.h"
#include "util/nointro.h"
}

View File

@ -10,10 +10,6 @@
#include "ui_ROMInfo.h"
extern "C" {
#include "gba/supervisor/thread.h"
}
namespace QGBA {
class GameController;

View File

@ -21,7 +21,6 @@
#ifdef M_CORE_GBA
#include "gba/core.h"
#include "gba/gba.h"
#include "gba/supervisor/thread.h"
#include "gba/video.h"
#endif
#ifdef M_CORE_GB

View File

@ -5,8 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "sdl-audio.h"
#include "core/thread.h"
#include "gba/gba.h"
#include "gba/supervisor/thread.h"
#include "third-party/blip_buf/blip_buf.h"

View File

@ -12,7 +12,6 @@
#include "gba/io.h"
#include "gba/rr/rr.h"
#include "gba/serialize.h"
#include "gba/supervisor/thread.h"
#include "gba/video.h"
#include "gba/renderers/video-software.h"
#include "util/configuration.h"
@ -380,159 +379,6 @@ static void _pauseAfterFrame(struct mCoreThread* context) {
mCoreThreadPauseFromThread(context);
}
static void _mSDLHandleKeypressGBA(struct GBAThread* context, struct mSDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) {
enum GBAKey key = GBA_KEY_NONE;
if (!event->keysym.mod) {
#if !defined(BUILD_PANDORA) && SDL_VERSION_ATLEAST(2, 0, 0)
key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.scancode);
#else
key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym);
#endif
}
if (key != GBA_KEY_NONE) {
if (event->type == SDL_KEYDOWN) {
context->activeKeys |= 1 << key;
} else {
context->activeKeys &= ~(1 << key);
}
return;
}
if (event->keysym.sym == SDLK_TAB) {
context->sync.audioWait = event->type != SDL_KEYDOWN;
return;
}
if (event->type == SDL_KEYDOWN) {
switch (event->keysym.sym) {
case SDLK_F11:
if (context->debugger) {
DebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL, 0);
}
return;
#ifdef USE_PNG
case SDLK_F12:
GBAThreadInterrupt(context);
GBAThreadTakeScreenshot(context);
GBAThreadContinue(context);
return;
#endif
case SDLK_BACKQUOTE:
GBAThreadInterrupt(context);
GBARewind(context, 10);
GBAThreadContinue(context);
return;
#ifdef BUILD_PANDORA
case SDLK_ESCAPE:
GBAThreadEnd(context);
return;
#endif
default:
if ((event->keysym.mod & GUI_MOD) && (event->keysym.mod & GUI_MOD) == event->keysym.mod) {
switch (event->keysym.sym) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDLK_f:
SDL_SetWindowFullscreen(sdlContext->window, sdlContext->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
sdlContext->fullscreen = !sdlContext->fullscreen;
sdlContext->windowUpdated = 1;
break;
#endif
case SDLK_p:
GBAThreadTogglePause(context);
break;
case SDLK_r:
GBAThreadReset(context);
break;
default:
break;
}
}
if (event->keysym.mod & KMOD_SHIFT) {
switch (event->keysym.sym) {
case SDLK_F1:
case SDLK_F2:
case SDLK_F3:
case SDLK_F4:
case SDLK_F5:
case SDLK_F6:
case SDLK_F7:
case SDLK_F8:
case SDLK_F9:
GBAThreadInterrupt(context);
GBASaveState(context, context->dirs.state, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
GBAThreadContinue(context);
break;
default:
break;
}
} else {
switch (event->keysym.sym) {
case SDLK_F1:
case SDLK_F2:
case SDLK_F3:
case SDLK_F4:
case SDLK_F5:
case SDLK_F6:
case SDLK_F7:
case SDLK_F8:
case SDLK_F9:
GBAThreadInterrupt(context);
GBALoadState(context, context->dirs.state, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
GBAThreadContinue(context);
break;
default:
break;
}
}
return;
}
}
}
static void _mSDLHandleJoyButtonGBA(struct GBAThread* context, struct mSDLPlayer* sdlContext, const struct SDL_JoyButtonEvent* event) {
enum GBAKey key = 0;
key = mInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button);
if (key == GBA_KEY_NONE) {
return;
}
if (event->type == SDL_JOYBUTTONDOWN) {
context->activeKeys |= 1 << key;
} else {
context->activeKeys &= ~(1 << key);
}
}
static void _mSDLHandleJoyHatGBA(struct GBAThread* context, const struct SDL_JoyHatEvent* event) {
enum GBAKey key = 0;
if (event->value & SDL_HAT_UP) {
key |= 1 << GBA_KEY_UP;
}
if (event->value & SDL_HAT_LEFT) {
key |= 1 << GBA_KEY_LEFT;
}
if (event->value & SDL_HAT_DOWN) {
key |= 1 << GBA_KEY_DOWN;
}
if (event->value & SDL_HAT_RIGHT) {
key |= 1 << GBA_KEY_RIGHT;
}
context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT));
context->activeKeys |= key;
}
static void _mSDLHandleJoyAxisGBA(struct GBAThread* context, struct mSDLPlayer* sdlContext, const struct SDL_JoyAxisEvent* event) {
int keys = context->activeKeys;
keys = mInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, keys);
enum GBAKey key = mInputMapAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, event->value);
if (key != -1) {
keys |= 1 << key;
}
context->activeKeys = keys;
}
static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) {
int key = -1;
if (!event->keysym.mod) {
@ -681,33 +527,6 @@ static void _mSDLHandleWindowEvent(struct mSDLPlayer* sdlContext, const struct S
}
#endif
void mSDLHandleEventGBA(struct GBAThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event) {
switch (event->type) {
case SDL_QUIT:
GBAThreadEnd(context);
break;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_WINDOWEVENT:
_mSDLHandleWindowEvent(sdlContext, &event->window);
break;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
_mSDLHandleKeypressGBA(context, sdlContext, &event->key);
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
_mSDLHandleJoyButtonGBA(context, sdlContext, &event->jbutton);
break;
case SDL_JOYHATMOTION:
_mSDLHandleJoyHatGBA(context, &event->jhat);
break;
case SDL_JOYAXISMOTION:
_mSDLHandleJoyAxisGBA(context, sdlContext, &event->jaxis);
break;
}
}
void mSDLHandleEvent(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event) {
switch (event->type) {
case SDL_QUIT:

View File

@ -93,9 +93,7 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events);
void mSDLPlayerLoadConfig(struct mSDLPlayer*, const struct Configuration*);
void mSDLPlayerSaveConfig(const struct mSDLPlayer*, struct Configuration*);
struct GBAThread;
void mSDLInitBindingsGBA(struct mInputMap* inputMap);
void mSDLHandleEventGBA(struct GBAThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event);
struct mCoreThread;
void mSDLHandleEvent(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event);