mirror of https://github.com/mgba-emu/mgba.git
3DS: Add experimental autosave
This commit is contained in:
parent
789a84d2e2
commit
0e9ba00dbf
|
@ -317,6 +317,13 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
mLOG(GUI_RUNNER, DEBUG, "Reseting...");
|
mLOG(GUI_RUNNER, DEBUG, "Reseting...");
|
||||||
runner->core->reset(runner->core);
|
runner->core->reset(runner->core);
|
||||||
mLOG(GUI_RUNNER, DEBUG, "Reset!");
|
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;
|
bool running = true;
|
||||||
if (runner->gameLoaded) {
|
if (runner->gameLoaded) {
|
||||||
runner->gameLoaded(runner);
|
runner->gameLoaded(runner);
|
||||||
|
@ -469,6 +476,14 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
mappedMemoryFree(drawState.screenshot, w * h * 4);
|
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) {
|
if (runner->config.port) {
|
||||||
mLOG(GUI_RUNNER, DEBUG, "Saving key sources...");
|
mLOG(GUI_RUNNER, DEBUG, "Saving key sources...");
|
||||||
if (runner->keySources) {
|
if (runner->keySources) {
|
||||||
|
@ -483,6 +498,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
mInputMapDeinit(&runner->core->inputMap);
|
mInputMapDeinit(&runner->core->inputMap);
|
||||||
mLOG(GUI_RUNNER, DEBUG, "Deinitializing core...");
|
mLOG(GUI_RUNNER, DEBUG, "Deinitializing core...");
|
||||||
runner->core->deinit(runner->core);
|
runner->core->deinit(runner->core);
|
||||||
|
runner->core = NULL;
|
||||||
|
|
||||||
GUIMenuItemListDeinit(&pauseMenu.items);
|
GUIMenuItemListDeinit(&pauseMenu.items);
|
||||||
GUIMenuItemListDeinit(&stateSaveMenu.items);
|
GUIMenuItemListDeinit(&stateSaveMenu.items);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <mgba/core/blip_buf.h>
|
#include <mgba/core/blip_buf.h>
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
|
#include <mgba/core/serialize.h>
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
#include <mgba/internal/gba/input.h>
|
#include <mgba/internal/gba/input.h>
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <mgba-util/memory.h>
|
#include <mgba-util/memory.h>
|
||||||
|
|
||||||
#include <mgba-util/platform/3ds/3ds-vfs.h>
|
#include <mgba-util/platform/3ds/3ds-vfs.h>
|
||||||
|
#include <mgba-util/threading.h>
|
||||||
#include "ctr-gpu.h"
|
#include "ctr-gpu.h"
|
||||||
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
@ -104,6 +106,12 @@ static C3D_Tex upscaleBufferTex;
|
||||||
|
|
||||||
static aptHookCookie cookie;
|
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);
|
extern bool allocateRomBuffer(void);
|
||||||
|
|
||||||
static bool _initGpu(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) {
|
static void _map3DSKey(struct mInputMap* map, int ctrKey, enum GBAKey key) {
|
||||||
mInputBindKey(map, _3DS_INPUT, __builtin_ctz(ctrKey), 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) {
|
static void _gameUnloaded(struct mGUIRunner* runner) {
|
||||||
|
@ -458,6 +497,10 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MutexLock(&autosaveMutex);
|
||||||
|
autosaveCore = NULL;
|
||||||
|
MutexUnlock(&autosaveMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _drawTex(struct mCore* core, bool faded) {
|
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 bool _running(struct mGUIRunner* runner) {
|
||||||
|
static int frame = 0;
|
||||||
|
if (autosaveCore) {
|
||||||
|
++frame;
|
||||||
|
if (frame == 300) {
|
||||||
|
_tryAutosave(autosaveCore);
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
return aptMainLoop();
|
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_UP, mGUI_INPUT_INCREASE_BRIGHTNESS);
|
||||||
_map3DSKey(&runner.params.keyMap, KEY_CSTICK_DOWN, mGUI_INPUT_DECREASE_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);
|
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);
|
mGUIDeinit(&runner);
|
||||||
|
|
||||||
_cleanup();
|
_cleanup();
|
||||||
|
|
Loading…
Reference in New Issue