Core: Refactor savestates
jump to
@@ -108,7 +108,7 @@ struct VFile* vf = mCoreGetState(core, slot, true);
if (!vf) { return false; } - bool success = core->saveState(core, vf, flags); + bool success = mCoreSaveStateNamed(core, vf, flags); vf->close(vf); if (success) { mLOG(STATUS, INFO, "State %i saved", slot);@@ -124,7 +124,7 @@ struct VFile* vf = mCoreGetState(core, slot, false);
if (!vf) { return false; } - bool success = core->loadState(core, vf, flags); + bool success = mCoreLoadStateNamed(core, vf, flags); vf->close(vf); if (success) { mLOG(STATUS, INFO, "State %i loaded", slot);
@@ -31,6 +31,7 @@
struct mRTCSource; struct mCoreConfig; struct mCoreSync; +struct mStateExtdata; struct mCore { void* cpu; void* board;@@ -78,8 +79,9 @@ void (*runFrame)(struct mCore*);
void (*runLoop)(struct mCore*); void (*step)(struct mCore*); - bool (*loadState)(struct mCore*, struct VFile*, int flags); - bool (*saveState)(struct mCore*, struct VFile*, int flags); + size_t (*stateSize)(struct mCore*); + bool (*loadState)(struct mCore*, const void* state); + bool (*saveState)(struct mCore*, void* state); void (*setKeys)(struct mCore*, uint32_t keys); void (*addKeys)(struct mCore*, uint32_t keys);
@@ -5,7 +5,25 @@ * 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 "serialize.h" +#include "core/core.h" +#include "core/cheats.h" +#include "core/sync.h" +#include "util/memory.h" #include "util/vfs.h" + +#ifdef USE_PNG +#include "util/png-io.h" +#include <png.h> +#include <zlib.h> +#endif + +mLOG_DEFINE_CATEGORY(SAVESTATE, "Savestate"); + +struct mBundledState { + size_t stateSize; + void* state; + struct mStateExtdata* extdata; +}; struct mStateExtdataHeader { uint32_t tag;@@ -129,3 +147,296 @@ vf->seek(vf, position, SEEK_SET);
}; return true; } + + + + + + + +#ifdef USE_PNG +static bool _savePNGState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) { + size_t stride; + color_t* pixels = 0; + + core->getVideoBuffer(core, &pixels, &stride); + if (!pixels) { + return false; + } + + size_t stateSize = core->stateSize(core); + void* state = anonymousMemoryMap(stateSize); + if (!state) { + return false; + } + core->saveState(core, state); + + uLongf len = compressBound(stateSize); + void* buffer = malloc(len); + if (!buffer) { + mappedMemoryFree(state, stateSize); + return false; + } + compress(buffer, &len, (const Bytef*) state, stateSize); + mappedMemoryFree(state, stateSize); + + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + png_structp png = PNGWriteOpen(vf); + png_infop info = PNGWriteHeader(png, width, height); + if (!png || !info) { + PNGWriteClose(png, info); + free(buffer); + return false; + } + PNGWritePixels(png, width, height, stride, pixels); + PNGWriteCustomChunk(png, "gbAs", len, buffer); + if (extdata) { + uint32_t i; + for (i = 1; i < EXTDATA_MAX; ++i) { + if (!extdata->data[i].data) { + continue; + } + uLongf len = compressBound(extdata->data[i].size) + sizeof(uint32_t) * 2; + uint32_t* data = malloc(len); + if (!data) { + continue; + } + STORE_32LE(i, 0, data); + STORE_32LE(extdata->data[i].size, sizeof(uint32_t), data); + compress((Bytef*) (data + 2), &len, extdata->data[i].data, extdata->data[i].size); + PNGWriteCustomChunk(png, "gbAx", len + sizeof(uint32_t) * 2, data); + free(data); + } + } + PNGWriteClose(png, info); + free(buffer); + return true; +} + +static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) { + struct mBundledState* bundle = png_get_user_chunk_ptr(png); + if (!bundle) { + return 0; + } + if (!strcmp((const char*) chunk->name, "gbAs")) { + void* state = bundle->state; + if (!state) { + return 0; + } + uLongf len = bundle->stateSize; + uncompress((Bytef*) state, &len, chunk->data, chunk->size); + return 1; + } + if (!strcmp((const char*) chunk->name, "gbAx")) { + struct mStateExtdata* extdata = bundle->extdata; + if (!extdata) { + return 0; + } + struct mStateExtdataItem item; + if (chunk->size < sizeof(uint32_t) * 2) { + return 0; + } + uint32_t tag; + LOAD_32LE(tag, 0, chunk->data); + LOAD_32LE(item.size, sizeof(uint32_t), chunk->data); + uLongf len = item.size; + if (item.size < 0 || tag == EXTDATA_NONE || tag >= EXTDATA_MAX) { + return 0; + } + item.data = malloc(item.size); + item.clean = free; + if (!item.data) { + return 0; + } + const uint8_t* data = chunk->data; + data += sizeof(uint32_t) * 2; + uncompress((Bytef*) item.data, &len, data, chunk->size); + item.size = len; + mStateExtdataPut(extdata, tag, &item); + return 1; + } + return 0; +} + +static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) { + png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES); + png_infop info = png_create_info_struct(png); + png_infop end = png_create_info_struct(png); + if (!png || !info || !end) { + PNGReadClose(png, info, end); + return false; + } + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + uint32_t* pixels = malloc(width * height * 4); + if (!pixels) { + PNGReadClose(png, info, end); + return false; + } + + size_t stateSize = core->stateSize(core); + void* state = anonymousMemoryMap(stateSize); + struct mBundledState bundle = { + .stateSize = stateSize, + .state = state, + .extdata = extdata + }; + + PNGInstallChunkHandler(png, &bundle, _loadPNGChunkHandler, "gbAs gbAx"); + bool success = PNGReadHeader(png, info); + success = success && PNGReadPixels(png, info, pixels, width, height, width); + success = success && PNGReadFooter(png, end); + PNGReadClose(png, info, end); + + if (success) { + struct mStateExtdataItem item = { + .size = width * height * 4, + .data = pixels, + .clean = free + }; + mStateExtdataPut(extdata, EXTDATA_SCREENSHOT, &item); + } else { + free(pixels); + mappedMemoryFree(state, stateSize); + return 0; + } + return state; +} +#endif + +bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { + struct mStateExtdata extdata; + mStateExtdataInit(&extdata); + size_t stateSize = core->stateSize(core); + if (flags & SAVESTATE_SAVEDATA) { + /* // TODO: A better way to do this would be nice + void* sram = malloc(SIZE_CART_FLASH1M); + struct VFile* svf = VFileFromMemory(sram, SIZE_CART_FLASH1M); + if (GBASavedataClone(&gba->memory.savedata, svf)) { + struct mStateExtdataItem item = { + .size = svf->seek(svf, 0, SEEK_CUR), + .data = sram, + .clean = free + }; + mStateExtdataPut(&extdata, EXTDATA_SAVEDATA, &item); + } else { + free(sram); + } + svf->close(svf);*/ + } + struct VFile* cheatVf = 0; + struct mCheatDevice* device; + if (flags & SAVESTATE_CHEATS && (device = core->cheatDevice(core))) { + cheatVf = VFileMemChunk(0, 0); + if (cheatVf) { + mCheatSaveFile(device, cheatVf); + struct mStateExtdataItem item = { + .size = cheatVf->size(cheatVf), + .data = cheatVf->map(cheatVf, cheatVf->size(cheatVf), MAP_READ), + .clean = 0 + }; + mStateExtdataPut(&extdata, EXTDATA_CHEATS, &item); + } + } +#ifdef USE_PNG + if (!(flags & SAVESTATE_SCREENSHOT)) { +#else + UNUSED(flags); +#endif + vf->truncate(vf, stateSize); + struct GBASerializedState* state = vf->map(vf, stateSize, MAP_WRITE); + if (!state) { + mStateExtdataDeinit(&extdata); + if (cheatVf) { + cheatVf->close(cheatVf); + } + return false; + } + core->saveState(core, state); + vf->unmap(vf, state, stateSize); + vf->seek(vf, stateSize, SEEK_SET); + mStateExtdataSerialize(&extdata, vf); + mStateExtdataDeinit(&extdata); + if (cheatVf) { + cheatVf->close(cheatVf); + } + return true; +#ifdef USE_PNG + } + else { + bool success = _savePNGState(core, vf, &extdata); + mStateExtdataDeinit(&extdata); + return success; + } +#endif + mStateExtdataDeinit(&extdata); + return false; +} + +void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) { +#ifdef USE_PNG + if (isPNG(vf)) { + return _loadPNGState(core, vf, extdata); + } +#endif + ssize_t stateSize = core->stateSize(core); + vf->seek(vf, 0, SEEK_SET); + if (vf->size(vf) < stateSize) { + return false; + } + void* state = anonymousMemoryMap(stateSize); + if (vf->read(vf, state, stateSize) != stateSize) { + mappedMemoryFree(state, stateSize); + return 0; + } + if (extdata) { + mStateExtdataDeserialize(extdata, vf); + } + return state; +} + +bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { + struct mStateExtdata extdata; + mStateExtdataInit(&extdata); + void* state = mCoreExtractState(core, vf, &extdata); + if (!state) { + return false; + } + bool success = core->loadState(core, state); + mappedMemoryFree(state, core->stateSize(core)); + + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + + struct mStateExtdataItem item; + if (flags & SAVESTATE_SCREENSHOT && mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item)) { + if (item.size >= (int) (width * height) * 4) { + /*gba->video.renderer->putPixels(gba->video.renderer, width, item.data); + mCoreSyncForceFrame(core->sync);*/ + } else { + mLOG(SAVESTATE, WARN, "Savestate includes invalid screenshot"); + } + } + if (flags & SAVESTATE_SAVEDATA && mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) { + /*struct VFile* svf = VFileFromMemory(item.data, item.size); + GBASavedataLoad(&gba->memory.savedata, svf); + if (svf) { + svf->close(svf); + }*/ + } + struct mCheatDevice* device; + if (flags & SAVESTATE_CHEATS && (device = core->cheatDevice(core)) && mStateExtdataGet(&extdata, EXTDATA_CHEATS, &item)) { + if (item.size) { + struct VFile* svf = VFileFromMemory(item.data, item.size); + if (svf) { + mCheatDeviceClear(device); + mCheatParseFile(device, svf); + svf->close(svf); + } + } + } + mStateExtdataDeinit(&extdata); + return success; +} +
@@ -39,4 +39,9 @@ struct VFile;
bool mStateExtdataSerialize(struct mStateExtdata* extdata, struct VFile* vf); bool mStateExtdataDeserialize(struct mStateExtdata* extdata, struct VFile* vf); +struct mCore; +bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags); +bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags); +void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata); + #endif
@@ -244,12 +244,18 @@ static void _GBACoreStep(struct mCore* core) {
ARMRun(core->cpu); } -static bool _GBACoreLoadState(struct mCore* core, struct VFile* vf, int flags) { - return GBALoadStateNamed(core->board, vf, flags); +static size_t _GBACoreStateSize(struct mCore* core) { + UNUSED(core); + return sizeof(struct GBASerializedState); } -static bool _GBACoreSaveState(struct mCore* core, struct VFile* vf, int flags) { - return GBASaveStateNamed(core->board, vf, flags); +static bool _GBACoreLoadState(struct mCore* core, const void* state) { + return GBADeserialize(core->board, state); +} + +static bool _GBACoreSaveState(struct mCore* core, void* state) { + GBASerialize(core->board, state); + return true; } static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {@@ -452,6 +458,7 @@ core->reset = _GBACoreReset;
core->runFrame = _GBACoreRunFrame; core->runLoop = _GBACoreRunLoop; core->step = _GBACoreStep; + core->stateSize = _GBACoreStateSize; core->loadState = _GBACoreLoadState; core->saveState = _GBACoreSaveState; core->setKeys = _GBACoreSetKeys;
@@ -30,7 +30,7 @@ }
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { struct VFile* vf = gba->rr->openSavestate(gba->rr, O_TRUNC | O_CREAT | O_RDWR); - GBASaveStateNamed(gba, vf, SAVESTATE_SAVEDATA); + //GBASaveStateNamed(gba, vf, SAVESTATE_SAVEDATA); vf->close(vf); } else { ARMReset(gba->cpu);@@ -54,7 +54,7 @@ }
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { struct VFile* vf = gba->rr->openSavestate(gba->rr, O_RDONLY); - GBALoadStateNamed(gba, vf, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA); + //GBALoadStateNamed(gba, vf, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA); vf->close(vf); } else { ARMReset(gba->cpu);
@@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "serialize.h" #include "core/serialize.h" -#include "core/sync.h" #include "gba/audio.h" #include "gba/cheats.h" #include "gba/io.h"@@ -21,12 +20,6 @@ #ifdef _MSC_VER
#include <time.h> #else #include <sys/time.h> -#endif - -#ifdef USE_PNG -#include "util/png-io.h" -#include <png.h> -#include <zlib.h> #endif const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000;@@ -213,278 +206,6 @@ if (gba->rr) {
gba->rr->stateLoaded(gba->rr, state); } return true; -} - -#ifdef USE_PNG -static bool _savePNGState(struct GBA* gba, struct VFile* vf, struct mStateExtdata* extdata) { - unsigned stride; - const void* pixels = 0; - gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels); - if (!pixels) { - return false; - } - - struct GBASerializedState* state = GBAAllocateState(); - if (!state) { - return false; - } - GBASerialize(gba, state); - uLongf len = compressBound(sizeof(*state)); - void* buffer = malloc(len); - if (!buffer) { - GBADeallocateState(state); - return false; - } - compress(buffer, &len, (const Bytef*) state, sizeof(*state)); - GBADeallocateState(state); - - png_structp png = PNGWriteOpen(vf); - png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); - if (!png || !info) { - PNGWriteClose(png, info); - free(buffer); - return false; - } - PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels); - PNGWriteCustomChunk(png, "gbAs", len, buffer); - if (extdata) { - uint32_t i; - for (i = 1; i < EXTDATA_MAX; ++i) { - if (!extdata->data[i].data) { - continue; - } - uLongf len = compressBound(extdata->data[i].size) + sizeof(uint32_t) * 2; - uint32_t* data = malloc(len); - if (!data) { - continue; - } - STORE_32(i, 0, data); - STORE_32(extdata->data[i].size, sizeof(uint32_t), data); - compress((Bytef*) (data + 2), &len, extdata->data[i].data, extdata->data[i].size); - PNGWriteCustomChunk(png, "gbAx", len + sizeof(uint32_t) * 2, data); - free(data); - } - } - PNGWriteClose(png, info); - free(buffer); - return true; -} - -static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) { - struct GBABundledState* bundle = png_get_user_chunk_ptr(png); - if (!bundle) { - return 0; - } - if (!strcmp((const char*) chunk->name, "gbAs")) { - struct GBASerializedState* state = bundle->state; - if (!state) { - return 0; - } - uLongf len = sizeof(*state); - uncompress((Bytef*) state, &len, chunk->data, chunk->size); - return 1; - } - if (!strcmp((const char*) chunk->name, "gbAx")) { - struct mStateExtdata* extdata = bundle->extdata; - if (!extdata) { - return 0; - } - struct mStateExtdataItem item; - if (chunk->size < sizeof(uint32_t) * 2) { - return 0; - } - uint32_t tag; - LOAD_32(tag, 0, chunk->data); - LOAD_32(item.size, sizeof(uint32_t), chunk->data); - uLongf len = item.size; - if (item.size < 0 || tag == EXTDATA_NONE || tag >= EXTDATA_MAX) { - return 0; - } - item.data = malloc(item.size); - item.clean = free; - if (!item.data) { - return 0; - } - const uint8_t* data = chunk->data; - data += sizeof(uint32_t) * 2; - uncompress((Bytef*) item.data, &len, data, chunk->size); - item.size = len; - mStateExtdataPut(extdata, tag, &item); - return 1; - } - return 0; -} - -static struct GBASerializedState* _loadPNGState(struct VFile* vf, struct mStateExtdata* extdata) { - png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES); - png_infop info = png_create_info_struct(png); - png_infop end = png_create_info_struct(png); - if (!png || !info || !end) { - PNGReadClose(png, info, end); - return false; - } - uint32_t* pixels = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); - if (!pixels) { - PNGReadClose(png, info, end); - return false; - } - - struct GBASerializedState* state = GBAAllocateState(); - struct GBABundledState bundle = { - .state = state, - .extdata = extdata - }; - - PNGInstallChunkHandler(png, &bundle, _loadPNGChunkHandler, "gbAs gbAx"); - bool success = PNGReadHeader(png, info); - success = success && PNGReadPixels(png, info, pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS); - success = success && PNGReadFooter(png, end); - PNGReadClose(png, info, end); - - if (success) { - struct mStateExtdataItem item = { - .size = VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4, - .data = pixels, - .clean = free - }; - mStateExtdataPut(extdata, EXTDATA_SCREENSHOT, &item); - } else { - free(pixels); - GBADeallocateState(state); - return 0; - } - return state; -} -#endif - -bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, int flags) { - struct mStateExtdata extdata; - mStateExtdataInit(&extdata); - if (flags & SAVESTATE_SAVEDATA) { - // TODO: A better way to do this would be nice - void* sram = malloc(SIZE_CART_FLASH1M); - struct VFile* svf = VFileFromMemory(sram, SIZE_CART_FLASH1M); - if (GBASavedataClone(&gba->memory.savedata, svf)) { - struct mStateExtdataItem item = { - .size = svf->seek(svf, 0, SEEK_CUR), - .data = sram, - .clean = free - }; - mStateExtdataPut(&extdata, EXTDATA_SAVEDATA, &item); - } else { - free(sram); - } - svf->close(svf); - } - struct VFile* cheatVf = 0; - if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { - struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; - cheatVf = VFileMemChunk(0, 0); - if (cheatVf) { - mCheatSaveFile(device, cheatVf); - struct mStateExtdataItem item = { - .size = cheatVf->size(cheatVf), - .data = cheatVf->map(cheatVf, cheatVf->size(cheatVf), MAP_READ), - .clean = 0 - }; - mStateExtdataPut(&extdata, EXTDATA_CHEATS, &item); - } - }; -#ifdef USE_PNG - if (!(flags & SAVESTATE_SCREENSHOT)) { -#else - UNUSED(flags); -#endif - vf->truncate(vf, sizeof(struct GBASerializedState)); - struct GBASerializedState* state = vf->map(vf, sizeof(struct GBASerializedState), MAP_WRITE); - if (!state) { - mStateExtdataDeinit(&extdata); - if (cheatVf) { - cheatVf->close(cheatVf); - } - return false; - } - GBASerialize(gba, state); - vf->unmap(vf, state, sizeof(struct GBASerializedState)); - vf->seek(vf, sizeof(struct GBASerializedState), SEEK_SET); - mStateExtdataSerialize(&extdata, vf); - mStateExtdataDeinit(&extdata); - if (cheatVf) { - cheatVf->close(cheatVf); - } - return true; -#ifdef USE_PNG - } - else { - bool success = _savePNGState(gba, vf, &extdata); - mStateExtdataDeinit(&extdata); - return success; - } -#endif - mStateExtdataDeinit(&extdata); - return false; -} - -struct GBASerializedState* GBAExtractState(struct VFile* vf, struct mStateExtdata* extdata) { -#ifdef USE_PNG - if (isPNG(vf)) { - return _loadPNGState(vf, extdata); - } -#endif - vf->seek(vf, 0, SEEK_SET); - if (vf->size(vf) < (ssize_t) sizeof(struct GBASerializedState)) { - return false; - } - struct GBASerializedState* state = GBAAllocateState(); - if (vf->read(vf, state, sizeof(*state)) != sizeof(*state)) { - GBADeallocateState(state); - return 0; - } - if (extdata) { - mStateExtdataDeserialize(extdata, vf); - } - return state; -} - -bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf, int flags) { - struct mStateExtdata extdata; - mStateExtdataInit(&extdata); - struct GBASerializedState* state = GBAExtractState(vf, &extdata); - if (!state) { - return false; - } - bool success = GBADeserialize(gba, state); - GBADeallocateState(state); - - struct mStateExtdataItem item; - if (flags & SAVESTATE_SCREENSHOT && mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item)) { - if (item.size >= VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4) { - gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, item.data); - mCoreSyncForceFrame(gba->sync); - } else { - mLOG(GBA_STATE, WARN, "Savestate includes invalid screenshot"); - } - } - if (flags & SAVESTATE_SAVEDATA && mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) { - struct VFile* svf = VFileFromMemory(item.data, item.size); - GBASavedataLoad(&gba->memory.savedata, svf); - if (svf) { - svf->close(svf); - } - } - if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] && mStateExtdataGet(&extdata, EXTDATA_CHEATS, &item)) { - if (item.size) { - struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; - struct VFile* svf = VFileFromMemory(item.data, item.size); - if (svf) { - mCheatDeviceClear(device); - mCheatParseFile(device, svf); - svf->close(svf); - } - } - } - mStateExtdataDeinit(&extdata); - return success; } struct GBASerializedState* GBAAllocateState(void) {
@@ -365,11 +365,6 @@
void GBASerialize(struct GBA* gba, struct GBASerializedState* state); bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state); -bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, int flags); -bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf, int flags); - -struct mStateExtdata; -struct GBASerializedState* GBAExtractState(struct VFile* vf, struct mStateExtdata* extdata); struct GBASerializedState* GBAAllocateState(void); void GBADeallocateState(struct GBASerializedState* state);
@@ -196,7 +196,7 @@
- (NSData *)serializeStateWithError:(NSError **)outError { struct VFile* vf = VFileMemChunk(nil, 0); - if (!core->saveState(core, vf, SAVESTATE_SAVEDATA)) { + if (!mCoreSaveStateNamed(core, vf, SAVESTATE_SAVEDATA)) { *outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:nil]; vf->close(vf); return nil;@@ -212,7 +212,7 @@
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError { struct VFile* vf = VFileFromConstMemory(state.bytes, state.length); - if (!core->loadState(core, vf, SAVESTATE_SAVEDATA)) { + if (!mCoreLoadStateNamed(core, vf, SAVESTATE_SAVEDATA)) { *outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:nil]; vf->close(vf); return NO;@@ -224,14 +224,14 @@
- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block { struct VFile* vf = VFileOpen([fileName UTF8String], O_CREAT | O_TRUNC | O_RDWR); - block(core->saveState(core, vf, 0), nil); + block(mCoreSaveStateNamed(core, vf, 0), nil); vf->close(vf); } - (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block { struct VFile* vf = VFileOpen([fileName UTF8String], O_RDONLY); - block(core->loadState(core, vf, 0), nil); + block(mCoreLoadStateNamed(core, vf, 0), nil); vf->close(vf); }
@@ -788,7 +788,7 @@ GameController* controller = static_cast<GameController*>(context->userData);
if (!controller->m_backupLoadState) { controller->m_backupLoadState = VFileMemChunk(nullptr, 0); } - context->core->saveState(context->core, controller->m_backupLoadState, controller->m_saveStateFlags); + mCoreLoadStateNamed(context->core, controller->m_backupLoadState, controller->m_saveStateFlags); if (mCoreLoadState(context->core, controller->m_stateSlot, controller->m_loadStateFlags)) { controller->frameAvailable(controller->m_drawContext); controller->stateLoaded(context);@@ -824,7 +824,7 @@
mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); controller->m_backupLoadState->seek(controller->m_backupLoadState, 0, SEEK_SET); - if (context->core->loadState(context->core, controller->m_backupLoadState, controller->m_loadStateFlags)) { + if (mCoreLoadStateNamed(context->core, controller->m_backupLoadState, controller->m_loadStateFlags)) { mLOG(STATUS, INFO, "Undid state load"); controller->frameAvailable(controller->m_drawContext); controller->stateLoaded(context);
@@ -19,6 +19,7 @@ #include "core/serialize.h"
#ifdef M_CORE_GBA #include "gba/serialize.h" #endif +#include "util/memory.h" } using namespace QGBA;@@ -180,7 +181,7 @@ }
mStateExtdata extdata; mStateExtdataInit(&extdata); - GBASerializedState* state = GBAExtractState(vf, &extdata); + void* state = mCoreExtractState(thread->core, vf, &extdata); vf->seek(vf, 0, SEEK_SET); if (!state) { m_slots[slot - 1]->setText(tr("Corrupted"));@@ -188,7 +189,7 @@ mStateExtdataDeinit(&extdata);
return; } - QDateTime creation(QDateTime::fromMSecsSinceEpoch(state->creationUsec / 1000LL)); + QDateTime creation/*(QDateTime::fromMSecsSinceEpoch(state->creationUsec / 1000LL))*/; // TODO QImage stateImage; mStateExtdataItem item;@@ -209,7 +210,7 @@ } else {
m_slots[slot - 1]->setText(QString()); } vf->close(vf); - GBADeallocateState(state); + mappedMemoryFree(state, thread->core->stateSize(thread->core)); } void LoadSaveState::triggerState(int slot) {
@@ -102,7 +102,7 @@ free(fuzzOpts.ssOverlay);
} if (savestate) { if (!savestateOverlay) { - core->loadState(core, savestate, 0); + mCoreLoadStateNamed(core, savestate, 0); } else { struct GBASerializedState* state = GBAAllocateState(); savestate->read(savestate, state, sizeof(*state));
@@ -162,7 +162,7 @@ mCoreLoadConfig(core);
core->reset(core); if (_savestate) { - core->loadState(core, _savestate, 0); + mCoreLoadStateNamed(core, _savestate, 0); } core->getGameCode(core, gameCode);