all repos — mgba @ ba6e34fd9039abb2a015e20449a3d47fa6b6f986

mGBA Game Boy Advance Emulator

Libretro: Defer loading save so RTC loading actually works (fixes #1959)
Vicki Pfau vi@endrift.com
Wed, 02 Dec 2020 00:13:09 -0800
commit

ba6e34fd9039abb2a015e20449a3d47fa6b6f986

parent

63921e025e4075684ce2f9b81143c123ec7b9fd3

1 files changed, 79 insertions(+), 18 deletions(-)

jump to
M src/platform/libretro/libretro.csrc/platform/libretro/libretro.c

@@ -70,6 +70,7 @@ static unsigned camHeight;

static unsigned imcapWidth; static unsigned imcapHeight; static size_t camStride; +static bool deferredSetup = false; static void _reloadSettings(void) { struct mCoreOptions opts = {

@@ -152,6 +153,18 @@ #endif

mCoreConfigLoadDefaults(&core->config, &opts); mCoreLoadConfig(core); +} + +static void _doDeferredSetup(void) { + // Libretro API doesn't let you know when it's done copying data into the save buffers. + // On the off-hand chance that a core actually expects its buffers to be populated when + // you actually first get them, you're out of luck without workarounds. Yup, seriously. + // Here's that workaround, but really the API needs to be thrown out and rewritten. + struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); + if (!core->loadSave(core, save)) { + save->close(save); + } + deferredSetup = false; } unsigned retro_api_version(void) {

@@ -288,6 +301,9 @@ free(outputBuffer);

} void retro_run(void) { + if (deferredSetup) { + _doDeferredSetup(); + } uint16_t keys; inputPollCallback();

@@ -588,11 +604,10 @@ core->setPeripheral(core, mPERIPH_RUMBLE, &rumble);

savedata = anonymousMemoryMap(SIZE_CART_FLASH1M); memset(savedata, 0xFF, SIZE_CART_FLASH1M); - struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); _reloadSettings(); core->loadROM(core, rom); - core->loadSave(core, save); + deferredSetup = true; const char* sysDir = 0; const char* biosName = 0;

@@ -670,6 +685,9 @@ savedata = 0;

} size_t retro_serialize_size(void) { + if (deferredSetup) { + _doDeferredSetup(); + } struct VFile* vfm = VFileMemChunk(NULL, 0); mCoreSaveStateNamed(core, vfm, SAVESTATE_SAVEDATA | SAVESTATE_RTC); size_t size = vfm->size(vfm);

@@ -678,6 +696,9 @@ return size;

} bool retro_serialize(void* data, size_t size) { + if (deferredSetup) { + _doDeferredSetup(); + } struct VFile* vfm = VFileMemChunk(NULL, 0); mCoreSaveStateNamed(core, vfm, SAVESTATE_SAVEDATA | SAVESTATE_RTC); if ((ssize_t) size > vfm->size(vfm)) {

@@ -693,6 +714,9 @@ return true;

} bool retro_unserialize(const void* data, size_t size) { + if (deferredSetup) { + _doDeferredSetup(); + } struct VFile* vfm = VFileFromConstMemory(data, size); bool success = mCoreLoadStateNamed(core, vfm, SAVESTATE_RTC); vfm->close(vfm);

@@ -777,31 +801,68 @@ return false;

} void* retro_get_memory_data(unsigned id) { - if (id != RETRO_MEMORY_SAVE_RAM) { - return 0; + switch (id) { + case RETRO_MEMORY_SAVE_RAM: + return savedata; + case RETRO_MEMORY_RTC: + switch (core->platform(core)) { +#ifdef M_CORE_GB + case PLATFORM_GB: + switch (((struct GB*) core->board)->memory.mbcType) { + case GB_MBC3_RTC: + return &((uint8_t*) savedata)[((struct GB*) core->board)->sramSize]; + default: + return NULL; + } +#endif + default: + return NULL; + } + default: + break; } - return savedata; + return NULL; } size_t retro_get_memory_size(unsigned id) { - if (id != RETRO_MEMORY_SAVE_RAM) { - return 0; - } + switch (id) { + case RETRO_MEMORY_SAVE_RAM: + switch (core->platform(core)) { #ifdef M_CORE_GBA - if (core->platform(core) == PLATFORM_GBA) { - switch (((struct GBA*) core->board)->memory.savedata.type) { - case SAVEDATA_AUTODETECT: - return SIZE_CART_FLASH1M; + case PLATFORM_GBA: + switch (((struct GBA*) core->board)->memory.savedata.type) { + case SAVEDATA_AUTODETECT: + return SIZE_CART_FLASH1M; + default: + return GBASavedataSize(&((struct GBA*) core->board)->memory.savedata); + } +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + return ((struct GB*) core->board)->sramSize; +#endif default: - return GBASavedataSize(&((struct GBA*) core->board)->memory.savedata); + break; } - } -#endif + break; + case RETRO_MEMORY_RTC: + switch (core->platform(core)) { #ifdef M_CORE_GB - if (core->platform(core) == PLATFORM_GB) { - return ((struct GB*) core->board)->sramSize; - } + case PLATFORM_GB: + switch (((struct GB*) core->board)->memory.mbcType) { + case GB_MBC3_RTC: + return sizeof(struct GBMBCRTCSaveBuffer); + default: + return 0; + } #endif + default: + break; + } + break; + default: + break; + } return 0; }