mirror of https://github.com/mgba-emu/mgba.git
GUI: Make autosave portable
This commit is contained in:
parent
0e9ba00dbf
commit
45c2fdf7ed
|
@ -23,6 +23,7 @@
|
||||||
mLOG_DECLARE_CATEGORY(GUI_RUNNER);
|
mLOG_DECLARE_CATEGORY(GUI_RUNNER);
|
||||||
mLOG_DEFINE_CATEGORY(GUI_RUNNER, "GUI Runner", "gui.runner");
|
mLOG_DEFINE_CATEGORY(GUI_RUNNER, "GUI Runner", "gui.runner");
|
||||||
|
|
||||||
|
#define AUTOSAVE_GRANULARITY 600
|
||||||
#define FPS_GRANULARITY 120
|
#define FPS_GRANULARITY 120
|
||||||
#define FPS_BUFFER_SIZE 3
|
#define FPS_BUFFER_SIZE 3
|
||||||
|
|
||||||
|
@ -34,19 +35,11 @@ enum {
|
||||||
RUNNER_SCREENSHOT,
|
RUNNER_SCREENSHOT,
|
||||||
RUNNER_CONFIG,
|
RUNNER_CONFIG,
|
||||||
RUNNER_RESET,
|
RUNNER_RESET,
|
||||||
RUNNER_COMMAND_MASK = 0xFFFF,
|
RUNNER_COMMAND_MASK = 0xFFFF
|
||||||
|
|
||||||
RUNNER_STATE_1 = 0x10000,
|
|
||||||
RUNNER_STATE_2 = 0x20000,
|
|
||||||
RUNNER_STATE_3 = 0x30000,
|
|
||||||
RUNNER_STATE_4 = 0x40000,
|
|
||||||
RUNNER_STATE_5 = 0x50000,
|
|
||||||
RUNNER_STATE_6 = 0x60000,
|
|
||||||
RUNNER_STATE_7 = 0x70000,
|
|
||||||
RUNNER_STATE_8 = 0x80000,
|
|
||||||
RUNNER_STATE_9 = 0x90000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define RUNNER_STATE(X) ((X) << 16)
|
||||||
|
|
||||||
static const struct mInputPlatformInfo _mGUIKeyInfo = {
|
static const struct mInputPlatformInfo _mGUIKeyInfo = {
|
||||||
.platformName = "gui",
|
.platformName = "gui",
|
||||||
.keyId = (const char*[GUI_INPUT_MAX]) {
|
.keyId = (const char*[GUI_INPUT_MAX]) {
|
||||||
|
@ -141,6 +134,21 @@ static uint8_t _readLux(struct GBALuminanceSource* lux) {
|
||||||
return 0xFF - value;
|
return 0xFF - value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tryAutosave(struct mGUIRunner* runner) {
|
||||||
|
#ifdef DISABLE_THREADING
|
||||||
|
mCoreSaveState(runner->core, 0, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
|
||||||
|
#else
|
||||||
|
if (!runner->autosave.buffer) {
|
||||||
|
runner->autosave.buffer = VFileMemChunk(NULL, 0);
|
||||||
|
}
|
||||||
|
MutexLock(&runner->autosave.mutex);
|
||||||
|
runner->autosave.core = runner->core;
|
||||||
|
mCoreSaveStateNamed(runner->core, runner->autosave.buffer, SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
|
||||||
|
ConditionWake(&runner->autosave.cond);
|
||||||
|
MutexUnlock(&runner->autosave.mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void mGUIInit(struct mGUIRunner* runner, const char* port) {
|
void mGUIInit(struct mGUIRunner* runner, const char* port) {
|
||||||
GUIInit(&runner->params);
|
GUIInit(&runner->params);
|
||||||
runner->port = port;
|
runner->port = port;
|
||||||
|
@ -174,9 +182,34 @@ void mGUIInit(struct mGUIRunner* runner, const char* port) {
|
||||||
strncpy(runner->params.currentPath, lastPath, PATH_MAX - 1);
|
strncpy(runner->params.currentPath, lastPath, PATH_MAX - 1);
|
||||||
runner->params.currentPath[PATH_MAX - 1] = '\0';
|
runner->params.currentPath[PATH_MAX - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
if (!runner->autosave.running) {
|
||||||
|
runner->autosave.running = true;
|
||||||
|
MutexInit(&runner->autosave.mutex);
|
||||||
|
ConditionInit(&runner->autosave.cond);
|
||||||
|
ThreadCreate(&runner->autosave.thread, mGUIAutosaveThread, &runner->autosave);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void mGUIDeinit(struct mGUIRunner* runner) {
|
void mGUIDeinit(struct mGUIRunner* runner) {
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
MutexLock(&runner->autosave.mutex);
|
||||||
|
runner->autosave.running = false;
|
||||||
|
ConditionWake(&runner->autosave.cond);
|
||||||
|
MutexUnlock(&runner->autosave.mutex);
|
||||||
|
|
||||||
|
ThreadJoin(runner->autosave.thread);
|
||||||
|
|
||||||
|
ConditionDeinit(&runner->autosave.cond);
|
||||||
|
MutexDeinit(&runner->autosave.mutex);
|
||||||
|
|
||||||
|
if (runner->autosave.buffer) {
|
||||||
|
runner->autosave.buffer->close(runner->autosave.buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (runner->teardown) {
|
if (runner->teardown) {
|
||||||
runner->teardown(runner);
|
runner->teardown(runner);
|
||||||
}
|
}
|
||||||
|
@ -239,25 +272,26 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu };
|
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu };
|
||||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu };
|
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu };
|
||||||
|
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_1) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(1)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_2) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(2)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_3) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(3)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_4) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(4)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_5) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(5)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_6) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(6)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_7) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(7)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_8) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(8)) };
|
||||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_9) };
|
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(9)) };
|
||||||
|
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_1) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "Autosave", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(0)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_2) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(1)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_3) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(2)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_4) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(3)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_5) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(4)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_6) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(5)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_7) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(6)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_8) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(7)) };
|
||||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_9) };
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(8)) };
|
||||||
|
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(9)) };
|
||||||
|
|
||||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT };
|
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT };
|
||||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG };
|
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG };
|
||||||
|
@ -325,6 +359,13 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
MutexLock(&runner->autosave.mutex);
|
||||||
|
runner->autosave.core = runner->core;
|
||||||
|
MutexUnlock(&runner->autosave.mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (runner->gameLoaded) {
|
if (runner->gameLoaded) {
|
||||||
runner->gameLoaded(runner);
|
runner->gameLoaded(runner);
|
||||||
}
|
}
|
||||||
|
@ -415,6 +456,9 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
|
runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (runner->core->frameCounter(runner->core) % AUTOSAVE_GRANULARITY == 0) {
|
||||||
|
_tryAutosave(runner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,6 +511,11 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
if (runner->gameUnloaded) {
|
if (runner->gameUnloaded) {
|
||||||
runner->gameUnloaded(runner);
|
runner->gameUnloaded(runner);
|
||||||
}
|
}
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
MutexLock(&runner->autosave.mutex);
|
||||||
|
runner->autosave.core = NULL;
|
||||||
|
MutexUnlock(&runner->autosave.mutex);
|
||||||
|
#endif
|
||||||
mLOG(GUI_RUNNER, DEBUG, "Unloading game...");
|
mLOG(GUI_RUNNER, DEBUG, "Unloading game...");
|
||||||
runner->core->unloadROM(runner->core);
|
runner->core->unloadROM(runner->core);
|
||||||
drawState.screenshotId = 0;
|
drawState.screenshotId = 0;
|
||||||
|
@ -524,3 +573,21 @@ void mGUIRunloop(struct mGUIRunner* runner) {
|
||||||
mGUIRun(runner, path);
|
mGUIRun(runner, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
THREAD_ENTRY mGUIAutosaveThread(void* context) {
|
||||||
|
struct mGUIAutosaveContext* autosave = context;
|
||||||
|
MutexLock(&autosave->mutex);
|
||||||
|
while (autosave->running) {
|
||||||
|
ConditionWait(&autosave->cond, &autosave->mutex);
|
||||||
|
if (autosave->running && autosave->core) {
|
||||||
|
struct VFile* vf = mCoreGetState(autosave->core, 0, true);
|
||||||
|
void* mem = autosave->buffer->map(autosave->buffer, autosave->buffer->size(autosave->buffer), MAP_READ);
|
||||||
|
vf->write(vf, mem, autosave->buffer->size(autosave->buffer));
|
||||||
|
autosave->buffer->unmap(autosave->buffer, mem, autosave->buffer->size(autosave->buffer));
|
||||||
|
vf->close(vf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MutexUnlock(&autosave->mutex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@ CXX_GUARD_START
|
||||||
#include <mgba/internal/gba/hardware.h>
|
#include <mgba/internal/gba/hardware.h>
|
||||||
#include <mgba-util/circle-buffer.h>
|
#include <mgba-util/circle-buffer.h>
|
||||||
#include <mgba-util/gui.h>
|
#include <mgba-util/gui.h>
|
||||||
|
#include <mgba-util/threading.h>
|
||||||
|
|
||||||
enum mGUIInput {
|
enum mGUIInput {
|
||||||
mGUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START,
|
mGUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START,
|
||||||
|
@ -38,12 +39,27 @@ struct mGUIRunnerLux {
|
||||||
int luxLevel;
|
int luxLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
struct VFile;
|
||||||
|
struct mGUIAutosaveContext {
|
||||||
|
struct VFile* buffer;
|
||||||
|
struct mCore* core;
|
||||||
|
Thread thread;
|
||||||
|
Mutex mutex;
|
||||||
|
Condition cond;
|
||||||
|
bool running;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct mGUIRunner {
|
struct mGUIRunner {
|
||||||
struct mCore* core;
|
struct mCore* core;
|
||||||
struct GUIParams params;
|
struct GUIParams params;
|
||||||
|
|
||||||
struct mGUIBackground background;
|
struct mGUIBackground background;
|
||||||
struct mGUIRunnerLux luminanceSource;
|
struct mGUIRunnerLux luminanceSource;
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
struct mGUIAutosaveContext autosave;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct mInputMap guiKeys;
|
struct mInputMap guiKeys;
|
||||||
struct mCoreConfig config;
|
struct mCoreConfig config;
|
||||||
|
@ -78,6 +94,10 @@ void mGUIDeinit(struct mGUIRunner*);
|
||||||
void mGUIRun(struct mGUIRunner*, const char* path);
|
void mGUIRun(struct mGUIRunner*, const char* path);
|
||||||
void mGUIRunloop(struct mGUIRunner*);
|
void mGUIRunloop(struct mGUIRunner*);
|
||||||
|
|
||||||
|
#ifndef DISABLE_THREADING
|
||||||
|
THREAD_ENTRY mGUIAutosaveThread(void* context);
|
||||||
|
#endif
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -106,12 +106,6 @@ 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) {
|
||||||
|
@ -201,33 +195,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -460,10 +427,6 @@ 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) {
|
||||||
|
@ -497,10 +460,6 @@ 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) {
|
||||||
|
@ -722,16 +681,7 @@ static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _running(struct mGUIRunner* runner) {
|
static bool _running(struct mGUIRunner* runner) {
|
||||||
static int frame = 0;
|
UNUSED(runner);
|
||||||
if (autosaveCore) {
|
|
||||||
++frame;
|
|
||||||
if (frame == 300) {
|
|
||||||
_tryAutosave(autosaveCore);
|
|
||||||
frame = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
frame = 0;
|
|
||||||
}
|
|
||||||
return aptMainLoop();
|
return aptMainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,6 +1031,13 @@ int main() {
|
||||||
.running = _running
|
.running = _running
|
||||||
};
|
};
|
||||||
|
|
||||||
|
runner.autosave.running = true;
|
||||||
|
MutexInit(&runner.autosave.mutex);
|
||||||
|
ConditionInit(&runner.autosave.cond);
|
||||||
|
|
||||||
|
APT_SetAppCpuTimeLimit(20);
|
||||||
|
runner.autosave.thread = threadCreate(mGUIAutosaveThread, &runner.autosave, 0x4000, 0x1F, 1, true);
|
||||||
|
|
||||||
mGUIInit(&runner, "3ds");
|
mGUIInit(&runner, "3ds");
|
||||||
|
|
||||||
_map3DSKey(&runner.params.keyMap, KEY_X, GUI_INPUT_CANCEL);
|
_map3DSKey(&runner.params.keyMap, KEY_X, GUI_INPUT_CANCEL);
|
||||||
|
@ -1094,29 +1051,7 @@ 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