diff --git a/CHANGES b/CHANGES index 2559db215..a14b55548 100644 --- a/CHANGES +++ b/CHANGES @@ -68,6 +68,7 @@ Misc: - Util: Add 8-bit PNG write support - Qt: Rename "Resample video" option to "Bilinear filtering" - GBA Video: Optimize when BLD* registers are written frequently + - Core: Cores can now have multiple sets of callbacks 0.5.2: (2016-12-31) Bugfixes: diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 06c7a7184..980322ebd 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -73,7 +73,8 @@ struct mCore { void (*setAudioBufferSize)(struct mCore*, size_t samples); size_t (*getAudioBufferSize)(struct mCore*); - void (*setCoreCallbacks)(struct mCore*, struct mCoreCallbacks*); + void (*addCoreCallbacks)(struct mCore*, struct mCoreCallbacks*); + void (*clearCoreCallbacks)(struct mCore*); void (*setAVStream)(struct mCore*, struct mAVStream*); bool (*isROM)(struct VFile* vf); diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index 2e78390cf..40eb099d6 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -10,6 +10,8 @@ CXX_GUARD_START +#include + struct mCore; #ifdef COLOR_16_BIT @@ -37,6 +39,8 @@ struct mCoreCallbacks { void (*coreCrashed)(void* context); }; +DECLARE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks); + struct mAVStream { void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height); void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride); diff --git a/include/mgba/internal/gb/gb.h b/include/mgba/internal/gb/gb.h index db3adf6cc..05362c7bd 100644 --- a/include/mgba/internal/gb/gb.h +++ b/include/mgba/internal/gb/gb.h @@ -11,6 +11,7 @@ CXX_GUARD_START #include +#include #include #include @@ -46,7 +47,6 @@ enum GBIRQVector { struct LR35902Core; struct mCoreSync; struct mAVStream; -struct mCoreCallbacks; struct GB { struct mCPUComponent d; @@ -76,7 +76,7 @@ struct GB { int32_t sramDirtAge; bool sramMaskWriteback; - struct mCoreCallbacks* coreCallbacks; + struct mCoreCallbacksList coreCallbacks; struct mAVStream* stream; bool cpuBlocked; diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index e27f6cbc0..e5b1f8899 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -100,7 +100,7 @@ struct GBA { struct mAVStream* stream; struct mKeyCallback* keyCallback; struct mStopCallback* stopCallback; - struct mCoreCallbacks* coreCallbacks; + struct mCoreCallbacksList coreCallbacks; enum GBAIdleLoopOptimization idleOptimization; uint32_t idleLoop; diff --git a/src/core/interface.c b/src/core/interface.c index 5317da562..75e171b3d 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -7,6 +7,8 @@ #include +DEFINE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks); + static time_t _rtcGenericCallback(struct mRTCSource* source) { struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; switch (rtc->override) { diff --git a/src/core/thread.c b/src/core/thread.c index 3ffa7c477..3ed5aeb1c 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -143,7 +143,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { .coreCrashed = _crashed, .context = threadContext }; - core->setCoreCallbacks(core, &callbacks); + core->addCoreCallbacks(core, &callbacks); core->setSync(core, &threadContext->sync); core->reset(core); @@ -223,7 +223,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { if (threadContext->cleanCallback) { threadContext->cleanCallback(threadContext); } - core->setCoreCallbacks(core, NULL); + core->clearCoreCallbacks(core); return 0; } diff --git a/src/gb/core.c b/src/gb/core.c index df64296c9..87ad3558a 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -156,9 +156,14 @@ static size_t _GBCoreGetAudioBufferSize(struct mCore* core) { return gb->audio.samples; } -static void _GBCoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { +static void _GBCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { struct GB* gb = core->board; - gb->coreCallbacks = coreCallbacks; + *mCoreCallbacksListAppend(&gb->coreCallbacks) = *coreCallbacks; +} + +static void _GBCoreClearCoreCallbacks(struct mCore* core) { + struct GB* gb = core->board; + mCoreCallbacksListClear(&gb->coreCallbacks); } static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { @@ -576,7 +581,8 @@ struct mCore* GBCoreCreate(void) { core->setAudioBufferSize = _GBCoreSetAudioBufferSize; core->getAudioBufferSize = _GBCoreGetAudioBufferSize; core->setAVStream = _GBCoreSetAVStream; - core->setCoreCallbacks = _GBCoreSetCoreCallbacks; + core->addCoreCallbacks = _GBCoreAddCoreCallbacks; + core->clearCoreCallbacks = _GBCoreClearCoreCallbacks; core->isROM = GBIsROM; core->loadROM = _GBCoreLoadROM; core->loadBIOS = _GBCoreLoadBIOS; diff --git a/src/gb/gb.c b/src/gb/gb.c index aee05205c..e664e02b8 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -83,7 +83,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) { gb->pristineRomSize = 0; gb->yankedRomSize = 0; - gb->coreCallbacks = NULL; + mCoreCallbacksListInit(&gb->coreCallbacks, 0); gb->stream = NULL; mTimingInit(&gb->timing, &gb->cpu->cycles, &gb->cpu->nextEvent); @@ -349,6 +349,7 @@ void GBDestroy(struct GB* gb) { GBAudioDeinit(&gb->audio); GBVideoDeinit(&gb->video); GBSIODeinit(&gb->sio); + mCoreCallbacksListDeinit(&gb->coreCallbacks); } void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) { diff --git a/src/gb/video.c b/src/gb/video.c index 27287959a..fda0f6111 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -129,9 +129,12 @@ void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) { } video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK); - struct mCoreCallbacks* callbacks = video->p->coreCallbacks; - if (callbacks && callbacks->videoFrameEnded) { - callbacks->videoFrameEnded(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } } } if (!GBRegisterSTATIsHblankIRQ(video->stat) && GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) { @@ -244,9 +247,12 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat video->p->stream->postVideoFrame(video->p->stream, pixels, stride); } - struct mCoreCallbacks* callbacks = video->p->coreCallbacks; - if (callbacks && callbacks->videoFrameStarted) { - callbacks->videoFrameStarted(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameStarted(callbacks->context); + } } if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC])) { diff --git a/src/gba/core.c b/src/gba/core.c index 1c6002fbe..c7483bed0 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -186,9 +186,14 @@ static size_t _GBACoreGetAudioBufferSize(struct mCore* core) { return gba->audio.samples; } -static void _GBACoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { +static void _GBACoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { struct GBA* gba = core->board; - gba->coreCallbacks = coreCallbacks; + *mCoreCallbacksListAppend(&gba->coreCallbacks) = *coreCallbacks; +} + +static void _GBACoreClearCoreCallbacks(struct mCore* core) { + struct GBA* gba = core->board; + mCoreCallbacksListClear(&gba->coreCallbacks); } static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { @@ -589,7 +594,8 @@ struct mCore* GBACoreCreate(void) { core->getAudioChannel = _GBACoreGetAudioChannel; core->setAudioBufferSize = _GBACoreSetAudioBufferSize; core->getAudioBufferSize = _GBACoreGetAudioBufferSize; - core->setCoreCallbacks = _GBACoreSetCoreCallbacks; + core->addCoreCallbacks = _GBACoreAddCoreCallbacks; + core->clearCoreCallbacks = _GBACoreClearCoreCallbacks; core->setAVStream = _GBACoreSetAVStream; core->isROM = GBAIsROM; core->loadROM = _GBACoreLoadROM; diff --git a/src/gba/gba.c b/src/gba/gba.c index 22dafd89a..49c96bd2d 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -91,7 +91,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->keyCallback = NULL; gba->stopCallback = NULL; gba->stopCallback = NULL; - gba->coreCallbacks = NULL; + mCoreCallbacksListInit(&gba->coreCallbacks, 0); gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); @@ -152,6 +152,7 @@ void GBADestroy(struct GBA* gba) { GBASIODeinit(&gba->sio); gba->rr = 0; mTimingDeinit(&gba->timing); + mCoreCallbacksListDeinit(&gba->coreCallbacks); } void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh) { @@ -632,9 +633,12 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) { void GBAFrameStarted(struct GBA* gba) { UNUSED(gba); - struct mCoreCallbacks* callbacks = gba->coreCallbacks; - if (callbacks && callbacks->videoFrameStarted) { - callbacks->videoFrameStarted(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameStarted(callbacks->context); + } } } @@ -665,9 +669,12 @@ void GBAFrameEnded(struct GBA* gba) { GBAHardwarePlayerUpdate(gba); } - struct mCoreCallbacks* callbacks = gba->coreCallbacks; - if (callbacks && callbacks->videoFrameEnded) { - callbacks->videoFrameEnded(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } } } diff --git a/src/gba/memory.c b/src/gba/memory.c index eb4316569..5c2c14511 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -303,9 +303,15 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { cpu->memory.activeMask = 0; if (gba->yankedRomSize || !gba->hardCrash) { mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); - } else if (gba->coreCallbacks && gba->coreCallbacks->coreCrashed) { + } else if (mCoreCallbacksListSize(&gba->coreCallbacks)) { mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); - gba->coreCallbacks->coreCrashed(gba->coreCallbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); + if (callbacks->coreCrashed) { + callbacks->coreCrashed(callbacks->context); + } + } } else { mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address); }