mirror of https://github.com/mgba-emu/mgba.git
Core: Revise how savegame loading works
This commit is contained in:
parent
d746a33338
commit
e2807b3915
|
@ -126,7 +126,7 @@ void (*busWrite16)(struct mCore*, uint32_t address, uint16_t);
|
|||
struct mCheatDevice* (*cheatDevice)(struct mCore*);
|
||||
|
||||
size_t (*savedataClone)(struct mCore*, void** sram);
|
||||
bool (*savedataLoad)(struct mCore*, const void* sram, size_t size);
|
||||
bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback);
|
||||
};
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
|
|
|
@ -407,10 +407,10 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) {
|
|||
mLOG(SAVESTATE, WARN, "Savestate includes invalid screenshot");
|
||||
}
|
||||
}
|
||||
if (flags & SAVESTATE_SAVEDATA && mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) {
|
||||
if (mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) {
|
||||
mLOG(SAVESTATE, INFO, "Loading savedata");
|
||||
if (item.data) {
|
||||
core->savedataLoad(core, item.data, item.size);
|
||||
core->savedataRestore(core, item.data, item.size, flags & SAVESTATE_SAVEDATA);
|
||||
}
|
||||
}
|
||||
struct mCheatDevice* device;
|
||||
|
|
|
@ -424,7 +424,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
runner->core->reset(runner->core);
|
||||
break;
|
||||
case RUNNER_SAVE_STATE:
|
||||
mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT);
|
||||
mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEGAME);
|
||||
break;
|
||||
case RUNNER_LOAD_STATE:
|
||||
mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT);
|
||||
|
|
|
@ -177,7 +177,7 @@ static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) {
|
|||
|
||||
static bool _GBCoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
|
||||
struct GB* gb = core->board;
|
||||
GBSavedataMask(gb, vf);
|
||||
GBSavedataMask(gb, vf, false);
|
||||
return true; // TODO: Return a real value
|
||||
}
|
||||
|
||||
|
@ -484,8 +484,13 @@ static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) {
|
|||
return gb->sramSize;
|
||||
}
|
||||
|
||||
static bool _GBCoreSavedataLoad(struct mCore* core, const void* sram, size_t size) {
|
||||
static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
|
||||
struct GB* gb = core->board;
|
||||
if (!writeback) {
|
||||
struct VFile* vf = VFileFromConstMemory(sram, size);
|
||||
GBSavedataMask(gb, vf, true);
|
||||
return true;
|
||||
}
|
||||
struct VFile* vf = gb->sramVf;
|
||||
if (vf) {
|
||||
vf->seek(vf, 0, SEEK_SET);
|
||||
|
@ -563,6 +568,6 @@ struct mCore* GBCoreCreate(void) {
|
|||
core->detachDebugger = _GBCoreDetachDebugger;
|
||||
core->cheatDevice = _GBCoreCheatDevice;
|
||||
core->savedataClone = _GBCoreSavedataClone;
|
||||
core->savedataLoad = _GBCoreSavedataLoad;
|
||||
core->savedataRestore = _GBCoreSavedataRestore;
|
||||
return core;
|
||||
}
|
||||
|
|
15
src/gb/gb.c
15
src/gb/gb.c
|
@ -118,8 +118,7 @@ static void GBSramDeinit(struct GB* gb) {
|
|||
if (gb->memory.mbcType == GB_MBC3_RTC) {
|
||||
GBMBCRTCWrite(gb);
|
||||
}
|
||||
gb->sramVf->close(gb->sramVf);
|
||||
gb->sramVf = 0;
|
||||
gb->sramVf = NULL;
|
||||
} else if (gb->memory.sram) {
|
||||
mappedMemoryFree(gb->memory.sram, gb->sramSize);
|
||||
}
|
||||
|
@ -210,9 +209,10 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) {
|
|||
}
|
||||
}
|
||||
|
||||
void GBSavedataMask(struct GB* gb, struct VFile* vf) {
|
||||
void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback) {
|
||||
GBSramDeinit(gb);
|
||||
gb->sramVf = vf;
|
||||
gb->sramMaskWriteback = writeback;
|
||||
gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ);
|
||||
}
|
||||
|
||||
|
@ -220,9 +220,14 @@ void GBSavedataUnmask(struct GB* gb) {
|
|||
if (gb->sramVf == gb->sramRealVf) {
|
||||
return;
|
||||
}
|
||||
struct VFile* vf = gb->sramVf;
|
||||
GBSramDeinit(gb);
|
||||
gb->sramVf = gb->sramRealVf;
|
||||
gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE);
|
||||
if (gb->sramMaskWriteback) {
|
||||
vf->read(vf, gb->memory.sram, gb->sramSize);
|
||||
}
|
||||
vf->close(vf);
|
||||
}
|
||||
|
||||
void GBUnloadROM(struct GB* gb) {
|
||||
|
@ -247,7 +252,11 @@ void GBUnloadROM(struct GB* gb) {
|
|||
gb->romVf = 0;
|
||||
}
|
||||
|
||||
struct VFile* vf = gb->sramVf;
|
||||
GBSramDeinit(gb);
|
||||
if (vf) {
|
||||
vf->close(vf);
|
||||
}
|
||||
}
|
||||
|
||||
void GBLoadBIOS(struct GB* gb, struct VFile* vf) {
|
||||
|
|
|
@ -70,6 +70,7 @@ struct GB {
|
|||
uint32_t sramSize;
|
||||
int sramDirty;
|
||||
int32_t sramDirtAge;
|
||||
bool sramMaskWriteback;
|
||||
|
||||
struct mAVStream* stream;
|
||||
|
||||
|
@ -121,7 +122,7 @@ void GBLoadBIOS(struct GB* gb, struct VFile* vf);
|
|||
|
||||
void GBSramClean(struct GB* gb, uint32_t frameCount);
|
||||
void GBResizeSram(struct GB* gb, size_t size);
|
||||
void GBSavedataMask(struct GB* gb, struct VFile* vf);
|
||||
void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback);
|
||||
void GBSavedataUnmask(struct GB* gb);
|
||||
|
||||
struct Patch;
|
||||
|
|
|
@ -211,7 +211,7 @@ static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
|
|||
|
||||
static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
|
||||
struct GBA* gba = core->board;
|
||||
GBASavedataMask(&gba->memory.savedata, vf);
|
||||
GBASavedataMask(&gba->memory.savedata, vf, false);
|
||||
return true; // TODO: Return a real value
|
||||
}
|
||||
|
||||
|
@ -507,14 +507,19 @@ static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
|
|||
return size;
|
||||
}
|
||||
|
||||
static bool _GBACoreSavedataLoad(struct mCore* core, const void* sram, size_t size) {
|
||||
static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
|
||||
struct VFile* vf = VFileFromConstMemory(sram, size);
|
||||
if (!vf) {
|
||||
return false;
|
||||
}
|
||||
struct GBA* gba = core->board;
|
||||
bool success = GBASavedataLoad(&gba->memory.savedata, vf);
|
||||
bool success = true;
|
||||
if (writeback) {
|
||||
success = GBASavedataLoad(&gba->memory.savedata, vf);
|
||||
vf->close(vf);
|
||||
} else {
|
||||
GBASavedataMask(&gba->memory.savedata, vf, true);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -582,6 +587,6 @@ struct mCore* GBACoreCreate(void) {
|
|||
core->detachDebugger = _GBACoreDetachDebugger;
|
||||
core->cheatDevice = _GBACoreCheatDevice;
|
||||
core->savedataClone = _GBACoreSavedataClone;
|
||||
core->savedataLoad = _GBACoreSavedataLoad;
|
||||
core->savedataRestore = _GBACoreSavedataRestore;
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ void GBAMemoryDeinit(struct GBA* gba) {
|
|||
if (gba->memory.rom) {
|
||||
mappedMemoryFree(gba->memory.rom, gba->memory.romSize);
|
||||
}
|
||||
GBASavedataUnmask(&gba->memory.savedata);
|
||||
GBASavedataDeinit(&gba->memory.savedata);
|
||||
if (gba->memory.savedata.realVf) {
|
||||
gba->memory.savedata.realVf->close(gba->memory.savedata.realVf);
|
||||
|
|
|
@ -23,9 +23,9 @@ void GBARRInitRecord(struct GBA* gba) {
|
|||
GBASavedataClone(&gba->memory.savedata, gba->rr->savedata);
|
||||
gba->rr->savedata->close(gba->rr->savedata);
|
||||
gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_RDONLY);
|
||||
GBASavedataMask(&gba->memory.savedata, gba->rr->savedata);
|
||||
GBASavedataMask(&gba->memory.savedata, gba->rr->savedata, false);
|
||||
} else {
|
||||
GBASavedataMask(&gba->memory.savedata, 0);
|
||||
GBASavedataMask(&gba->memory.savedata, 0, false);
|
||||
}
|
||||
|
||||
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) {
|
||||
|
@ -47,9 +47,9 @@ void GBARRInitPlay(struct GBA* gba) {
|
|||
gba->rr->savedata->close(gba->rr->savedata);
|
||||
}
|
||||
gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_RDONLY);
|
||||
GBASavedataMask(&gba->memory.savedata, gba->rr->savedata);
|
||||
GBASavedataMask(&gba->memory.savedata, gba->rr->savedata, false);
|
||||
} else {
|
||||
GBASavedataMask(&gba->memory.savedata, 0);
|
||||
GBASavedataMask(&gba->memory.savedata, 0, false);
|
||||
}
|
||||
|
||||
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) {
|
||||
|
|
|
@ -47,10 +47,7 @@ void GBASavedataDeinit(struct GBASavedata* savedata) {
|
|||
if (savedata->vf) {
|
||||
size_t size = GBASavedataSize(savedata);
|
||||
savedata->vf->unmap(savedata->vf, savedata->data, size);
|
||||
if (savedata->vf != savedata->realVf) {
|
||||
savedata->vf->close(savedata->vf);
|
||||
}
|
||||
savedata->vf = 0;
|
||||
savedata->vf = NULL;
|
||||
} else {
|
||||
switch (savedata->type) {
|
||||
case SAVEDATA_SRAM:
|
||||
|
@ -74,23 +71,30 @@ void GBASavedataDeinit(struct GBASavedata* savedata) {
|
|||
savedata->type = SAVEDATA_AUTODETECT;
|
||||
}
|
||||
|
||||
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) {
|
||||
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback) {
|
||||
enum SavedataType type = savedata->type;
|
||||
GBASavedataDeinit(savedata);
|
||||
savedata->vf = vf;
|
||||
savedata->mapMode = MAP_READ;
|
||||
savedata->maskWriteback = writeback;
|
||||
GBASavedataForceType(savedata, type, savedata->realisticTiming);
|
||||
}
|
||||
|
||||
void GBASavedataUnmask(struct GBASavedata* savedata) {
|
||||
if (savedata->mapMode != MAP_READ) {
|
||||
if (savedata->vf == savedata->realVf) {
|
||||
return;
|
||||
}
|
||||
enum SavedataType type = savedata->type;
|
||||
struct VFile* vf = savedata->vf;
|
||||
GBASavedataDeinit(savedata);
|
||||
savedata->vf = savedata->realVf;
|
||||
savedata->mapMode = MAP_WRITE;
|
||||
GBASavedataForceType(savedata, type, savedata->realisticTiming);
|
||||
if (savedata->maskWriteback) {
|
||||
GBASavedataLoad(savedata, vf);
|
||||
savedata->maskWriteback = false;
|
||||
}
|
||||
vf->close(vf);
|
||||
}
|
||||
|
||||
bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
|
||||
|
@ -488,6 +492,9 @@ void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
|
|||
savedata->dirty |= SAVEDATA_DIRT_SEEN;
|
||||
}
|
||||
} else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
|
||||
if (savedata->maskWriteback) {
|
||||
GBASavedataUnmask(savedata);
|
||||
}
|
||||
size_t size = GBASavedataSize(savedata);
|
||||
savedata->dirty = 0;
|
||||
if (savedata->data && savedata->vf->sync(savedata->vf, savedata->data, size)) {
|
||||
|
|
|
@ -74,6 +74,7 @@ struct GBASavedata {
|
|||
struct VFile* vf;
|
||||
|
||||
int mapMode;
|
||||
bool maskWriteback;
|
||||
struct VFile* realVf;
|
||||
|
||||
int32_t readBitsRemaining;
|
||||
|
@ -95,7 +96,7 @@ struct GBASavedata {
|
|||
void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf);
|
||||
void GBASavedataDeinit(struct GBASavedata* savedata);
|
||||
|
||||
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf);
|
||||
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback);
|
||||
void GBASavedataUnmask(struct GBASavedata* savedata);
|
||||
size_t GBASavedataSize(struct GBASavedata* savedata);
|
||||
bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out);
|
||||
|
|
|
@ -470,7 +470,7 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer*
|
|||
case SDLK_F8:
|
||||
case SDLK_F9:
|
||||
mCoreThreadInterrupt(context);
|
||||
mCoreSaveState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
|
||||
mCoreSaveState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SAVEDATA | SAVESTATE_SCREENSHOT);
|
||||
mCoreThreadContinue(context);
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue