Skip to content

Commit 3eef019

Browse files
authored
added in-ram savestates (#2252)
1 parent 3339416 commit 3eef019

File tree

8 files changed

+82
-10
lines changed

8 files changed

+82
-10
lines changed

core/input/gamepad.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ enum DreamcastKey
5252
EMU_BTN_SAVESTATE,
5353
EMU_BTN_NEXTSLOT,
5454
EMU_BTN_PREVSLOT,
55+
EMU_BTN_LOADSTATE_RAM,
56+
EMU_BTN_SAVESTATE_RAM,
5557
EMU_BTN_BYPASS_KB,
5658
EMU_BTN_SCREENSHOT,
5759
EMU_BTN_SRVMODE, // used internally by virtual gamepad

core/input/gamepad_device.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
110110
if (pressed)
111111
gui_cycleSaveStateSlot(-1);
112112
break;
113+
case EMU_BTN_LOADSTATE_RAM:
114+
if (pressed)
115+
gui_loadState(true);
116+
break;
117+
case EMU_BTN_SAVESTATE_RAM:
118+
if (pressed)
119+
gui_saveState(false, true);
120+
break;
113121
case EMU_BTN_SCREENSHOT:
114122
if (pressed)
115123
gui_takeScreenshot();

core/input/mapping.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ button_list[] =
6464
{ EMU_BTN_SAVESTATE, "emulator", "btn_quick_save" },
6565
{ EMU_BTN_NEXTSLOT, "emulator", "btn_next_slot" },
6666
{ EMU_BTN_PREVSLOT, "emulator", "btn_prev_slot" },
67+
{ EMU_BTN_LOADSTATE_RAM, "emulator", "btn_jump_state_ram" },
68+
{ EMU_BTN_SAVESTATE_RAM, "emulator", "btn_quick_save_ram" },
6769
{ EMU_BTN_BYPASS_KB, "emulator", "btn_bypass_kb" },
6870
{ EMU_BTN_SCREENSHOT, "emulator", "btn_screenshot" },
6971
};

core/nullDC.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@
2727
static std::string lastStateFile;
2828
static time_t lastStateTime;
2929

