2018-03-28 19:22:07 +00:00
|
|
|
#include <stddef.h>
|
2018-03-29 13:52:49 +00:00
|
|
|
#include <stdlib.h>
|
2018-03-28 19:22:07 +00:00
|
|
|
#include <string.h>
|
2018-03-29 13:15:47 +00:00
|
|
|
|
|
|
|
#include <boolean.h>
|
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
#include "dirty_input.h"
|
|
|
|
#include "mylist.h"
|
|
|
|
#include "secondary_core.h"
|
2018-03-29 14:18:45 +00:00
|
|
|
#include "run_ahead.h"
|
2018-03-28 19:22:07 +00:00
|
|
|
|
2018-03-29 13:15:47 +00:00
|
|
|
#include "../core.h"
|
|
|
|
#include "../dynamic.h"
|
|
|
|
#include "../audio/audio_driver.h"
|
|
|
|
#include "../gfx/video_driver.h"
|
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
static bool runahead_create(void);
|
|
|
|
static bool runahead_save_state(void);
|
|
|
|
static bool runahead_load_state(void);
|
|
|
|
static bool runahead_load_state_secondary(void);
|
|
|
|
static bool runahead_run_secondary(void);
|
|
|
|
static void runahead_suspend_audio(void);
|
|
|
|
static void runahead_resume_audio(void);
|
|
|
|
static void runahead_suspend_video(void);
|
|
|
|
static void runahead_resume_video(void);
|
2018-03-31 01:22:35 +00:00
|
|
|
static void set_fast_savestate(void);
|
|
|
|
static void unset_fast_savestate(void);
|
|
|
|
static void set_hard_disable_audio(void);
|
|
|
|
static void unset_hard_disable_audio(void);
|
2018-03-28 19:22:07 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
/* TODO/FIXME - shouldn't this be signed size_t? */
|
2018-03-28 19:22:07 +00:00
|
|
|
static size_t runahead_save_state_size = -1;
|
|
|
|
|
|
|
|
/* Save State List for Run Ahead */
|
|
|
|
static MyList *runahead_save_state_list;
|
|
|
|
|
|
|
|
static void *runahead_save_state_alloc(void)
|
|
|
|
{
|
2018-03-29 14:18:45 +00:00
|
|
|
retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)
|
|
|
|
malloc(sizeof(retro_ctx_serialize_info_t));
|
|
|
|
|
|
|
|
if (!savestate)
|
|
|
|
return NULL;
|
|
|
|
|
2018-03-29 16:41:19 +00:00
|
|
|
savestate->data = NULL;
|
|
|
|
savestate->data_const = NULL;
|
|
|
|
savestate->size = 0;
|
2018-03-29 14:18:45 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
if (runahead_save_state_size > 0 && runahead_save_state_size != -1)
|
|
|
|
{
|
2018-03-29 16:41:19 +00:00
|
|
|
savestate->data = malloc(runahead_save_state_size);
|
2018-03-28 19:22:07 +00:00
|
|
|
savestate->data_const = savestate->data;
|
2018-03-29 16:41:19 +00:00
|
|
|
savestate->size = runahead_save_state_size;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
2018-03-29 14:18:45 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
return savestate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void runahead_save_state_free(void *state)
|
|
|
|
{
|
2018-03-29 13:13:33 +00:00
|
|
|
retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)state;
|
|
|
|
if (!savestate)
|
|
|
|
return;
|
2018-03-28 19:22:07 +00:00
|
|
|
free(savestate->data);
|
|
|
|
free(savestate);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void runahead_save_state_list_init(size_t saveStateSize)
|
|
|
|
{
|
|
|
|
runahead_save_state_size = saveStateSize;
|
2018-03-29 13:13:33 +00:00
|
|
|
mylist_create(&runahead_save_state_list, 16,
|
|
|
|
runahead_save_state_alloc, runahead_save_state_free);
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void runahead_save_state_list_destroy(void)
|
|
|
|
{
|
|
|
|
mylist_destroy(&runahead_save_state_list);
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:18:45 +00:00
|
|
|
#if 0
|
2018-03-28 19:22:07 +00:00
|
|
|
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++)
|
2018-03-29 14:52:14 +00:00
|
|
|
runahead_save_state_list->data[i - 1] =
|
|
|
|
runahead_save_state_list->data[i];
|
|
|
|
runahead_save_state_list->data[runahead_save_state_list->size - 1] =
|
2018-03-29 14:18:45 +00:00
|
|
|
firstElement;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
2018-03-29 14:18:45 +00:00
|
|
|
#endif
|
2018-03-28 19:22:07 +00:00
|
|
|
|
|
|
|
/* Hooks - Hooks to cleanup, and add dirty input hooks */
|
|
|
|
|
|
|
|
static function_t originalRetroDeinit = NULL;
|
|
|
|
static function_t originalRetroUnload = NULL;
|
|
|
|
|
2018-03-31 05:55:37 +00:00
|
|
|
extern struct retro_core_t current_core;
|
2018-03-28 19:22:07 +00:00
|
|
|
extern struct retro_callbacks retro_ctx;
|
|
|
|
|
|
|
|
static void remove_hooks(void)
|
|
|
|
{
|
2018-03-29 13:13:33 +00:00
|
|
|
if (originalRetroDeinit)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
current_core.retro_deinit = originalRetroDeinit;
|
2018-03-29 14:18:45 +00:00
|
|
|
originalRetroDeinit = NULL;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
2018-03-29 13:13:33 +00:00
|
|
|
|
|
|
|
if (originalRetroUnload)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
current_core.retro_unload_game = originalRetroUnload;
|
2018-03-29 14:18:45 +00:00
|
|
|
originalRetroUnload = NULL;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
2018-04-01 22:34:54 +00:00
|
|
|
current_core.retro_set_environment(rarch_environment_cb);
|
2018-03-28 19:22:07 +00:00
|
|
|
remove_input_state_hook();
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:18:45 +00:00
|
|
|
static void unload_hook(void)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
remove_hooks();
|
|
|
|
runahead_destroy();
|
|
|
|
secondary_core_destroy();
|
2018-03-29 14:18:45 +00:00
|
|
|
if (current_core.retro_unload_game)
|
|
|
|
current_core.retro_unload_game();
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 14:18:45 +00:00
|
|
|
|
|
|
|
static void deinit_hook(void)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
remove_hooks();
|
|
|
|
runahead_destroy();
|
|
|
|
secondary_core_destroy();
|
2018-03-29 14:18:45 +00:00
|
|
|
if (current_core.retro_deinit)
|
|
|
|
current_core.retro_deinit();
|
|
|
|
}
|
|
|
|
|
2018-04-01 22:34:54 +00:00
|
|
|
static bool env_hook(unsigned cmd, void *data)
|
|
|
|
{
|
|
|
|
bool result = rarch_environment_cb(cmd, data);
|
|
|
|
if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE && result)
|
|
|
|
{
|
|
|
|
bool *bool_p = (bool*)data;
|
|
|
|
if (*bool_p == true)
|
|
|
|
secondary_core_set_variable_update();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:18:45 +00:00
|
|
|
static void add_hooks(void)
|
|
|
|
{
|
|
|
|
if (!originalRetroDeinit)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
2018-03-29 14:18:45 +00:00
|
|
|
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;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
2018-04-01 22:34:54 +00:00
|
|
|
current_core.retro_set_environment(env_hook);
|
2018-03-29 14:18:45 +00:00
|
|
|
add_input_state_hook();
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 14:18:45 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
/* Runahead Code */
|
|
|
|
|
2018-03-29 13:13:33 +00:00
|
|
|
static bool runahead_video_driver_is_active = true;
|
|
|
|
static bool runahead_available = true;
|
2018-03-28 19:22:07 +00:00
|
|
|
static bool runahead_secondary_core_available = true;
|
2018-03-29 13:13:33 +00:00
|
|
|
static bool runahead_force_input_dirty = true;
|
|
|
|
static uint64_t runahead_last_frame_count = 0;
|
2018-03-28 19:22:07 +00:00
|
|
|
|
|
|
|
static void runahead_clear_variables(void)
|
|
|
|
{
|
2018-03-29 13:13:33 +00:00
|
|
|
runahead_save_state_size = -1;
|
|
|
|
runahead_video_driver_is_active = true;
|
|
|
|
runahead_available = true;
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_secondary_core_available = true;
|
2018-03-29 13:13:33 +00:00
|
|
|
runahead_force_input_dirty = true;
|
|
|
|
runahead_last_frame_count = 0;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void runahead_check_for_gui(void)
|
|
|
|
{
|
|
|
|
/* Hack: If we were in the GUI, force a resync. */
|
2018-03-29 13:13:33 +00:00
|
|
|
bool is_alive, is_focused = false;
|
|
|
|
uint64_t frame_count = 0;
|
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
video_driver_get_status(&frame_count, &is_alive, &is_focused);
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
if (frame_count != runahead_last_frame_count + 1)
|
|
|
|
runahead_force_input_dirty = true;
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_last_frame_count = frame_count;
|
|
|
|
}
|
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
void run_ahead(int runahead_count, bool useSecondary)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
int frame_number = 0;
|
|
|
|
bool last_frame = false;
|
|
|
|
bool suspended_frame = false;
|
2018-04-07 01:14:29 +00:00
|
|
|
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
|
2018-04-07 23:09:31 +00:00
|
|
|
const bool have_dynamic = true;
|
2018-04-07 01:08:18 +00:00
|
|
|
#else
|
2018-04-07 23:09:31 +00:00
|
|
|
const bool have_dynamic = false;
|
2018-04-07 01:08:18 +00:00
|
|
|
#endif
|
2018-03-28 19:22:07 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (runahead_count <= 0 || !runahead_available)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
core_run();
|
|
|
|
runahead_force_input_dirty = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (runahead_save_state_size == -1)
|
|
|
|
{
|
|
|
|
if (!runahead_create())
|
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
/* RunAhead has been disabled because the core
|
|
|
|
* does not support savestates. */
|
2018-03-28 19:22:07 +00:00
|
|
|
core_run();
|
|
|
|
runahead_force_input_dirty = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
runahead_check_for_gui();
|
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (!useSecondary || !have_dynamic || !runahead_secondary_core_available)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
/* TODO: multiple savestates for higher performance
|
|
|
|
* when not using secondary core */
|
|
|
|
for (frame_number = 0; frame_number <= runahead_count; frame_number++)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
last_frame = frame_number == runahead_count;
|
|
|
|
suspended_frame = !last_frame;
|
2018-03-29 16:41:19 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (suspended_frame)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
runahead_suspend_audio();
|
|
|
|
runahead_suspend_video();
|
|
|
|
}
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (frame_number == 0)
|
2018-03-28 19:22:07 +00:00
|
|
|
core_run();
|
|
|
|
else
|
|
|
|
core_run_no_input_polling();
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (suspended_frame)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
runahead_resume_video();
|
|
|
|
runahead_resume_audio();
|
|
|
|
}
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (frame_number == 0)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
/* RunAhead has been disabled due
|
|
|
|
* to save state failure */
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!runahead_save_state())
|
|
|
|
return;
|
|
|
|
}
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
if (last_frame)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
/* RunAhead has been disabled due
|
|
|
|
* to load state failure */
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!runahead_load_state())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if HAVE_DYNAMIC
|
2018-04-07 23:09:31 +00:00
|
|
|
bool okay = false;
|
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
/* run main core with video suspended */
|
|
|
|
runahead_suspend_video();
|
|
|
|
core_run();
|
|
|
|
runahead_resume_video();
|
|
|
|
|
|
|
|
if (input_is_dirty || runahead_force_input_dirty)
|
|
|
|
{
|
2018-03-29 13:13:33 +00:00
|
|
|
unsigned frame_count;
|
|
|
|
|
|
|
|
input_is_dirty = false;
|
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!runahead_save_state())
|
|
|
|
return;
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-29 14:52:14 +00:00
|
|
|
/* Could not create a secondary core.
|
2018-03-29 13:13:33 +00:00
|
|
|
* RunAhead wll only use the main core now. */
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!runahead_load_state_secondary())
|
|
|
|
return;
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-04-07 23:09:31 +00:00
|
|
|
for (frame_count = 0; frame_count <
|
|
|
|
(unsigned)(runahead_count - 1); frame_count++)
|
2018-03-28 19:22:07 +00:00
|
|
|
{
|
|
|
|
runahead_suspend_video();
|
|
|
|
runahead_suspend_audio();
|
2018-03-31 01:22:35 +00:00
|
|
|
set_hard_disable_audio();
|
2018-03-28 19:22:07 +00:00
|
|
|
okay = runahead_run_secondary();
|
2018-03-31 01:22:35 +00:00
|
|
|
unset_hard_disable_audio();
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_resume_audio();
|
|
|
|
runahead_resume_video();
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-29 14:52:14 +00:00
|
|
|
/* Could not create a secondary core. RunAhead
|
2018-03-29 13:13:33 +00:00
|
|
|
* will only use the main core now. */
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!okay)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
runahead_suspend_audio();
|
2018-03-31 01:22:35 +00:00
|
|
|
set_hard_disable_audio();
|
2018-03-28 19:22:07 +00:00
|
|
|
okay = runahead_run_secondary();
|
2018-03-31 01:22:35 +00:00
|
|
|
unset_hard_disable_audio();
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_resume_audio();
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-29 14:52:14 +00:00
|
|
|
/* Could not create a secondary core. RunAhead
|
2018-03-29 13:13:33 +00:00
|
|
|
* will only use the main core now. */
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!okay)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
runahead_force_input_dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void runahead_error(void)
|
|
|
|
{
|
|
|
|
runahead_available = false;
|
|
|
|
runahead_save_state_list_destroy();
|
|
|
|
remove_hooks();
|
|
|
|
runahead_save_state_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool runahead_create(void)
|
|
|
|
{
|
|
|
|
/* get savestate size and allocate buffer */
|
|
|
|
retro_ctx_size_info_t info;
|
|
|
|
core_serialize_size(&info);
|
|
|
|
|
|
|
|
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 == -1)
|
|
|
|
{
|
|
|
|
runahead_error();
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
add_hooks();
|
|
|
|
runahead_force_input_dirty = true;
|
|
|
|
mylist_resize(runahead_save_state_list, 1, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool runahead_save_state(void)
|
|
|
|
{
|
2018-04-07 23:09:31 +00:00
|
|
|
bool okay = false;
|
2018-03-29 14:52:14 +00:00
|
|
|
retro_ctx_serialize_info_t *serialize_info =
|
2018-03-29 13:13:33 +00:00
|
|
|
(retro_ctx_serialize_info_t*)runahead_save_state_list->data[0];
|
2018-03-31 01:22:35 +00:00
|
|
|
set_fast_savestate();
|
|
|
|
okay = core_serialize(serialize_info);
|
|
|
|
unset_fast_savestate();
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!okay)
|
2018-04-07 23:28:17 +00:00
|
|
|
{
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_error();
|
2018-04-07 23:28:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool runahead_load_state(void)
|
|
|
|
{
|
2018-04-07 23:28:17 +00:00
|
|
|
bool okay = false;
|
2018-03-29 16:41:19 +00:00
|
|
|
retro_ctx_serialize_info_t *serialize_info = (retro_ctx_serialize_info_t*)
|
|
|
|
runahead_save_state_list->data[0];
|
2018-04-07 23:28:17 +00:00
|
|
|
bool last_dirty = input_is_dirty;
|
|
|
|
|
2018-03-31 01:22:35 +00:00
|
|
|
set_fast_savestate();
|
2018-04-07 23:28:17 +00:00
|
|
|
/* calling core_unserialize has side effects with
|
|
|
|
* netplay (it triggers transmitting your save state)
|
2018-03-31 05:32:41 +00:00
|
|
|
call retro_unserialize directly from the core instead */
|
2018-04-07 23:28:17 +00:00
|
|
|
okay = current_core.retro_unserialize(
|
|
|
|
serialize_info->data_const, serialize_info->size);
|
2018-03-31 01:22:35 +00:00
|
|
|
unset_fast_savestate();
|
2018-04-07 23:28:17 +00:00
|
|
|
input_is_dirty = last_dirty;
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!okay)
|
|
|
|
runahead_error();
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool runahead_load_state_secondary(void)
|
|
|
|
{
|
2018-04-07 23:28:17 +00:00
|
|
|
bool okay = false;
|
2018-03-29 14:52:14 +00:00
|
|
|
retro_ctx_serialize_info_t *serialize_info =
|
2018-03-29 13:13:33 +00:00
|
|
|
(retro_ctx_serialize_info_t*)runahead_save_state_list->data[0];
|
2018-04-07 23:28:17 +00:00
|
|
|
|
2018-03-31 01:22:35 +00:00
|
|
|
set_fast_savestate();
|
2018-04-07 23:28:17 +00:00
|
|
|
okay = secondary_core_deserialize(
|
2018-04-09 13:56:45 +00:00
|
|
|
serialize_info->data_const, (int)serialize_info->size);
|
2018-03-31 01:22:35 +00:00
|
|
|
unset_fast_savestate();
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-03-28 19:22:07 +00:00
|
|
|
if (!okay)
|
2018-04-07 23:28:17 +00:00
|
|
|
{
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_secondary_core_available = false;
|
2018-04-07 23:28:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-03-29 13:13:33 +00:00
|
|
|
|
2018-04-07 23:28:17 +00:00
|
|
|
return true;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool runahead_run_secondary(void)
|
|
|
|
{
|
2018-04-07 23:28:17 +00:00
|
|
|
if (!secondary_core_run_no_input_polling())
|
|
|
|
{
|
2018-03-28 19:22:07 +00:00
|
|
|
runahead_secondary_core_available = false;
|
2018-04-07 23:28:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2018-03-28 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
void runahead_destroy(void)
|
|
|
|
{
|
|
|
|
runahead_save_state_list_destroy();
|
|
|
|
remove_hooks();
|
|
|
|
runahead_clear_variables();
|
|
|
|
}
|
2018-03-31 01:22:35 +00:00
|
|
|
|
|
|
|
static bool request_fast_savestate;
|
|
|
|
static bool hard_disable_audio;
|
|
|
|
|
|
|
|
|
|
|
|
bool want_fast_savestate(void)
|
|
|
|
{
|
|
|
|
return request_fast_savestate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_fast_savestate(void)
|
|
|
|
{
|
|
|
|
request_fast_savestate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unset_fast_savestate(void)
|
|
|
|
{
|
|
|
|
request_fast_savestate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get_hard_disable_audio(void)
|
|
|
|
{
|
|
|
|
return hard_disable_audio;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_hard_disable_audio(void)
|
|
|
|
{
|
|
|
|
hard_disable_audio = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unset_hard_disable_audio(void)
|
|
|
|
{
|
|
|
|
hard_disable_audio = false;
|
|
|
|
}
|