diff --git a/config.def.h b/config.def.h index 21314eb899..a7662d1c7e 100644 --- a/config.def.h +++ b/config.def.h @@ -258,6 +258,18 @@ #endif #define DEFAULT_CHECK_FIRMWARE_BEFORE_LOADING false +/* Specifies whether to 'reload' (fork and quit) + * RetroArch when launching content with the + * currently loaded core + * > Only relevant on platforms without dynamic core + * loading support + * > Setting this to 'false' will decrease loading + * times when required core is already running, + * but may cause stability issues (if core misbehaves) */ +#ifndef HAVE_DYNAMIC +#define DEFAULT_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT true +#endif + /* Forcibly disable composition. * Only valid on Windows Vista/7/8 for now. */ #define DEFAULT_DISABLE_COMPOSITION false diff --git a/configuration.c b/configuration.c index 062085d892..ff32c26793 100644 --- a/configuration.c +++ b/configuration.c @@ -1422,6 +1422,9 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("input_descriptor_hide_unbound", &settings->bools.input_descriptor_hide_unbound, true, input_descriptor_hide_unbound, false); SETTING_BOOL("load_dummy_on_core_shutdown", &settings->bools.load_dummy_on_core_shutdown, true, DEFAULT_LOAD_DUMMY_ON_CORE_SHUTDOWN, false); SETTING_BOOL("check_firmware_before_loading", &settings->bools.check_firmware_before_loading, true, DEFAULT_CHECK_FIRMWARE_BEFORE_LOADING, false); +#ifndef HAVE_DYNAMIC + SETTING_BOOL("always_reload_core_on_run_content", &settings->bools.always_reload_core_on_run_content, true, DEFAULT_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, false); +#endif SETTING_BOOL("builtin_mediaplayer_enable", &settings->bools.multimedia_builtin_mediaplayer_enable, false, false /* TODO */, false); SETTING_BOOL("builtin_imageviewer_enable", &settings->bools.multimedia_builtin_imageviewer_enable, true, true, false); SETTING_BOOL("fps_show", &settings->bools.video_fps_show, true, DEFAULT_FPS_SHOW, false); diff --git a/configuration.h b/configuration.h index 3d21ae781e..015483155b 100644 --- a/configuration.h +++ b/configuration.h @@ -360,6 +360,9 @@ typedef struct settings bool network_remote_enable_user[MAX_USERS]; bool load_dummy_on_core_shutdown; bool check_firmware_before_loading; +#ifndef HAVE_DYNAMIC + bool always_reload_core_on_run_content; +#endif bool game_specific_options; bool auto_overrides_enable; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index fcd0a01617..9c6bbb63fa 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1088,6 +1088,12 @@ MSG_HASH( MENU_ENUM_LABEL_DUMMY_ON_CORE_SHUTDOWN, "dummy_on_core_shutdown" ) +#ifndef HAVE_DYNAMIC +MSG_HASH( + MENU_ENUM_LABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, + "always_reload_core_on_run_content" + ) +#endif MSG_HASH( MENU_ENUM_LABEL_DYNAMIC_WALLPAPER, "menu_dynamic_wallpaper_enable" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0fe0e0f121..1b82e626bf 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2716,6 +2716,16 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, "Check if all the required firmware is present before attempting to load content." ) +#ifndef HAVE_DYNAMIC +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, + "Always Reload Core on Run Content" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, + "Restart RetroArch when launching content, even when the requested core is already loaded. This may improve system stability, at the expense of increased loading times." + ) +#endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, "Allow Rotation" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index ca69167ec7..0a2f1db025 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -6437,10 +6437,7 @@ int action_ok_core_lock(const char *path, static int action_ok_core_delete(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - const char *core_path = label; - const char *core = NULL; - const char *loaded_core_path = NULL; - const char *loaded_core = NULL; + const char *core_path = label; if (string_is_empty(core_path)) return -1; @@ -6483,20 +6480,9 @@ static int action_ok_core_delete(const char *path, return 0; } - /* Get core file name */ - core = path_basename(core_path); - if (string_is_empty(core)) - return -1; - - /* Get loaded core file name */ - loaded_core_path = path_get(RARCH_PATH_CORE); - if (!string_is_empty(loaded_core_path)) - loaded_core = path_basename(loaded_core_path); - /* Check if core to be deleted is currently * loaded - if so, unload it */ - if (!string_is_empty(loaded_core) && - string_is_equal(core, loaded_core)) + if (rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path)) generic_action_ok_command(CMD_EVENT_UNLOAD_CORE); /* Delete core file */ diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index fb328a1a8d..aa6c93143f 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -327,6 +327,9 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_adaptive_vsync, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_allow_rotate, MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_dummy_on_core_shutdown, MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_dummy_check_missing_firmware, MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE) +#ifndef HAVE_DYNAMIC +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_always_reload_core_on_run_content, MENU_ENUM_SUBLABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT) +#endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_refresh_rate, MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_refresh_rate_polled, MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_POLLED) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_enable, MENU_ENUM_SUBLABEL_AUDIO_ENABLE) @@ -3059,6 +3062,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_CHECK_FOR_MISSING_FIRMWARE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_dummy_check_missing_firmware); break; +#ifndef HAVE_DYNAMIC + case MENU_ENUM_LABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_always_reload_core_on_run_content); + break; +#endif case MENU_ENUM_LABEL_VIDEO_ALLOW_ROTATE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_allow_rotate); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 3d4dff4ea4..e32a626e99 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -7930,6 +7930,9 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_DUMMY_ON_CORE_SHUTDOWN, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_CHECK_FOR_MISSING_FIRMWARE, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_VIDEO_ALLOW_ROTATE, PARSE_ONLY_BOOL}, +#ifndef HAVE_DYNAMIC + {MENU_ENUM_LABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, PARSE_ONLY_BOOL}, +#endif }; for (i = 0; i < ARRAY_SIZE(build_list); i++) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 08cd8789ce..53989c10de 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -8587,8 +8587,11 @@ static bool setting_append_list( case SETTINGS_LIST_CORE: { unsigned i, listing = 0; +#ifndef HAVE_DYNAMIC + struct bool_entry bool_entries[7]; +#else struct bool_entry bool_entries[6]; - +#endif START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS), parent_group); MENU_SETTINGS_LIST_CURRENT_ADD_ENUM_IDX_PTR(list, list_info, MENU_ENUM_LABEL_CORE_SETTINGS); @@ -8642,6 +8645,14 @@ static bool setting_append_list( bool_entries[listing].flags = SD_FLAG_ADVANCED; listing++; +#ifndef HAVE_DYNAMIC + bool_entries[listing].target = &settings->bools.always_reload_core_on_run_content; + bool_entries[listing].name_enum_idx = MENU_ENUM_LABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT; + bool_entries[listing].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT; + bool_entries[listing].default_value = DEFAULT_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT; + bool_entries[listing].flags = SD_FLAG_ADVANCED; + listing++; +#endif for (i = 0; i < ARRAY_SIZE(bool_entries); i++) { CONFIG_BOOL( diff --git a/msg_hash.h b/msg_hash.h index 8acf79197f..179b5c37c3 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1954,6 +1954,9 @@ enum msg_hash_enums MENU_LABEL(DUMMY_ON_CORE_SHUTDOWN), MENU_LABEL(CHECK_FOR_MISSING_FIRMWARE), +#ifndef HAVE_DYNAMIC + MENU_LABEL(ALWAYS_RELOAD_CORE_ON_RUN_CONTENT), +#endif MENU_LABEL(DETECT_CORE_LIST_OK_CURRENT_CORE), MENU_LABEL(DETECT_CORE_LIST_OK), diff --git a/retroarch.c b/retroarch.c index 894fd03e5e..09189b728e 100644 --- a/retroarch.c +++ b/retroarch.c @@ -36879,6 +36879,35 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) #endif case RARCH_CTL_IS_DUMMY_CORE: return (p_rarch->current_core_type == CORE_TYPE_DUMMY); + case RARCH_CTL_IS_CORE_LOADED: + { + const char *core_path = (const char*)data; + const char *core_file = NULL; + const char *loaded_core_path = NULL; + const char *loaded_core_file = NULL; + + if (string_is_empty(core_path)) + return false; + + /* Get core file name */ + core_file = path_basename(core_path); + if (string_is_empty(core_file)) + return false; + + /* Get loaded core file name */ + loaded_core_path = path_get(RARCH_PATH_CORE); + if (!string_is_empty(loaded_core_path)) + loaded_core_file = path_basename(loaded_core_path); + + /* Check whether specified core and currently + * loaded core are the same */ + if (!string_is_empty(loaded_core_file) && + string_is_equal(core_file, loaded_core_file)) + return true; + + return false; + } + break; case RARCH_CTL_HAS_SET_USERNAME: return p_rarch->has_set_username; case RARCH_CTL_IS_INITED: diff --git a/retroarch.h b/retroarch.h index 33e72eeb05..95671ba67d 100644 --- a/retroarch.h +++ b/retroarch.h @@ -88,6 +88,7 @@ enum rarch_ctl_state RARCH_CTL_IS_INITED, RARCH_CTL_IS_DUMMY_CORE, + RARCH_CTL_IS_CORE_LOADED, RARCH_CTL_IS_BPS_PREF, RARCH_CTL_UNSET_BPS_PREF, diff --git a/tasks/task_content.c b/tasks/task_content.c index 26838b8747..6ccbfaa87f 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -1445,7 +1445,6 @@ static bool command_event_cmd_exec( content_info.argc = 0; content_info.argv = NULL; content_info.args = NULL; - content_info.environ_get = NULL; content_info.environ_get = menu_content_environment_get; #endif @@ -1635,6 +1634,9 @@ bool task_push_load_content_from_playlist_from_menu( settings_t *settings = config_get_ptr(); rarch_system_info_t *sys_info = runloop_get_system_info(); const char *path_dir_system = settings->paths.directory_system; +#ifndef HAVE_DYNAMIC + bool force_core_reload = settings->bools.always_reload_core_on_run_content; +#endif content_ctx.check_firmware_before_loading = settings->bools.check_firmware_before_loading; #ifdef HAVE_PATCH @@ -1674,19 +1676,73 @@ bool task_push_load_content_from_playlist_from_menu( if (!string_is_empty(path_dir_system)) content_ctx.directory_system = strdup(path_dir_system); - path_set(RARCH_PATH_CORE, core_path); - /* Is content required by this core? */ if (fullpath) sys_info->load_no_content = false; else sys_info->load_no_content = true; - /* On targets that have no dynamic core loading support, we'd - * execute the new core from this point. If this returns false, - * we assume we can dynamically load the core. */ - if (!command_event_cmd_exec(p_content, - fullpath, &content_ctx, CONTENT_MODE_LOAD_NONE, &error_string)) +#ifndef HAVE_DYNAMIC + /* Check whether specified core is already loaded + * > If so, content can be launched directly with + * the currently loaded core */ + if (!force_core_reload && + rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path)) + { + if (!content_info->environ_get) + content_info->environ_get = menu_content_environment_get; + + /* Register content path */ + path_clear(RARCH_PATH_CONTENT); + if (!string_is_empty(fullpath)) + path_set(RARCH_PATH_CONTENT, fullpath); + + /* Load content */ + ret = content_load(content_info, p_content); + + if (!ret) + goto end; + + /* Update content history */ + task_push_to_history_list(p_content, true, false, false); + + goto end; + } +#endif + + /* Specified core is not loaded + * > Load it */ + path_set(RARCH_PATH_CORE, core_path); +#ifdef HAVE_DYNAMIC + command_event(CMD_EVENT_LOAD_CORE, NULL); +#endif + + /* Load content + * > On targets that do not support dynamic core loading, + * command_event_cmd_exec() will fork a new instance */ + ret = command_event_cmd_exec(p_content, + fullpath, &content_ctx, false, &error_string); + + if (!ret) + goto end; + +#ifdef HAVE_COCOATOUCH + /* This seems to be needed for iOS for some reason + * to show the quick menu after the menu is shown */ + menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL); +#endif + +#ifndef HAVE_DYNAMIC + /* No dynamic core loading support: if we reach + * this point then a new instance has been + * forked - have to shut down this one */ + rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); + retroarch_menu_running_finished(true); +#endif + +end: + /* Handle load content failure */ + if (!ret) { if (error_string) { @@ -1696,25 +1752,8 @@ bool task_push_load_content_from_playlist_from_menu( } retroarch_menu_running(); - - ret = false; - goto end; } - /* Load core */ -#ifdef HAVE_DYNAMIC - command_event(CMD_EVENT_LOAD_CORE, NULL); -#ifdef HAVE_COCOATOUCH - /* This seems to be needed for iOS for some reason to show the - * quick menu after the menu is shown */ - menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL); -#endif -#else - rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); - retroarch_menu_running_finished(true); -#endif - -end: if (content_ctx.name_ips) free(content_ctx.name_ips); if (content_ctx.name_bps) @@ -1873,6 +1912,19 @@ bool task_push_load_content_with_new_core_from_menu( settings_t *settings = config_get_ptr(); bool check_firmware_before_loading = settings->bools.check_firmware_before_loading; const char *path_dir_system = settings->paths.directory_system; +#ifndef HAVE_DYNAMIC + bool force_core_reload = settings->bools.always_reload_core_on_run_content; + + /* Check whether specified core is already loaded + * > If so, we can skip loading the core and + * just load the content directly */ + if (!force_core_reload && + (type == CORE_TYPE_PLAIN) && + rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path)) + return task_push_load_content_with_core_from_menu( + fullpath, content_info, + type, cb, user_data); +#endif content_ctx.check_firmware_before_loading = check_firmware_before_loading; #ifdef HAVE_PATCH diff --git a/tasks/task_core_backup.c b/tasks/task_core_backup.c index 30efbf9186..4d7c745589 100644 --- a/tasks/task_core_backup.c +++ b/tasks/task_core_backup.c @@ -646,41 +646,6 @@ error: /* Core Restore */ /****************/ -/* Unloads core if it is currently loaded - * > Returns true if core was unloaded */ -static bool task_core_restore_unload_core(const char *core_path) -{ - const char *core_filename = NULL; - const char *loaded_core_path = NULL; - const char *loaded_core_filename = NULL; - - if (string_is_empty(core_path)) - return false; - - /* Get core file name */ - core_filename = path_basename(core_path); - if (string_is_empty(core_filename)) - return false; - - /* Get loaded core file name */ - loaded_core_path = path_get(RARCH_PATH_CORE); - if (string_is_empty(loaded_core_path)) - return false; - - loaded_core_filename = path_basename(loaded_core_path); - if (string_is_empty(loaded_core_filename)) - return false; - - /* Check if whether file names match */ - if (string_is_equal(core_filename, loaded_core_filename)) - { - command_event(CMD_EVENT_UNLOAD_CORE, NULL); - return true; - } - - return false; -} - static void cb_task_core_restore( retro_task_t *task, void *task_data, void *user_data, const char *err) @@ -1086,7 +1051,13 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro, /* If core to be restored is currently loaded, must * unload it before pushing the task */ - *core_loaded = task_core_restore_unload_core(core_path); + if (rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path)) + { + command_event(CMD_EVENT_UNLOAD_CORE, NULL); + *core_loaded = true; + } + else + *core_loaded = false; /* Push task */ task_queue_push(task);