diff --git a/Makefile.common b/Makefile.common index f7842b2ee7..2ca5dacddb 100644 --- a/Makefile.common +++ b/Makefile.common @@ -268,7 +268,6 @@ ifeq ($(HAVE_RUNAHEAD), 1) runahead/dirty_input.o \ runahead/mem_util.o \ runahead/mylist.o \ - runahead/run_ahead.o \ runahead/secondary_core.o endif diff --git a/core.h b/core.h index 6a2ff7f3a3..c7e47b7740 100644 --- a/core.h +++ b/core.h @@ -172,9 +172,6 @@ bool core_set_poll_type(unsigned *type); /* Runs the core for one frame. */ bool core_run(void); -/* Runs the core for one frame, but does not trigger any input polling */ -bool core_run_no_input_polling(void); - bool core_init(void); bool core_deinit(void *data); diff --git a/griffin/griffin.c b/griffin/griffin.c index 3c0ab917f8..fd28cc9a1d 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1368,7 +1368,6 @@ MENU #ifdef HAVE_RUNAHEAD #include "../runahead/mem_util.c" #include "../runahead/secondary_core.c" -#include "../runahead/run_ahead.c" #include "../runahead/copy_load_info.c" #include "../runahead/dirty_input.c" #include "../runahead/mylist.c" diff --git a/input/input_driver.h b/input/input_driver.h index 08fba4e19a..70856e7868 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -294,13 +294,6 @@ float input_sensor_get_input(unsigned port, unsigned id); } \ } -/** - * input_poll: - * - * Input polling callback function. - **/ -void input_poll(void); - /** * input_state: * @port : user number. diff --git a/retroarch.c b/retroarch.c index cb9dc871c5..d469976c01 100644 --- a/retroarch.c +++ b/retroarch.c @@ -163,7 +163,9 @@ #include "retroarch.h" #ifdef HAVE_RUNAHEAD +#include "runahead/dirty_input.h" #include "runahead/copy_load_info.h" +#include "runahead/mylist.h" #include "runahead/secondary_core.h" #include "runahead/run_ahead.h" #endif @@ -1488,6 +1490,20 @@ void streaming_set_state(bool state) streaming_enable = state; } +bool video_driver_gpu_record_init(unsigned size) +{ + video_driver_record_gpu_buffer = (uint8_t*)malloc(size); + if (!video_driver_record_gpu_buffer) + return false; + return true; +} + +void video_driver_gpu_record_deinit(void) +{ + free(video_driver_record_gpu_buffer); + video_driver_record_gpu_buffer = NULL; +} + /** * recording_init: * @@ -2405,7 +2421,7 @@ float input_sensor_get_input(unsigned port, unsigned id) * * Input polling callback function. **/ -void input_poll(void) +static void input_poll(void) { size_t i; settings_t *settings = configuration_settings; @@ -7236,26 +7252,11 @@ void audio_driver_frame_is_reverse(void) runloop_slowmotion); } -void audio_driver_suspend(void) -{ - audio_suspended = true; -} - bool audio_driver_is_suspended(void) { return audio_suspended; } -void audio_driver_resume(void) -{ - audio_suspended = false; -} - -void audio_driver_set_active(void) -{ - audio_driver_active = true; -} - bool audio_driver_is_active(void) { return audio_driver_active; @@ -8956,35 +8957,11 @@ bool video_driver_is_video_cache_context_ack(void) return video_driver_cache_context_ack; } -void video_driver_set_active(void) -{ - video_driver_active = true; -} - -void video_driver_unset_active(void) -{ - video_driver_active = false; -} - bool video_driver_is_active(void) { return video_driver_active; } -bool video_driver_gpu_record_init(unsigned size) -{ - video_driver_record_gpu_buffer = (uint8_t*)malloc(size); - if (!video_driver_record_gpu_buffer) - return false; - return true; -} - -void video_driver_gpu_record_deinit(void) -{ - free(video_driver_record_gpu_buffer); - video_driver_record_gpu_buffer = NULL; -} - bool video_driver_get_current_software_framebuffer( struct retro_framebuffer *fb) { @@ -11672,6 +11649,447 @@ bool driver_ctl(enum driver_ctl_state state, void *data) return true; } +/* Runahead */ + +static size_t runahead_save_state_size = 0; + +static bool runahead_save_state_size_known = false; +static bool request_fast_savestate = false; +static bool hard_disable_audio = false; + +/* Save State List for Run Ahead */ +static MyList *runahead_save_state_list = NULL; + +static void *runahead_save_state_alloc(void) +{ + retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*) + malloc(sizeof(retro_ctx_serialize_info_t)); + + if (!savestate) + return NULL; + + savestate->data = NULL; + savestate->data_const = NULL; + savestate->size = 0; + + if (runahead_save_state_size > 0 && runahead_save_state_size_known) + { + savestate->data = malloc(runahead_save_state_size); + savestate->data_const = savestate->data; + savestate->size = runahead_save_state_size; + } + + return savestate; +} + +static void runahead_save_state_free(void *data) +{ + retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)data; + if (!savestate) + return; + free(savestate->data); + free(savestate); +} + +static void runahead_save_state_list_init(size_t saveStateSize) +{ + runahead_save_state_size = saveStateSize; + runahead_save_state_size_known = true; + mylist_create(&runahead_save_state_list, 16, + runahead_save_state_alloc, runahead_save_state_free); +} + +static void runahead_save_state_list_destroy(void) +{ + mylist_destroy(&runahead_save_state_list); +} + +#if 0 +static void runahead_save_state_list_rotate(void) +{ + unsigned i; + void *element; + void *firstElement = runahead_save_state_list->data[0]; + for (i = 1; i < runahead_save_state_list->size; i++) + runahead_save_state_list->data[i - 1] = + runahead_save_state_list->data[i]; + runahead_save_state_list->data[runahead_save_state_list->size - 1] = + firstElement; +} +#endif + +/* Hooks - Hooks to cleanup, and add dirty input hooks */ + +static function_t originalRetroDeinit = NULL; +static function_t originalRetroUnload = NULL; + +extern struct retro_core_t current_core; +extern struct retro_callbacks retro_ctx; + +static void runahead_remove_hooks(void) +{ + if (originalRetroDeinit) + { + current_core.retro_deinit = originalRetroDeinit; + originalRetroDeinit = NULL; + } + + if (originalRetroUnload) + { + current_core.retro_unload_game = originalRetroUnload; + originalRetroUnload = NULL; + } + remove_input_state_hook(); +} + +static bool runahead_video_driver_is_active = true; +static bool runahead_available = true; +static bool runahead_secondary_core_available = true; +static bool runahead_force_input_dirty = true; +static uint64_t runahead_last_frame_count = 0; + +static void runahead_clear_variables(void) +{ + runahead_save_state_size = 0; + runahead_save_state_size_known = false; + runahead_video_driver_is_active = true; + runahead_available = true; + runahead_secondary_core_available = true; + runahead_force_input_dirty = true; + runahead_last_frame_count = 0; +} + +static void runahead_destroy(void) +{ + runahead_save_state_list_destroy(); + runahead_remove_hooks(); + runahead_clear_variables(); +} + +static void unload_hook(void) +{ + runahead_remove_hooks(); + runahead_destroy(); + secondary_core_destroy(); + if (current_core.retro_unload_game) + current_core.retro_unload_game(); +} + +static void runahead_deinit_hook(void) +{ + runahead_remove_hooks(); + runahead_destroy(); + secondary_core_destroy(); + if (current_core.retro_deinit) + current_core.retro_deinit(); +} + +static void runahead_add_hooks(void) +{ + if (!originalRetroDeinit) + { + originalRetroDeinit = current_core.retro_deinit; + current_core.retro_deinit = runahead_deinit_hook; + } + + if (!originalRetroUnload) + { + originalRetroUnload = current_core.retro_unload_game; + current_core.retro_unload_game = unload_hook; + } + add_input_state_hook(); +} + +/* Runahead Code */ + +static void runahead_error(void) +{ + runahead_available = false; + runahead_save_state_list_destroy(); + runahead_remove_hooks(); + runahead_save_state_size = 0; + runahead_save_state_size_known = true; +} + + +static bool runahead_create(void) +{ + /* get savestate size and allocate buffer */ + retro_ctx_size_info_t info; + request_fast_savestate = true; + core_serialize_size(&info); + request_fast_savestate = false; + + runahead_save_state_list_init(info.size); + runahead_video_driver_is_active = video_driver_is_active(); + + if (runahead_save_state_size == 0 || !runahead_save_state_size_known) + { + runahead_error(); + return false; + } + + runahead_add_hooks(); + runahead_force_input_dirty = true; + mylist_resize(runahead_save_state_list, 1, true); + return true; +} + +static bool runahead_save_state(void) +{ + bool okay = false; + retro_ctx_serialize_info_t *serialize_info; + if (!runahead_save_state_list) + return false; + serialize_info = + (retro_ctx_serialize_info_t*)runahead_save_state_list->data[0]; + request_fast_savestate = true; + okay = core_serialize(serialize_info); + request_fast_savestate = false; + + if (okay) + return true; + + runahead_error(); + return false; +} + +static bool runahead_load_state(void) +{ + bool okay = false; + retro_ctx_serialize_info_t *serialize_info = (retro_ctx_serialize_info_t*) + runahead_save_state_list->data[0]; + bool last_dirty = input_is_dirty; + + request_fast_savestate = true; + /* calling core_unserialize has side effects with + * netplay (it triggers transmitting your save state) + call retro_unserialize directly from the core instead */ + okay = current_core.retro_unserialize( + serialize_info->data_const, serialize_info->size); + + request_fast_savestate = false; + input_is_dirty = last_dirty; + + if (!okay) + runahead_error(); + + return okay; +} + +#if HAVE_DYNAMIC +static bool runahead_load_state_secondary(void) +{ + bool okay = false; + retro_ctx_serialize_info_t *serialize_info = + (retro_ctx_serialize_info_t*)runahead_save_state_list->data[0]; + + request_fast_savestate = true; + okay = secondary_core_deserialize( + serialize_info->data_const, (int)serialize_info->size); + request_fast_savestate = false; + + if (!okay) + { + runahead_secondary_core_available = false; + runahead_error(); + return false; + } + + return true; +} + +static bool runahead_run_secondary(void) +{ + if (!secondary_core_run_use_last_input()) + { + runahead_secondary_core_available = false; + return false; + } + return true; +} +#endif + +static void runahead_resume_video(void) +{ + if (runahead_video_driver_is_active) + video_driver_active = true; + else + video_driver_active = false; +} + +static void retro_input_poll_null(void); + +static bool runahead_core_run_use_last_input(void) +{ + retro_input_poll_t old_poll_function = retro_ctx.poll_cb; + retro_input_state_t old_input_function = retro_ctx.state_cb; + + retro_ctx.poll_cb = retro_input_poll_null; + retro_ctx.state_cb = input_state_get_last; + + current_core.retro_set_input_poll(retro_ctx.poll_cb); + current_core.retro_set_input_state(retro_ctx.state_cb); + + current_core.retro_run(); + + retro_ctx.poll_cb = old_poll_function; + retro_ctx.state_cb = old_input_function; + + current_core.retro_set_input_poll(retro_ctx.poll_cb); + current_core.retro_set_input_state(retro_ctx.state_cb); + + return true; +} + +static void run_ahead(int runahead_count, bool useSecondary) +{ + int frame_number = 0; + bool last_frame = false; + bool suspended_frame = false; +#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB) + const bool have_dynamic = true; +#else + const bool have_dynamic = false; +#endif + uint64_t frame_count = video_driver_frame_count; + + if (runahead_count <= 0 || !runahead_available) + { + core_run(); + runahead_force_input_dirty = true; + return; + } + + if (!runahead_save_state_size_known) + { + if (!runahead_create()) + { + settings_t *settings = config_get_ptr(); + if (!settings->bools.run_ahead_hide_warnings) + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES), 0, 2 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + core_run(); + runahead_force_input_dirty = true; + return; + } + } + + /* Check for GUI */ + /* Hack: If we were in the GUI, force a resync. */ + if (frame_count != runahead_last_frame_count + 1) + runahead_force_input_dirty = true; + + runahead_last_frame_count = frame_count; + + if (!useSecondary || !have_dynamic || !runahead_secondary_core_available) + { + /* TODO: multiple savestates for higher performance + * when not using secondary core */ + for (frame_number = 0; frame_number <= runahead_count; frame_number++) + { + last_frame = frame_number == runahead_count; + suspended_frame = !last_frame; + + if (suspended_frame) + { + audio_suspended = true; + video_driver_active = false; + } + + if (frame_number == 0) + core_run(); + else + runahead_core_run_use_last_input(); + + if (suspended_frame) + { + runahead_resume_video(); + audio_suspended = false; + } + + if (frame_number == 0) + { + if (!runahead_save_state()) + { + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + return; + } + } + + if (last_frame) + { + if (!runahead_load_state()) + { + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + return; + } + } + } + } + else + { +#if HAVE_DYNAMIC + if (!secondary_core_ensure_exists()) + { + runahead_secondary_core_available = false; + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + core_run(); + runahead_force_input_dirty = true; + return; + } + + /* run main core with video suspended */ + video_driver_active = false; + core_run(); + runahead_resume_video(); + + if (input_is_dirty || runahead_force_input_dirty) + { + input_is_dirty = false; + + if (!runahead_save_state()) + { + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + return; + } + + if (!runahead_load_state_secondary()) + { + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + return; + } + + for (frame_number = 0; frame_number < runahead_count - 1; frame_number++) + { + video_driver_active = false; + audio_suspended = true; + hard_disable_audio = true; + runahead_run_secondary(); + hard_disable_audio = false; + audio_suspended = false; + runahead_resume_video(); + } + } + audio_suspended = true; + hard_disable_audio = true; + runahead_run_secondary(); + hard_disable_audio = false; + audio_suspended = false; +#endif + } + runahead_force_input_dirty = false; +} + +bool want_fast_savestate(void) +{ + return request_fast_savestate; +} + +bool get_hard_disable_audio(void) +{ + return hard_disable_audio; +} + void rarch_core_runtime_tick(void) { struct retro_system_av_info *av_info = &video_driver_av_info; @@ -12750,7 +13168,7 @@ bool retroarch_main_init(int argc, char *argv[]) char log_file_name[128]; #endif - video_driver_set_active(); + video_driver_active = true; audio_driver_active = true; if (setjmp(error_sjlj_context) > 0) @@ -13021,7 +13439,6 @@ static void runloop_task_msg_queue_push( runloop_msg_queue_push(msg, prio, duration, flush, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } - bool rarch_ctl(enum rarch_ctl_state state, void *data) { static bool has_set_username = false; @@ -13140,7 +13557,7 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) sthread_tls_create(&rarch_tls); sthread_tls_set(&rarch_tls, MAGIC_POINTER); #endif - video_driver_set_active(); + video_driver_active = true; audio_driver_active = true; { uint8_t i; @@ -16712,12 +17129,6 @@ bool core_run(void) return true; } -bool core_run_no_input_polling(void) -{ - current_core.retro_run(); - return true; -} - static bool core_verify_api_version(void) { unsigned api_version = current_core.retro_api_version(); diff --git a/retroarch.h b/retroarch.h index b88abd47d1..86a1933d43 100644 --- a/retroarch.h +++ b/retroarch.h @@ -556,14 +556,8 @@ typedef struct audio_driver size_t (*buffer_size)(void *data); } audio_driver_t; -void audio_driver_suspend(void); - bool audio_driver_is_suspended(void); -void audio_driver_resume(void); - -void audio_driver_set_active(void); - bool audio_driver_is_active(void); bool audio_driver_enable_callback(void); @@ -1669,23 +1663,33 @@ void video_driver_load_settings(config_file_t *conf); void video_driver_save_settings(config_file_t *conf); bool video_driver_is_hw_context(void); struct retro_hw_render_callback *video_driver_get_hw_context(void); + const struct retro_hw_render_context_negotiation_interface *video_driver_get_context_negotiation_interface(void); + void video_driver_set_context_negotiation_interface(const struct retro_hw_render_context_negotiation_interface *iface); -bool video_driver_is_video_cache_context(void); -void video_driver_set_video_cache_context_ack(void); -bool video_driver_is_video_cache_context_ack(void); -void video_driver_set_active(void); -void video_driver_unset_active(void); -bool video_driver_is_active(void); + bool video_driver_gpu_record_init(unsigned size); + void video_driver_gpu_record_deinit(void); + +bool video_driver_is_video_cache_context(void); + +void video_driver_set_video_cache_context_ack(void); + +bool video_driver_is_video_cache_context_ack(void); + +bool video_driver_is_active(void); + bool video_driver_get_current_software_framebuffer(struct retro_framebuffer *fb); + bool video_driver_get_hw_render_interface(const struct retro_hw_render_interface **iface); + bool video_driver_get_viewport_info(struct video_viewport *viewport); + void video_driver_set_title_buf(void); #if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) @@ -1917,9 +1921,6 @@ bool *video_driver_get_threaded(void); void video_driver_set_threaded(bool val); -void video_driver_get_status(uint64_t *frame_count, bool * is_alive, - bool *is_focused); - /** * video_context_driver_init_first: * @data : Input data. diff --git a/runahead/run_ahead.c b/runahead/run_ahead.c deleted file mode 100644 index 0501a48664..0000000000 --- a/runahead/run_ahead.c +++ /dev/null @@ -1,490 +0,0 @@ -#include -#include -#include - -#include - -#include "dirty_input.h" -#include "mylist.h" -#include "secondary_core.h" -#include "run_ahead.h" - -#include "../core.h" -#include "../dynamic.h" -#include "../configuration.h" -#include "../retroarch.h" - -static size_t runahead_save_state_size = 0; - -static bool runahead_save_state_size_known = false; -static bool request_fast_savestate = false; -static bool hard_disable_audio = false; - -/* Save State List for Run Ahead */ -static MyList *runahead_save_state_list = NULL; - -static void *runahead_save_state_alloc(void) -{ - retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*) - malloc(sizeof(retro_ctx_serialize_info_t)); - - if (!savestate) - return NULL; - - savestate->data = NULL; - savestate->data_const = NULL; - savestate->size = 0; - - if (runahead_save_state_size > 0 && runahead_save_state_size_known) - { - savestate->data = malloc(runahead_save_state_size); - savestate->data_const = savestate->data; - savestate->size = runahead_save_state_size; - } - - return savestate; -} - -static void runahead_save_state_free(void *data) -{ - retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)data; - if (!savestate) - return; - free(savestate->data); - free(savestate); -} - -static void runahead_save_state_list_init(size_t saveStateSize) -{ - runahead_save_state_size = saveStateSize; - runahead_save_state_size_known = true; - mylist_create(&runahead_save_state_list, 16, - runahead_save_state_alloc, runahead_save_state_free); -} - -static void runahead_save_state_list_destroy(void) -{ - mylist_destroy(&runahead_save_state_list); -} - -#if 0 -static void runahead_save_state_list_rotate(void) -{ - int i; - void *element; - void *firstElement; - firstElement = runahead_save_state_list->data[0]; - for (i = 1; i < runahead_save_state_list->size; i++) - runahead_save_state_list->data[i - 1] = - runahead_save_state_list->data[i]; - runahead_save_state_list->data[runahead_save_state_list->size - 1] = - firstElement; -} -#endif - -/* Hooks - Hooks to cleanup, and add dirty input hooks */ - -static function_t originalRetroDeinit = NULL; -static function_t originalRetroUnload = NULL; - -extern struct retro_core_t current_core; -extern struct retro_callbacks retro_ctx; - -static void runahead_remove_hooks(void) -{ - if (originalRetroDeinit) - { - current_core.retro_deinit = originalRetroDeinit; - originalRetroDeinit = NULL; - } - - if (originalRetroUnload) - { - current_core.retro_unload_game = originalRetroUnload; - originalRetroUnload = NULL; - } - remove_input_state_hook(); -} - -static void unload_hook(void) -{ - runahead_remove_hooks(); - runahead_destroy(); - secondary_core_destroy(); - if (current_core.retro_unload_game) - current_core.retro_unload_game(); -} - -static void deinit_hook(void) -{ - runahead_remove_hooks(); - runahead_destroy(); - secondary_core_destroy(); - if (current_core.retro_deinit) - current_core.retro_deinit(); -} - -static void add_hooks(void) -{ - if (!originalRetroDeinit) - { - originalRetroDeinit = current_core.retro_deinit; - current_core.retro_deinit = deinit_hook; - } - - if (!originalRetroUnload) - { - originalRetroUnload = current_core.retro_unload_game; - current_core.retro_unload_game = unload_hook; - } - add_input_state_hook(); -} - -/* Runahead Code */ - -static bool runahead_video_driver_is_active = true; -static bool runahead_available = true; -static bool runahead_secondary_core_available = true; -static bool runahead_force_input_dirty = true; -static uint64_t runahead_last_frame_count = 0; - -static void runahead_clear_variables(void) -{ - runahead_save_state_size = 0; - runahead_save_state_size_known = false; - runahead_video_driver_is_active = true; - runahead_available = true; - runahead_secondary_core_available = true; - runahead_force_input_dirty = true; - runahead_last_frame_count = 0; -} - -static uint64_t runahead_get_frame_count(void) -{ - bool is_alive, is_focused = false; - uint64_t frame_count = 0; - video_driver_get_status(&frame_count, &is_alive, &is_focused); - return frame_count; -} - -static void runahead_check_for_gui(void) -{ - /* Hack: If we were in the GUI, force a resync. */ - uint64_t frame_count = runahead_get_frame_count(); - - if (frame_count != runahead_last_frame_count + 1) - runahead_force_input_dirty = true; - - runahead_last_frame_count = frame_count; -} - -static void runahead_error(void) -{ - runahead_available = false; - runahead_save_state_list_destroy(); - runahead_remove_hooks(); - runahead_save_state_size = 0; - runahead_save_state_size_known = true; -} - - -static bool runahead_create(void) -{ - /* get savestate size and allocate buffer */ - retro_ctx_size_info_t info; - request_fast_savestate = true; - core_serialize_size(&info); - request_fast_savestate = false; - - runahead_save_state_list_init(info.size); - runahead_video_driver_is_active = video_driver_is_active(); - - if (runahead_save_state_size == 0 || !runahead_save_state_size_known) - { - runahead_error(); - return false; - } - - add_hooks(); - runahead_force_input_dirty = true; - mylist_resize(runahead_save_state_list, 1, true); - return true; -} - -static bool runahead_save_state(void) -{ - bool okay = false; - retro_ctx_serialize_info_t *serialize_info; - if (!runahead_save_state_list) - return false; - serialize_info = - (retro_ctx_serialize_info_t*)runahead_save_state_list->data[0]; - request_fast_savestate = true; - okay = core_serialize(serialize_info); - request_fast_savestate = false; - - if (okay) - return true; - - runahead_error(); - return false; -} - -static bool runahead_load_state(void) -{ - bool okay = false; - retro_ctx_serialize_info_t *serialize_info = (retro_ctx_serialize_info_t*) - runahead_save_state_list->data[0]; - bool last_dirty = input_is_dirty; - - request_fast_savestate = true; - /* calling core_unserialize has side effects with - * netplay (it triggers transmitting your save state) - call retro_unserialize directly from the core instead */ - okay = current_core.retro_unserialize( - serialize_info->data_const, serialize_info->size); - - request_fast_savestate = false; - input_is_dirty = last_dirty; - - if (!okay) - runahead_error(); - - return okay; -} - -#if HAVE_DYNAMIC -static bool runahead_load_state_secondary(void) -{ - bool okay = false; - retro_ctx_serialize_info_t *serialize_info = - (retro_ctx_serialize_info_t*)runahead_save_state_list->data[0]; - - request_fast_savestate = true; - okay = secondary_core_deserialize( - serialize_info->data_const, (int)serialize_info->size); - request_fast_savestate = false; - - if (!okay) - { - runahead_secondary_core_available = false; - runahead_error(); - return false; - } - - return true; -} - -static bool runahead_run_secondary(void) -{ - if (!secondary_core_run_use_last_input()) - { - runahead_secondary_core_available = false; - return false; - } - return true; -} -#endif - -static void runahead_suspend_audio(void) -{ - audio_driver_suspend(); -} - -static void runahead_resume_audio(void) -{ - audio_driver_resume(); -} - -static void runahead_suspend_video(void) -{ - video_driver_unset_active(); -} - -static void runahead_resume_video(void) -{ - if (runahead_video_driver_is_active) - video_driver_set_active(); - else - video_driver_unset_active(); -} - -static void runahead_input_poll_null(void) -{ -} - -static bool runahead_core_run_use_last_input(void) -{ - extern struct retro_callbacks retro_ctx; - extern struct retro_core_t current_core; - - retro_input_poll_t old_poll_function = retro_ctx.poll_cb; - retro_input_state_t old_input_function = retro_ctx.state_cb; - - retro_ctx.poll_cb = runahead_input_poll_null; - retro_ctx.state_cb = input_state_get_last; - - current_core.retro_set_input_poll(retro_ctx.poll_cb); - current_core.retro_set_input_state(retro_ctx.state_cb); - - current_core.retro_run(); - - retro_ctx.poll_cb = old_poll_function; - retro_ctx.state_cb = old_input_function; - - current_core.retro_set_input_poll(retro_ctx.poll_cb); - current_core.retro_set_input_state(retro_ctx.state_cb); - - return true; -} - -void run_ahead(int runahead_count, bool useSecondary) -{ - int frame_number = 0; - bool last_frame = false; - bool suspended_frame = false; -#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB) - const bool have_dynamic = true; -#else - const bool have_dynamic = false; -#endif - - if (runahead_count <= 0 || !runahead_available) - { - core_run(); - runahead_force_input_dirty = true; - return; - } - - if (!runahead_save_state_size_known) - { - if (!runahead_create()) - { - settings_t *settings = config_get_ptr(); - if (!settings->bools.run_ahead_hide_warnings) - { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES), 0, 2 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - } - core_run(); - runahead_force_input_dirty = true; - return; - } - } - - runahead_check_for_gui(); - - if (!useSecondary || !have_dynamic || !runahead_secondary_core_available) - { - /* TODO: multiple savestates for higher performance - * when not using secondary core */ - for (frame_number = 0; frame_number <= runahead_count; frame_number++) - { - last_frame = frame_number == runahead_count; - suspended_frame = !last_frame; - - if (suspended_frame) - { - runahead_suspend_audio(); - runahead_suspend_video(); - } - - if (frame_number == 0) - core_run(); - else - runahead_core_run_use_last_input(); - - if (suspended_frame) - { - runahead_resume_video(); - runahead_resume_audio(); - } - - if (frame_number == 0) - { - if (!runahead_save_state()) - { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - return; - } - } - - if (last_frame) - { - if (!runahead_load_state()) - { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - return; - } - } - } - } - else - { -#if HAVE_DYNAMIC - if (!secondary_core_ensure_exists()) - { - runahead_secondary_core_available = false; - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - core_run(); - runahead_force_input_dirty = true; - return; - } - - /* run main core with video suspended */ - runahead_suspend_video(); - core_run(); - runahead_resume_video(); - - if (input_is_dirty || runahead_force_input_dirty) - { - input_is_dirty = false; - - if (!runahead_save_state()) - { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - return; - } - - if (!runahead_load_state_secondary()) - { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - return; - } - - for (frame_number = 0; frame_number < runahead_count - 1; frame_number++) - { - runahead_suspend_video(); - runahead_suspend_audio(); - hard_disable_audio = true; - runahead_run_secondary(); - hard_disable_audio = false; - runahead_resume_audio(); - runahead_resume_video(); - } - } - runahead_suspend_audio(); - hard_disable_audio = true; - runahead_run_secondary(); - hard_disable_audio = false; - runahead_resume_audio(); -#endif - } - runahead_force_input_dirty = false; -} - -void runahead_destroy(void) -{ - runahead_save_state_list_destroy(); - runahead_remove_hooks(); - runahead_clear_variables(); -} - -bool want_fast_savestate(void) -{ - return request_fast_savestate; -} - -bool get_hard_disable_audio(void) -{ - return hard_disable_audio; -} diff --git a/runahead/run_ahead.h b/runahead/run_ahead.h index 8868ce345b..d529ab1742 100644 --- a/runahead/run_ahead.h +++ b/runahead/run_ahead.h @@ -8,10 +8,6 @@ RETRO_BEGIN_DECLS -void runahead_destroy(void); - -void run_ahead(int runAheadCount, bool useSecondary); - bool want_fast_savestate(void); bool get_hard_disable_audio(void);