Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,16 @@
#define DEFAULT_SAVESTATE_AUTO_SAVE false
#define DEFAULT_SAVESTATE_AUTO_LOAD false

/* Automatically saves a savestate at a regular interval.
* It is measured in seconds. A value of 0 disables automatic savestate saving. */
#if defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(__x86_64__) || defined(_M_X64) || defined(_WIN32) || defined(OSX) || defined(ANDROID) || defined(IOS) || defined(DINGUX)
/* Disabled by default but can be enabled by user */
#define DEFAULT_AUTOMATIC_SAVESTATE_INTERVAL 0
#else
/* Default to disabled on I/O-constrained platforms */
#define DEFAULT_AUTOMATIC_SAVESTATE_INTERVAL 0
#endif

/* Take screenshots for save states */
#if defined(__x86_64__) || defined(_M_X64)
#define DEFAULT_SAVESTATE_THUMBNAIL_ENABLE true
Expand Down
1 change: 1 addition & 0 deletions configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -2461,6 +2461,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("memory_update_interval", &settings->uints.memory_update_interval, true, DEFAULT_MEMORY_UPDATE_INTERVAL, false);
SETTING_UINT("core_updater_auto_backup_history_size", &settings->uints.core_updater_auto_backup_history_size, true, DEFAULT_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, false);
SETTING_UINT("autosave_interval", &settings->uints.autosave_interval, true, DEFAULT_AUTOSAVE_INTERVAL, false);
SETTING_UINT("automatic_savestate_interval", &settings->uints.automatic_savestate_interval, true, DEFAULT_AUTOMATIC_SAVESTATE_INTERVAL, false);
SETTING_UINT("rewind_granularity", &settings->uints.rewind_granularity, true, DEFAULT_REWIND_GRANULARITY, false);
SETTING_UINT("rewind_buffer_size_step", &settings->uints.rewind_buffer_size_step, true, DEFAULT_REWIND_BUFFER_SIZE_STEP, false);
SETTING_UINT("run_ahead_frames", &settings->uints.run_ahead_frames, true, 1, false);
Expand Down
1 change: 1 addition & 0 deletions configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ typedef struct settings
unsigned rewind_granularity;
unsigned rewind_buffer_size_step;
unsigned autosave_interval;
unsigned automatic_savestate_interval;
unsigned replay_checkpoint_interval;
unsigned replay_max_keep;
unsigned savestate_max_keep;
Expand Down
3 changes: 3 additions & 0 deletions content.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ bool content_load_state(const char* path, bool load_to_backup_buffer, bool autol
/* Save a state from memory to disk. */
bool content_save_state(const char *path, bool save_to_disk);

/* Automatically save a state if the interval has elapsed. */
bool content_save_state_automatic(void);

/* Save an automatic savestate to disk. */
bool content_auto_save_state(const char *path);

Expand Down
7 changes: 6 additions & 1 deletion gfx/drivers_shader/slang_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,18 @@ static bool spirv_cache_get_filename(const char *hash,
char *cache_file_out, size_t cache_file_out_len)
{
char cache_dir[PATH_MAX_LENGTH];
int ret;

if (!spirv_cache_get_dir(cache_dir, sizeof(cache_dir)))
return false;

snprintf(cache_file_out, cache_file_out_len, "%s/%s.spirv",
ret = snprintf(cache_file_out, cache_file_out_len, "%s/%s.spirv",
cache_dir, hash);

/* Check if snprintf truncated the output */
if (ret < 0 || (size_t)ret >= cache_file_out_len)
return false;

return true;
}

Expand Down
4 changes: 4 additions & 0 deletions intl/msg_hash_lbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ MSG_HASH(
MENU_ENUM_LABEL_AUTOSAVE_INTERVAL,
MENU_ENUM_LABEL_AUTOSAVE_INTERVAL_STR
)
MSG_HASH(
MENU_ENUM_LABEL_AUTOMATIC_SAVESTATE_INTERVAL,
MENU_ENUM_LABEL_AUTOMATIC_SAVESTATE_INTERVAL_STR
)
MSG_HASH(
MENU_ENUM_LABEL_REPLAY_CHECKPOINT_INTERVAL,
MENU_ENUM_LABEL_REPLAY_CHECKPOINT_INTERVAL_STR
Expand Down
12 changes: 12 additions & 0 deletions intl/msg_hash_us.h
Original file line number Diff line number Diff line change
Expand Up @@ -4779,6 +4779,18 @@ MSG_HASH(
MENU_ENUM_LABEL_HELP_AUTOSAVE_INTERVAL,
"Autosaves the non-volatile SRAM at a regular interval. This is disabled by default unless set otherwise. The interval is measured in seconds. A value of 0 disables autosave."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_AUTOMATIC_SAVESTATE_INTERVAL,
"Automatic Savestate Interval"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_AUTOMATIC_SAVESTATE_INTERVAL,
"Automatically save a savestate at a regular interval (in seconds). Set to 0 to disable."
)
MSG_HASH(
MENU_ENUM_LABEL_HELP_AUTOMATIC_SAVESTATE_INTERVAL,
"Automatically saves a savestate at regular intervals. This is useful for creating periodic backups of your game progress. The interval is measured in seconds. A value of 0 disables automatic savestate saving."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_REPLAY_CHECKPOINT_INTERVAL,
"Replay: Checkpoint Interval"
Expand Down
4 changes: 4 additions & 0 deletions menu/cbs/menu_cbs_sublabel.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_save_file_compression, MENU_
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_savestate_file_compression, MENU_ENUM_SUBLABEL_SAVESTATE_FILE_COMPRESSION)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_savestate_max_keep, MENU_ENUM_SUBLABEL_SAVESTATE_MAX_KEEP)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_autosave_interval, MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_automatic_savestate_interval, MENU_ENUM_SUBLABEL_AUTOMATIC_SAVESTATE_INTERVAL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_replay_max_keep, MENU_ENUM_SUBLABEL_REPLAY_MAX_KEEP)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_replay_checkpoint_interval, MENU_ENUM_SUBLABEL_REPLAY_CHECKPOINT_INTERVAL)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_replay_checkpoint_deserialize, MENU_ENUM_SUBLABEL_REPLAY_CHECKPOINT_DESERIALIZE)
Expand Down Expand Up @@ -4107,6 +4108,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_AUTOSAVE_INTERVAL:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_autosave_interval);
break;
case MENU_ENUM_LABEL_AUTOMATIC_SAVESTATE_INTERVAL:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_automatic_savestate_interval);
break;
case MENU_ENUM_LABEL_REPLAY_CHECKPOINT_INTERVAL:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_replay_checkpoint_interval);
break;
Expand Down
1 change: 1 addition & 0 deletions menu/menu_displaylist.c
Original file line number Diff line number Diff line change
Expand Up @@ -11138,6 +11138,7 @@ unsigned menu_displaylist_build_list(
{MENU_ENUM_LABEL_SORT_SAVEFILES_BY_CONTENT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_AUTOSAVE_INTERVAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_AUTOMATIC_SAVESTATE_INTERVAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE, PARSE_ONLY_BOOL, true},
#if defined(HAVE_ZLIB)
{MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION, PARSE_ONLY_BOOL, true},
Expand Down
20 changes: 20 additions & 0 deletions menu/menu_setting.c
Original file line number Diff line number Diff line change
Expand Up @@ -12006,6 +12006,26 @@ static bool setting_append_list(
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_uint_autosave_interval;
#endif

#ifdef HAVE_THREADS
CONFIG_UINT(
list, list_info,
&settings->uints.automatic_savestate_interval,
MENU_ENUM_LABEL_AUTOMATIC_SAVESTATE_INTERVAL,
MENU_ENUM_LABEL_VALUE_AUTOMATIC_SAVESTATE_INTERVAL,
DEFAULT_AUTOMATIC_SAVESTATE_INTERVAL,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
menu_settings_list_current_add_range(list, list_info, 0, 0, 1, true, false);
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_CMD_APPLY_AUTO);
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_uint_autosave_interval;
#endif

CONFIG_BOOL(
list, list_info,
&settings->bools.savestate_auto_index,
Expand Down
1 change: 1 addition & 0 deletions msg_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -2546,6 +2546,7 @@ enum msg_hash_enums
MENU_LABEL(FRONTEND_LOG_LEVEL),
MENU_LBL_H(LIBRETRO_LOG_LEVEL),
MENU_LBL_H(AUTOSAVE_INTERVAL),
MENU_LBL_H(AUTOMATIC_SAVESTATE_INTERVAL),
MENU_LBL_H(REPLAY_CHECKPOINT_INTERVAL),
MENU_LBL_H(REPLAY_CHECKPOINT_DESERIALIZE),
MENU_LBL_H(CONFIG_SAVE_ON_EXIT),
Expand Down
1 change: 1 addition & 0 deletions msg_hash_lbl_str.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
#define MENU_ENUM_LABEL_MICROPHONE_WASAPI_SH_BUFFER_LENGTH_STR "microphone_wasapi_sh_buffer_length"
#define MENU_ENUM_LABEL_MICROPHONE_RESAMPLER_QUALITY_STR "microphone_resampler_quality"
#define MENU_ENUM_LABEL_AUTOSAVE_INTERVAL_STR "autosave_interval"
#define MENU_ENUM_LABEL_AUTOMATIC_SAVESTATE_INTERVAL_STR "automatic_savestate_interval"
#define MENU_ENUM_LABEL_REPLAY_CHECKPOINT_INTERVAL_STR "replay_checkpoint_interval"
#define MENU_ENUM_LABEL_REPLAY_CHECKPOINT_DESERIALIZE_STR "replay_checkpoint_deserialize"
#define MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE_STR "auto_overrides_enable"
Expand Down
3 changes: 3 additions & 0 deletions runloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -7476,6 +7476,9 @@ int runloop_iterate(void)
autosave_unlock();
#endif

/* Check if we should save state automatically */
content_save_state_automatic();

end:
if (vrr_runloop_enable)
{
Expand Down
43 changes: 43 additions & 0 deletions tasks/task_save.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ static struct ram_save_state_buf ram_buf;
static bool save_state_in_background = false;
static bool save_state_disable_undo = false;

/* Time tracking for automatic savestate interval */
static time_t last_automatic_savestate_time = 0;

typedef struct rastate_size_info
{
size_t total_size;
Expand Down Expand Up @@ -1882,3 +1885,43 @@ void set_save_state_disable_undo(bool disable)
{
save_state_disable_undo = disable;
}

bool content_save_state_automatic(void)
{
time_t current_time;
char savestate_path[PATH_MAX_LENGTH];
settings_t *settings = config_get_ptr();
unsigned automatic_savestate_interval =
settings->uints.automatic_savestate_interval;

/* Return early if automatic savestate is disabled,
safety checks already happen in content_save_state() */
if (automatic_savestate_interval == 0)
return false;

current_time = time(NULL);

/* Check how long since last autosavestate */
if ((current_time - last_automatic_savestate_time) <
(time_t)automatic_savestate_interval)
return false;

/* Generate the savestate path */
if (!runloop_get_savestate_path(savestate_path,
sizeof(savestate_path), -1))
{
RARCH_WARN("[State] %s\n",
msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO));
return false;
}

/* Trigger the savestate */
RARCH_LOG("[State] %s (automatic) to \"%s\".\n",
msg_hash_to_str(MSG_SAVING_STATE),
savestate_path);

/* Update the last savestate time, rinse/repeat */
last_automatic_savestate_time = current_time;

return content_auto_save_state(savestate_path);
}
Loading