30+
#if defined(__ANDROID__)
31+
#include <android/api-level.h>
32+
// fmemopen was added in Marshmallow (API 23)
33+
#if __ANDROID_API__ >= 23
34+
#define HAS_FMEMOPEN
35+
#endif
36+
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__GLIBC__)
37+
// Standard POSIX platforms usually have fmemopen
38+
#define HAS_FMEMOPEN
39+
#endif
40+
41+
#ifdef HAS_FMEMOPEN
42+
const u32 QUICKSAVE_DEFAULT_SIZE = 32 * 1024 * 1024; // 32 MB
43+
static u8 quicksave_buf[QUICKSAVE_DEFAULT_SIZE] = {0};
44+
#endif
45+
3046
struct SavestateHeader
3147
{
3248
void init()
@@ -182,8 +198,23 @@ void dc_savestate(int index, const u8 *pngData, u32 pngSize)
182198
ser = Serializer(data, ser.size());
183199
dc_serialize(ser);
184200

185-
std::string filename = hostfs::getSavestatePath(index, true);
186-
FILE *f = nowide::fopen(filename.c_str(), "wb");
201+
FILE *f = nullptr;
202+
std::string filename = "";
203+
#ifdef HAS_FMEMOPEN
204+
if (index == -2)
205+
{
206+
// in-ram savestate
207+
filename = "RAM";
208+
f = fmemopen(quicksave_buf, QUICKSAVE_DEFAULT_SIZE, "wb");
209+
}
210+
else
211+
#endif
212+
{
213+
// regular file savestate
214+
filename = hostfs::getSavestatePath(index, true);
215+
f = nowide::fopen(filename.c_str(), "wb");
216+
}
217+
187218
if (f == nullptr)
188219
{
189220
WARN_LOG(SAVESTATE, "Failed to save state - could not open %s for writing", filename.c_str());
@@ -235,8 +266,23 @@ void dc_loadstate(int index)
235266
return;
236267
u32 total_size = 0;
237268

238-
std::string filename = hostfs::getSavestatePath(index, false);
239-
FILE *f = hostfs::storage().openFile(filename, "rb");
269+
FILE *f = nullptr;
270+
std::string filename = "";
271+
#ifdef HAS_FMEMOPEN
272+
if (index == -2)
273+
{
274+
// in-ram savestate
275+
filename = "RAM";
276+
f = fmemopen(quicksave_buf, QUICKSAVE_DEFAULT_SIZE, "rb");
277+
}
278+
else
279+
#endif
280+
{
281+
// regular file savestate
282+
filename = hostfs::getSavestatePath(index, false);
283+
f = hostfs::storage().openFile(filename, "rb");
284+
}
285+
240286
if (f == nullptr)
241287
{
242288
WARN_LOG(SAVESTATE, "Failed to load state - could not open %s for reading", filename.c_str());

core/oslib/oslib.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ std::string getSavestatePath(int index, bool writable)
206206
state_file = state_file + index_str + ".state";
207207
if (index == -1)
208208
state_file += ".net";
209+
if (index == -2)
210+
state_file += ".tmp";
209211

210212
static std::string lastFile;
211213
static std::string lastPath;

core/ui/gui.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,30 +1736,38 @@ void gui_error(const std::string& what) {
17361736
error_msg = what;
17371737
}
17381738

1739-
void gui_loadState()
1739+
void gui_loadState(bool inRam)
17401740
{
17411741
const LockGuard lock(guiMutex);
17421742
if (gui_state == GuiState::Closed && dc_savestateAllowed())
17431743
{
17441744
try {
17451745
emu.stop();
1746-
dc_loadstate(config::SavestateSlot);
1746+
if (inRam)
1747+
dc_loadstate(-2); // special slot used for inRam states
1748+
else
1749+
dc_loadstate(config::SavestateSlot);
17471750
emu.start();
17481751
} catch (const FlycastException& e) {
17491752
gui_stop_game(e.what());
17501753
}
17511754
}
17521755
}
17531756

1754-
void gui_saveState(bool stopRestart)
1757+
void gui_saveState(bool stopRestart, bool inRam)
17551758
{
17561759
const LockGuard lock(guiMutex);
17571760
if ((gui_state == GuiState::Closed || !stopRestart) && dc_savestateAllowed())
17581761
{
17591762
try {
17601763
if (stopRestart)
17611764
emu.stop();
1762-
savestate();
1765+
1766+
if (inRam)
1767+
dc_savestate(-2);
1768+
else
1769+
savestate();
1770+
17631771
if (stopRestart)
17641772
emu.start();
17651773
} catch (const FlycastException& e) {

core/ui/gui.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ void gui_stop_game(const std::string& message = "");
4848
void gui_start_game(const std::string& path);
4949
void gui_error(const std::string& what);
5050
void gui_setOnScreenKeyboardCallback(void (*callback)(bool show));
51-
void gui_loadState();
52-
void gui_saveState(bool stopRestart = true);
51+
void gui_loadState(bool inRam = false);
52+
void gui_saveState(bool stopRestart = true, bool inRam = false);
5353
void gui_cycleSaveStateSlot(int step);
5454
std::string gui_getCurGameBoxartUrl();
5555
void gui_takeScreenshot();

core/ui/settings_controls.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ static Mapping dcButtons[] = {
221221
{ EMU_BTN_FFORWARD, Tnop("Fast-forward") },
222222
{ EMU_BTN_LOADSTATE, Tnop("Load State") },
223223
{ EMU_BTN_SAVESTATE, Tnop("Save State") },
224+
{ EMU_BTN_LOADSTATE_RAM, Tnop("Load State in RAM") },
225+
{ EMU_BTN_SAVESTATE_RAM, Tnop("Save State in RAM") },
224226
{ EMU_BTN_NEXTSLOT, Tnop("Next Save State Slot") },
225227
{ EMU_BTN_PREVSLOT, Tnop("Previous Save State Slot") },
226228
{ EMU_BTN_BYPASS_KB, Tnop("Bypass Emulated Keyboard") },
@@ -277,6 +279,8 @@ static Mapping arcadeButtons[] = {
277279
{ EMU_BTN_FFORWARD, Tnop("Fast-forward") },
278280
{ EMU_BTN_LOADSTATE, Tnop("Load State") },
279281
{ EMU_BTN_SAVESTATE, Tnop("Save State") },
282+
{ EMU_BTN_LOADSTATE_RAM, Tnop("Load State in RAM") },
283+
{ EMU_BTN_SAVESTATE_RAM, Tnop("Save State in RAM") },
280284
{ EMU_BTN_NEXTSLOT, Tnop("Next Save State Slot") },
281285
{ EMU_BTN_PREVSLOT, Tnop("Previous Save State Slot") },
282286
{ EMU_BTN_BYPASS_KB, Tnop("Bypass Emulated Keyboard") },

0 commit comments

Comments
 (0)