Add optional save (SRAM) file compression

This commit is contained in:
jdgleaver 2020-04-20 12:47:13 +01:00
parent 3fa60d08de
commit 0d1fd657ab
11 changed files with 103 additions and 12 deletions

View File

@ -911,6 +911,10 @@ static const bool savestate_auto_load = false;
static const bool savestate_thumbnail_enable = false;
/* When creating save (srm) files, compress
* written data */
#define DEFAULT_SAVE_FILE_COMPRESSION false
/* When creating save state files, compress
* written data */
#define DEFAULT_SAVESTATE_FILE_COMPRESSION false

View File

@ -1614,6 +1614,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
SETTING_BOOL("savestate_auto_save", &settings->bools.savestate_auto_save, true, savestate_auto_save, false);
SETTING_BOOL("savestate_auto_load", &settings->bools.savestate_auto_load, true, savestate_auto_load, false);
SETTING_BOOL("savestate_thumbnail_enable", &settings->bools.savestate_thumbnail_enable, true, savestate_thumbnail_enable, false);
SETTING_BOOL("save_file_compression", &settings->bools.save_file_compression, true, DEFAULT_SAVE_FILE_COMPRESSION, false);
SETTING_BOOL("savestate_file_compression", &settings->bools.savestate_file_compression, true, DEFAULT_SAVESTATE_FILE_COMPRESSION, false);
SETTING_BOOL("history_list_enable", &settings->bools.history_list_enable, true, DEFAULT_HISTORY_LIST_ENABLE, false);
SETTING_BOOL("playlist_entry_rename", &settings->bools.playlist_entry_rename, true, DEFAULT_PLAYLIST_ENTRY_RENAME, false);

View File

@ -344,6 +344,7 @@ typedef struct settings
bool savestate_auto_save;
bool savestate_auto_load;
bool savestate_thumbnail_enable;
bool save_file_compression;
bool savestate_file_compression;
bool network_cmd_enable;
bool stdin_cmd_enable;

View File

@ -43,7 +43,7 @@ typedef struct content_ctx_info
bool content_load_ram_file(unsigned slot);
/* Save a RAM state from memory to disk. */
bool content_save_ram_file(unsigned slot);
bool content_save_ram_file(unsigned slot, bool compress);
/* Load a state from disk to memory. */
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);

View File

@ -1200,6 +1200,8 @@ MSG_HASH(MENU_ENUM_LABEL_SAVESTATE_AUTO_LOAD,
"savestate_auto_load")
MSG_HASH(MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE,
"savestate_thumbnails")
MSG_HASH(MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION,
"save_file_compression")
MSG_HASH(MENU_ENUM_LABEL_SAVESTATE_FILE_COMPRESSION,
"savestate_file_compression")
MSG_HASH(MENU_ENUM_LABEL_SAVESTATE_AUTO_SAVE,

View File

@ -2616,6 +2616,14 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE,
"Show thumbnails of save states inside the menu."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_SAVE_FILE_COMPRESSION,
"SaveRAM Compression"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_SAVE_FILE_COMPRESSION,
"Write non-volatile Save RAM files in an archived format. Dramatically reduces file size at the expense of (negligibly) increased saving/loading times. Note: Only applies to cores that enable saving via the standard libretro Save RAM interface."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_SAVESTATE_FILE_COMPRESSION,
"Savestate Compression"

View File

@ -381,6 +381,7 @@ default_sublabel_macro(action_bind_sublabel_perfcnt_enable, MENU_
default_sublabel_macro(action_bind_sublabel_savestate_auto_save, MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE)
default_sublabel_macro(action_bind_sublabel_savestate_auto_load, MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD)
default_sublabel_macro(action_bind_sublabel_savestate_thumbnail_enable, MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE)
default_sublabel_macro(action_bind_sublabel_save_file_compression, MENU_ENUM_SUBLABEL_SAVE_FILE_COMPRESSION)
default_sublabel_macro(action_bind_sublabel_savestate_file_compression, MENU_ENUM_SUBLABEL_SAVESTATE_FILE_COMPRESSION)
default_sublabel_macro(action_bind_sublabel_autosave_interval, MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL)
default_sublabel_macro(action_bind_sublabel_input_remap_binds_enable, MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE)
@ -2328,6 +2329,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_savestate_thumbnail_enable);
break;
case MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_save_file_compression);
break;
case MENU_ENUM_LABEL_SAVESTATE_FILE_COMPRESSION:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_savestate_file_compression);
break;

View File

