mirror of https://github.com/mgba-emu/mgba.git
Core: Add callbacks
This commit is contained in:
parent
9756f79f04
commit
8d89fb78ba
|
@ -64,6 +64,7 @@ struct mCore {
|
||||||
void (*setAudioBufferSize)(struct mCore*, size_t samples);
|
void (*setAudioBufferSize)(struct mCore*, size_t samples);
|
||||||
size_t (*getAudioBufferSize)(struct mCore*);
|
size_t (*getAudioBufferSize)(struct mCore*);
|
||||||
|
|
||||||
|
void (*setCoreCallbacks)(struct mCore*, struct mCoreCallbacks*);
|
||||||
void (*setAVStream)(struct mCore*, struct mAVStream*);
|
void (*setAVStream)(struct mCore*, struct mAVStream*);
|
||||||
|
|
||||||
bool (*isROM)(struct VFile* vf);
|
bool (*isROM)(struct VFile* vf);
|
||||||
|
|
|
@ -20,6 +20,13 @@ typedef uint32_t color_t;
|
||||||
|
|
||||||
struct blip_t;
|
struct blip_t;
|
||||||
|
|
||||||
|
struct mCoreCallbacks {
|
||||||
|
void* context;
|
||||||
|
void (*videoFrameStarted)(void* context);
|
||||||
|
void (*videoFrameEnded)(void* context);
|
||||||
|
void (*coreCrashed)(void* context);
|
||||||
|
};
|
||||||
|
|
||||||
struct mAVStream {
|
struct mAVStream {
|
||||||
void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height);
|
void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height);
|
||||||
void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride);
|
void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride);
|
||||||
|
|
|
@ -85,6 +85,40 @@ static void _pauseThread(struct mCoreThread* threadContext) {
|
||||||
_waitUntilNotState(threadContext, THREAD_PAUSING);
|
_waitUntilNotState(threadContext, THREAD_PAUSING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _frameStarted(void* context) {
|
||||||
|
struct mCoreThread* thread = context;
|
||||||
|
if (!thread) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) {
|
||||||
|
if (thread->state != THREAD_REWINDING) {
|
||||||
|
mCoreRewindAppend(&thread->rewind, thread->core);
|
||||||
|
} else if (thread->state == THREAD_REWINDING) {
|
||||||
|
if (!mCoreRewindRestore(&thread->rewind, thread->core)) {
|
||||||
|
mCoreRewindAppend(&thread->rewind, thread->core);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _frameEnded(void* context) {
|
||||||
|
struct mCoreThread* thread = context;
|
||||||
|
if (!thread) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (thread->frameCallback) {
|
||||||
|
thread->frameCallback(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _crashed(void* context) {
|
||||||
|
struct mCoreThread* thread = context;
|
||||||
|
if (!thread) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_changeState(thread, THREAD_CRASHED, true);
|
||||||
|
}
|
||||||
|
|
||||||
static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
||||||
struct mCoreThread* threadContext = context;
|
struct mCoreThread* threadContext = context;
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
|
@ -104,6 +138,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct mCore* core = threadContext->core;
|
struct mCore* core = threadContext->core;
|
||||||
|
struct mCoreCallbacks callbacks = {
|
||||||
|
.videoFrameStarted = _frameStarted,
|
||||||
|
.videoFrameEnded = _frameEnded,
|
||||||
|
.coreCrashed = _crashed,
|
||||||
|
.context = threadContext
|
||||||
|
};
|
||||||
|
core->setCoreCallbacks(core, &callbacks);
|
||||||
core->setSync(core, &threadContext->sync);
|
core->setSync(core, &threadContext->sync);
|
||||||
core->reset(core);
|
core->reset(core);
|
||||||
|
|
||||||
|
@ -179,6 +220,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
||||||
if (threadContext->cleanCallback) {
|
if (threadContext->cleanCallback) {
|
||||||
threadContext->cleanCallback(threadContext);
|
threadContext->cleanCallback(threadContext);
|
||||||
}
|
}
|
||||||
|
core->setCoreCallbacks(core, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -483,43 +525,10 @@ struct mCoreThread* mCoreThreadGet(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void mCoreThreadFrameStarted(struct mCoreThread* thread) {
|
|
||||||
if (!thread) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) {
|
|
||||||
if (thread->state != THREAD_REWINDING) {
|
|
||||||
mCoreRewindAppend(&thread->rewind, thread->core);
|
|
||||||
} else if (thread->state == THREAD_REWINDING) {
|
|
||||||
if (!mCoreRewindRestore(&thread->rewind, thread->core)) {
|
|
||||||
mCoreRewindAppend(&thread->rewind, thread->core);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mCoreThreadFrameEnded(struct mCoreThread* thread) {
|
|
||||||
if (!thread) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (thread->frameCallback) {
|
|
||||||
thread->frameCallback(thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
struct mCoreThread* mCoreThreadGet(void) {
|
struct mCoreThread* mCoreThreadGet(void) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mCoreThreadFrameStarted(struct mCoreThread* thread) {
|
|
||||||
UNUSED(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mCoreThreadFrameEnded(struct mCoreThread* thread) {
|
|
||||||
UNUSED(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
@ -95,10 +95,6 @@ void mCoreThreadStopWaiting(struct mCoreThread* threadContext);
|
||||||
void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool);
|
void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool);
|
||||||
|
|
||||||
struct mCoreThread* mCoreThreadGet(void);
|
struct mCoreThread* mCoreThreadGet(void);
|
||||||
|
|
||||||
void mCoreThreadFrameStarted(struct mCoreThread*);
|
|
||||||
void mCoreThreadFrameEnded(struct mCoreThread*);
|
|
||||||
|
|
||||||
struct mLogger* mCoreThreadLogger(void);
|
struct mLogger* mCoreThreadLogger(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -153,6 +153,11 @@ static size_t _GBCoreGetAudioBufferSize(struct mCore* core) {
|
||||||
return gb->audio.samples;
|
return gb->audio.samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _GBCoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
|
||||||
|
struct GB* gb = core->board;
|
||||||
|
gb->coreCallbacks = coreCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
||||||
struct GB* gb = core->board;
|
struct GB* gb = core->board;
|
||||||
gb->stream = stream;
|
gb->stream = stream;
|
||||||
|
@ -534,6 +539,7 @@ struct mCore* GBCoreCreate(void) {
|
||||||
core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
|
core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
|
||||||
core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
|
core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
|
||||||
core->setAVStream = _GBCoreSetAVStream;
|
core->setAVStream = _GBCoreSetAVStream;
|
||||||
|
core->setCoreCallbacks = _GBCoreSetCoreCallbacks;
|
||||||
core->isROM = GBIsROM;
|
core->isROM = GBIsROM;
|
||||||
core->loadROM = _GBCoreLoadROM;
|
core->loadROM = _GBCoreLoadROM;
|
||||||
core->loadBIOS = _GBCoreLoadBIOS;
|
core->loadBIOS = _GBCoreLoadBIOS;
|
||||||
|
|
|
@ -76,6 +76,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) {
|
||||||
gb->pristineRomSize = 0;
|
gb->pristineRomSize = 0;
|
||||||
gb->yankedRomSize = 0;
|
gb->yankedRomSize = 0;
|
||||||
|
|
||||||
|
gb->coreCallbacks = NULL;
|
||||||
gb->stream = NULL;
|
gb->stream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ enum GBIRQVector {
|
||||||
|
|
||||||
struct mCoreSync;
|
struct mCoreSync;
|
||||||
struct mAVStream;
|
struct mAVStream;
|
||||||
|
struct mCoreCallbacks;
|
||||||
struct GB {
|
struct GB {
|
||||||
struct mCPUComponent d;
|
struct mCPUComponent d;
|
||||||
|
|
||||||
|
@ -72,6 +73,7 @@ struct GB {
|
||||||
int32_t sramDirtAge;
|
int32_t sramDirtAge;
|
||||||
bool sramMaskWriteback;
|
bool sramMaskWriteback;
|
||||||
|
|
||||||
|
struct mCoreCallbacks* coreCallbacks;
|
||||||
struct mAVStream* stream;
|
struct mAVStream* stream;
|
||||||
|
|
||||||
int32_t eiPending;
|
int32_t eiPending;
|
||||||
|
|
|
@ -133,8 +133,10 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
||||||
}
|
}
|
||||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK);
|
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK);
|
||||||
|
|
||||||
struct mCoreThread* thread = mCoreThreadGet();
|
struct mCoreCallbacks* callbacks = video->p->coreCallbacks;
|
||||||
mCoreThreadFrameEnded(thread);
|
if (callbacks && callbacks->videoFrameEnded) {
|
||||||
|
callbacks->videoFrameEnded(callbacks->context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) {
|
if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) {
|
||||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||||
|
@ -220,8 +222,10 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
||||||
video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels);
|
video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels);
|
||||||
video->p->stream->postVideoFrame(video->p->stream, pixels, stride);
|
video->p->stream->postVideoFrame(video->p->stream, pixels, stride);
|
||||||
}
|
}
|
||||||
struct mCoreThread* thread = mCoreThreadGet();
|
struct mCoreCallbacks* callbacks = video->p->coreCallbacks;
|
||||||
mCoreThreadFrameStarted(thread);
|
if (callbacks && callbacks->videoFrameStarted) {
|
||||||
|
callbacks->videoFrameStarted(callbacks->context);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
video->nextFrame = 4 - ((video->p->cpu->executionState + 1) & 3);
|
video->nextFrame = 4 - ((video->p->cpu->executionState + 1) & 3);
|
||||||
if (video->nextFrame < video->nextEvent) {
|
if (video->nextFrame < video->nextEvent) {
|
||||||
|
|
|
@ -184,6 +184,11 @@ static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
|
||||||
return gba->audio.samples;
|
return gba->audio.samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _GBACoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
|
||||||
|
struct GBA* gba = core->board;
|
||||||
|
gba->coreCallbacks = coreCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
||||||
struct GBA* gba = core->board;
|
struct GBA* gba = core->board;
|
||||||
gba->stream = stream;
|
gba->stream = stream;
|
||||||
|
@ -550,6 +555,7 @@ struct mCore* GBACoreCreate(void) {
|
||||||
core->getAudioChannel = _GBACoreGetAudioChannel;
|
core->getAudioChannel = _GBACoreGetAudioChannel;
|
||||||
core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
|
core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
|
||||||
core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
|
core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
|
||||||
|
core->setCoreCallbacks = _GBACoreSetCoreCallbacks;
|
||||||
core->setAVStream = _GBACoreSetAVStream;
|
core->setAVStream = _GBACoreSetAVStream;
|
||||||
core->isROM = GBAIsROM;
|
core->isROM = GBAIsROM;
|
||||||
core->loadROM = _GBACoreLoadROM;
|
core->loadROM = _GBACoreLoadROM;
|
||||||
|
|
|
@ -94,9 +94,11 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
|
||||||
gba->romVf = 0;
|
gba->romVf = 0;
|
||||||
gba->biosVf = 0;
|
gba->biosVf = 0;
|
||||||
|
|
||||||
gba->stream = 0;
|
gba->stream = NULL;
|
||||||
gba->keyCallback = 0;
|
gba->keyCallback = NULL;
|
||||||
gba->stopCallback = 0;
|
gba->stopCallback = NULL;
|
||||||
|
gba->stopCallback = NULL;
|
||||||
|
gba->coreCallbacks = NULL;
|
||||||
|
|
||||||
gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
|
gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
|
||||||
|
|
||||||
|
@ -854,8 +856,10 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) {
|
||||||
void GBAFrameStarted(struct GBA* gba) {
|
void GBAFrameStarted(struct GBA* gba) {
|
||||||
UNUSED(gba);
|
UNUSED(gba);
|
||||||
|
|
||||||
struct mCoreThread* thread = mCoreThreadGet();
|
struct mCoreCallbacks* callbacks = gba->coreCallbacks;
|
||||||
mCoreThreadFrameStarted(thread);
|
if (callbacks && callbacks->videoFrameStarted) {
|
||||||
|
callbacks->videoFrameStarted(callbacks->context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAFrameEnded(struct GBA* gba) {
|
void GBAFrameEnded(struct GBA* gba) {
|
||||||
|
@ -885,10 +889,10 @@ void GBAFrameEnded(struct GBA* gba) {
|
||||||
GBAHardwarePlayerUpdate(gba);
|
GBAHardwarePlayerUpdate(gba);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mCoreThread* thread = mCoreThreadGet();
|
struct mCoreCallbacks* callbacks = gba->coreCallbacks;
|
||||||
mCoreThreadFrameEnded(thread);
|
if (callbacks && callbacks->videoFrameEnded) {
|
||||||
|
callbacks->videoFrameEnded(callbacks->context);
|
||||||
// TODO: Put back RR
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
|
void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
|
||||||
|
|
|
@ -112,6 +112,7 @@ struct GBA {
|
||||||
struct mAVStream* stream;
|
struct mAVStream* stream;
|
||||||
struct mKeyCallback* keyCallback;
|
struct mKeyCallback* keyCallback;
|
||||||
struct mStopCallback* stopCallback;
|
struct mStopCallback* stopCallback;
|
||||||
|
struct mCoreCallbacks* coreCallbacks;
|
||||||
|
|
||||||
enum GBAIdleLoopOptimization idleOptimization;
|
enum GBAIdleLoopOptimization idleOptimization;
|
||||||
uint32_t idleLoop;
|
uint32_t idleLoop;
|
||||||
|
|
|
@ -310,6 +310,9 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
||||||
cpu->memory.activeMask = 0;
|
cpu->memory.activeMask = 0;
|
||||||
if (gba->yankedRomSize || !gba->hardCrash) {
|
if (gba->yankedRomSize || !gba->hardCrash) {
|
||||||
mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address);
|
mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address);
|
||||||
|
} else if (gba->coreCallbacks && gba->coreCallbacks->coreCrashed) {
|
||||||
|
mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address);
|
||||||
|
gba->coreCallbacks->coreCrashed(gba->coreCallbacks->context);
|
||||||
} else {
|
} else {
|
||||||
mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address);
|
mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue