From 0e9ba00dbfd3ed4586fbe79b64ebb319db5221a5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 10 Jan 2018 00:42:09 -0800 Subject: [PATCH] 3DS: Add experimental autosave --- src/feature/gui/gui-runner.c | 16 ++++++++ src/platform/3ds/main.c | 75 ++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index ca4168d9f..6e68168fb 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -317,6 +317,13 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mLOG(GUI_RUNNER, DEBUG, "Reseting..."); runner->core->reset(runner->core); mLOG(GUI_RUNNER, DEBUG, "Reset!"); + + if (mCoreLoadState(runner->core, 0, SAVESTATE_SCREENSHOT | SAVESTATE_RTC)) { + struct VFile* autosave = mCoreGetState(runner->core, 0, true); + autosave->truncate(autosave, 0); + autosave->close(autosave); + } + bool running = true; if (runner->gameLoaded) { runner->gameLoaded(runner); @@ -469,6 +476,14 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mappedMemoryFree(drawState.screenshot, w * h * 4); } + struct VFile* autosave = mCoreGetState(runner->core, 0, false); + if (autosave) { + autosave->close(autosave); + autosave = mCoreGetState(runner->core, 0, true); + autosave->truncate(autosave, 0); + autosave->close(autosave); + } + if (runner->config.port) { mLOG(GUI_RUNNER, DEBUG, "Saving key sources..."); if (runner->keySources) { @@ -483,6 +498,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mInputMapDeinit(&runner->core->inputMap); mLOG(GUI_RUNNER, DEBUG, "Deinitializing core..."); runner->core->deinit(runner->core); + runner->core = NULL; GUIMenuItemListDeinit(&pauseMenu.items); GUIMenuItemListDeinit(&stateSaveMenu.items); diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index b04cf5a27..7ce131219 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -6,6 +6,7 @@ #include #include +#include #ifdef M_CORE_GBA #include #include @@ -22,6 +23,7 @@ #include #include +#include #include "ctr-gpu.h" #include <3ds.h> @@ -104,6 +106,12 @@ static C3D_Tex upscaleBufferTex; static aptHookCookie cookie; +static Thread autosave; +static struct VFile* autosaveBuffer = NULL; +static Mutex autosaveMutex; +static Condition autosaveCond; +static struct mCore* autosaveCore = NULL; + extern bool allocateRomBuffer(void); static bool _initGpu(void) { @@ -193,6 +201,33 @@ static void _aptHook(APT_HookType hook, void* user) { } } +static void _autosaveThread(void* context) { + bool* running = context; + MutexLock(&autosaveMutex); + while (*running) { + ConditionWait(&autosaveCond, &autosaveMutex); + if (*running && autosaveCore) { + struct VFile* vf = mCoreGetState(autosaveCore, 0, true); + void* mem = autosaveBuffer->map(autosaveBuffer, autosaveBuffer->size(autosaveBuffer), MAP_READ); + vf->write(vf, mem, autosaveBuffer->size(autosaveBuffer)); + autosaveBuffer->unmap(autosaveBuffer, mem, autosaveBuffer->size(autosaveBuffer)); + vf->close(vf); + } + } + MutexUnlock(&autosaveMutex); +} + +static void _tryAutosave(struct mCore* core) { + if (!autosaveBuffer) { + autosaveBuffer = VFileMemChunk(NULL, 0); + } + MutexLock(&autosaveMutex); + autosaveCore = core; + mCoreSaveStateNamed(core, autosaveBuffer, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA); + ConditionWake(&autosaveCond); + MutexUnlock(&autosaveMutex); +} + static void _map3DSKey(struct mInputMap* map, int ctrKey, enum GBAKey key) { mInputBindKey(map, _3DS_INPUT, __builtin_ctz(ctrKey), key); } @@ -425,6 +460,10 @@ static void _gameLoaded(struct mGUIRunner* runner) { } } } + + MutexLock(&autosaveMutex); + autosaveCore = runner->core; + MutexUnlock(&autosaveMutex); } static void _gameUnloaded(struct mGUIRunner* runner) { @@ -458,6 +497,10 @@ static void _gameUnloaded(struct mGUIRunner* runner) { default: break; } + + MutexLock(&autosaveMutex); + autosaveCore = NULL; + MutexUnlock(&autosaveMutex); } static void _drawTex(struct mCore* core, bool faded) { @@ -679,6 +722,16 @@ static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) { } static bool _running(struct mGUIRunner* runner) { + static int frame = 0; + if (autosaveCore) { + ++frame; + if (frame == 300) { + _tryAutosave(autosaveCore); + frame = 0; + } + } else { + frame = 0; + } return aptMainLoop(); } @@ -1041,7 +1094,29 @@ int main() { _map3DSKey(&runner.params.keyMap, KEY_CSTICK_UP, mGUI_INPUT_INCREASE_BRIGHTNESS); _map3DSKey(&runner.params.keyMap, KEY_CSTICK_DOWN, mGUI_INPUT_DECREASE_BRIGHTNESS); + bool autosaveActive = true; + MutexInit(&autosaveMutex); + ConditionInit(&autosaveCond); + + APT_SetAppCpuTimeLimit(20); + autosave = threadCreate(_autosaveThread, &autosaveActive, 0x4000, 0x1F, 1, true); + mGUIRunloop(&runner); + + MutexLock(&autosaveMutex); + autosaveActive = false; + ConditionWake(&autosaveCond); + MutexUnlock(&autosaveMutex); + + threadJoin(autosave, U64_MAX); + + if (autosaveBuffer) { + autosaveBuffer->close(autosaveBuffer); + } + + ConditionDeinit(&autosaveCond); + MutexDeinit(&autosaveMutex); + mGUIDeinit(&runner); _cleanup();