@ -6855,6 +6855,7 @@ unsigned menu_displaylist_build_list(
{MENU_ENUM_LABEL_SAVESTATE_AUTO_SAVE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAVESTATE_AUTO_LOAD, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAVESTATE_FILE_COMPRESSION, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL},

View File

@ -8951,6 +8951,21 @@ static bool setting_append_list(
SD_FLAG_NONE);
#if defined(HAVE_ZLIB)
CONFIG_BOOL(
list, list_info,
&settings->bools.save_file_compression,
MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION,
MENU_ENUM_LABEL_VALUE_SAVE_FILE_COMPRESSION,
DEFAULT_SAVE_FILE_COMPRESSION,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE);
CONFIG_BOOL(
list, list_info,
&settings->bools.savestate_file_compression,

View File

@ -1607,6 +1607,7 @@ enum msg_hash_enums
MENU_LABEL(SAVESTATE_AUTO_SAVE),
MENU_LABEL(SAVESTATE_AUTO_LOAD),
MENU_LABEL(SAVESTATE_THUMBNAIL_ENABLE),
MENU_LABEL(SAVE_FILE_COMPRESSION),
MENU_LABEL(SAVESTATE_FILE_COMPRESSION),
MENU_LABEL(SUSPEND_SCREENSAVER_ENABLE),

View File

@ -31,6 +31,7 @@
#include <lists/string_list.h>
#include <streams/interface_stream.h>
#include <streams/file_stream.h>
#include <streams/rzip_stream.h>
#include <rthreads/rthreads.h>
#include <file/file_path.h>
#include <retro_miscellaneous.h>
@ -129,6 +130,7 @@ struct autosave
volatile bool quit;
size_t bufsize;
unsigned interval;
bool compress_files;
void *buffer;
const void *retro_buffer;
const char *path;
@ -163,15 +165,22 @@ static void autosave_thread(void *data)
if (differ)
{
intfstream_t *file = NULL;
/* Should probably deal with this more elegantly. */
RFILE *file = filestream_open(save->path,
RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (save->compress_files)
file = intfstream_open_rzip_file(save->path,
RETRO_VFS_FILE_ACCESS_WRITE);
else
file = intfstream_open_file(save->path,
RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (file)
{
filestream_write(file, save->buffer, save->bufsize);
filestream_flush(file);
filestream_close(file);
intfstream_write(file, save->buffer, save->bufsize);
intfstream_flush(file);
intfstream_close(file);
free(file);
}
}
@ -206,7 +215,7 @@ static void autosave_thread(void *data)
**/
static autosave_t *autosave_new(const char *path,
const void *data, size_t size,
unsigned interval)
unsigned interval, bool compress)
{
void *buf = NULL;
autosave_t *handle = (autosave_t*)malloc(sizeof(*handle));
@ -216,6 +225,7 @@ static autosave_t *autosave_new(const char *path,
handle->quit = false;
handle->bufsize = size;
handle->interval = interval;
handle->compress_files = compress;
handle->retro_buffer = data;
handle->path = path;
@ -268,6 +278,11 @@ bool autosave_init(void)
autosave_t **list = NULL;
settings_t *settings = config_get_ptr();
unsigned autosave_interval = settings->uints.autosave_interval;
#if defined(HAVE_ZLIB)
bool compress_files = settings->bools.save_file_compression;
#else
bool compress_files = false;
#endif
if (autosave_interval < 1 || !task_save_files)
return false;
@ -299,7 +314,8 @@ bool autosave_init(void)
auto_st = autosave_new(path,
mem_info.data,
mem_info.size,
autosave_interval);
autosave_interval,
compress_files);
if (!auto_st)
{
@ -1471,7 +1487,22 @@ bool content_load_ram_file(unsigned slot)
if (!content_get_memory(&mem_info, &ram, slot))
return false;
/* On first run of content, SRAM file will
* not exist. This is a common enough occurrence
* that we should check before attempting to
* invoke the relevant read_file() function */
if (string_is_empty(ram.path) ||
!path_is_valid(ram.path))
return false;
#if defined(HAVE_ZLIB)
/* Always use RZIP interface when reading SRAM
* files - this will automatically handle uncompressed
* data */
if (!rzipstream_read_file(ram.path, &buf, &rc))
#else
if (!filestream_read_file(ram.path, &buf, &rc))
#endif
return false;
if (rc > 0)
@ -1539,6 +1570,15 @@ static bool dump_to_file_desperate(const void *data,
free(application_data);
free(timebuf);
/* Fallback (emergency) saves are always
* uncompressed
* > If a regular save fails, then the host
* system is experiencing serious technical
* difficulties (most likely some kind of
* hardware failure)
* > In this case, we don't want to further
* complicate matters by introducing zlib
* compression overheads */
if (!filestream_write_file(path, data, size))
{
free(path);
@ -1558,10 +1598,11 @@ static bool dump_to_file_desperate(const void *data,
* Save a RAM state from memory to disk.
*
*/
bool content_save_ram_file(unsigned slot)
bool content_save_ram_file(unsigned slot, bool compress)
{
struct ram_type ram;
retro_ctx_memory_info_t mem_info;
bool write_success;
if (!content_get_memory(&mem_info, &ram, slot))
return false;
@ -1572,8 +1613,16 @@ bool content_save_ram_file(unsigned slot)
msg_hash_to_str(MSG_TO),
ram.path);
if (!filestream_write_file(
ram.path, mem_info.data, mem_info.size))
#if defined(HAVE_ZLIB)
if (compress)
write_success = rzipstream_write_file(
ram.path, mem_info.data, mem_info.size);
else
#endif
write_success = filestream_write_file(
ram.path, mem_info.data, mem_info.size);
if (!write_success)
{
RARCH_ERR("%s.\n",
msg_hash_to_str(MSG_FAILED_TO_SAVE_SRAM));
@ -1602,6 +1651,11 @@ bool event_save_files(bool is_sram_used)
unsigned i;
settings_t *settings = config_get_ptr();
const char *path_cheat_database = settings->paths.path_cheat_database;
#if defined(HAVE_ZLIB)
bool compress_files = settings->bools.save_file_compression;
#else
bool compress_files = false;
#endif
cheat_manager_save_game_specific_cheats(
path_cheat_database);
@ -1609,7 +1663,7 @@ bool event_save_files(bool is_sram_used)
return false;
for (i = 0; i < task_save_files->size; i++)
content_save_ram_file(i);
content_save_ram_file(i, compress_files);
return true;
}