mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 21:32:45 +00:00
Split up code to runloop.c
This commit is contained in:
parent
f8b6443b91
commit
d1c7d97b10
@ -232,6 +232,7 @@ endif
|
||||
|
||||
OBJ += frontend/frontend_driver.o \
|
||||
retroarch.o \
|
||||
runloop.o \
|
||||
command.o \
|
||||
msg_hash.o \
|
||||
intl/msg_hash_us.o \
|
||||
|
@ -1191,6 +1191,7 @@ GIT
|
||||
RETROARCH
|
||||
============================================================ */
|
||||
#include "../retroarch.c"
|
||||
#include "../runloop.c"
|
||||
#include "../command.c"
|
||||
#include "../libretro-common/queues/task_queue.c"
|
||||
|
||||
|
924
retroarch.c
924
retroarch.c
File diff suppressed because it is too large
Load Diff
298
retroarch.h
298
retroarch.h
@ -27,6 +27,10 @@
|
||||
#include <retro_inline.h>
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#include <rthreads/rthreads.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@ -43,6 +47,7 @@
|
||||
|
||||
#include "core_type.h"
|
||||
#include "core.h"
|
||||
#include "core_option_manager.h"
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
#include "menu/menu_defines.h"
|
||||
@ -79,6 +84,9 @@ RETRO_BEGIN_DECLS
|
||||
* 3 - Late
|
||||
*/
|
||||
|
||||
#define MEASURE_FRAME_TIME_SAMPLES_COUNT (2 * 1024)
|
||||
#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
|
||||
|
||||
enum rarch_ctl_state
|
||||
{
|
||||
RARCH_CTL_NONE = 0,
|
||||
@ -321,6 +329,12 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data);
|
||||
int retroarch_get_capabilities(enum rarch_capabilities type,
|
||||
char *s, size_t len);
|
||||
|
||||
bool retroarch_validate_game_options(
|
||||
char *s, size_t len, bool mkdir);
|
||||
|
||||
bool retroarch_validate_folder_options(
|
||||
char *s, size_t len, bool mkdir);
|
||||
|
||||
void retroarch_override_setting_set(enum rarch_override_setting enum_idx, void *data);
|
||||
|
||||
void retroarch_override_setting_unset(enum rarch_override_setting enum_idx, void *data);
|
||||
@ -2019,6 +2033,290 @@ typedef enum apple_view_type
|
||||
APPLE_VIEW_TYPE_METAL
|
||||
} apple_view_type_t;
|
||||
|
||||
typedef struct input_game_focus_state
|
||||
{
|
||||
bool enabled;
|
||||
bool core_requested;
|
||||
} input_game_focus_state_t;
|
||||
|
||||
|
||||
typedef struct runloop runloop_state_t;
|
||||
|
||||
struct runloop
|
||||
{
|
||||
double audio_source_ratio_original;
|
||||
double audio_source_ratio_current;
|
||||
struct retro_system_av_info av_info; /* double alignment */
|
||||
|
||||
retro_time_t libretro_core_runtime_last;
|
||||
retro_time_t libretro_core_runtime_usec;
|
||||
retro_time_t frame_limit_minimum_time;
|
||||
retro_time_t frame_limit_last_time;
|
||||
retro_time_t frame_time_samples[
|
||||
MEASURE_FRAME_TIME_SAMPLES_COUNT];
|
||||
|
||||
retro_usec_t frame_time_last; /* int64_t alignment */
|
||||
|
||||
uint64_t frame_time_count;
|
||||
uint64_t frame_count;
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
uint64_t last_frame_count_runahead;
|
||||
#endif
|
||||
|
||||
uint64_t free_audio_samples_count;
|
||||
|
||||
float *audio_output_samples_buf;
|
||||
float *audio_input_data;
|
||||
|
||||
int16_t *audio_output_samples_conv_buf;
|
||||
#ifdef HAVE_REWIND
|
||||
int16_t *audio_rewind_buf;
|
||||
#endif
|
||||
|
||||
struct retro_audio_callback audio_callback; /* ptr alignment */
|
||||
msg_queue_t msg_queue; /* ptr alignment */
|
||||
#ifdef HAVE_THREADS
|
||||
slock_t *msg_queue_lock;
|
||||
slock_t *display_lock;
|
||||
slock_t *context_lock;
|
||||
#endif
|
||||
|
||||
core_option_manager_t *core_options;
|
||||
retro_keyboard_event_t key_event; /* ptr alignment */
|
||||
retro_keyboard_event_t frontend_key_event; /* ptr alignment */
|
||||
|
||||
rarch_system_info_t system; /* ptr alignment */
|
||||
struct retro_frame_time_callback frame_time; /* ptr alignment */
|
||||
struct retro_audio_buffer_status_callback audio_buffer_status; /* ptr alignment */
|
||||
|
||||
void *audio_context_audio_data;
|
||||
void *audio_resampler_data;
|
||||
|
||||
#ifdef HAVE_REWIND
|
||||
size_t audio_rewind_ptr;
|
||||
size_t audio_rewind_size;
|
||||
#endif
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
size_t runahead_save_state_size;
|
||||
#endif
|
||||
size_t audio_buffer_size;
|
||||
size_t audio_data_ptr;
|
||||
size_t audio_chunk_size;
|
||||
size_t audio_chunk_nonblock_size;
|
||||
size_t audio_chunk_block_size;
|
||||
size_t msg_queue_size;
|
||||
|
||||
unsigned pending_windowed_scale;
|
||||
unsigned max_frames;
|
||||
unsigned audio_latency;
|
||||
unsigned free_audio_samples_buf[
|
||||
AUDIO_BUFFER_FREE_SAMPLES_COUNT];
|
||||
|
||||
struct retro_fastforwarding_override fastmotion_override; /* float alignment */
|
||||
float audio_rate_control_delta;
|
||||
float audio_input_sample_rate;
|
||||
float audio_volume_gain;
|
||||
#ifdef HAVE_AUDIOMIXER
|
||||
float audio_mixer_volume_gain;
|
||||
#endif
|
||||
|
||||
input_game_focus_state_t game_focus_state; /* bool alignment */
|
||||
#ifdef HAVE_GFX_WIDGETS
|
||||
bool widgets_active;
|
||||
bool widgets_persisting;
|
||||
bool widgets_paused;
|
||||
bool widgets_fast_forward;
|
||||
bool widgets_rewinding;
|
||||
#endif
|
||||
bool audio_active;
|
||||
bool audio_use_float;
|
||||
bool audio_suspended;
|
||||
bool audio_control;
|
||||
bool audio_mute_enable;
|
||||
#ifdef HAVE_AUDIOMIXER
|
||||
bool audio_mixer_mute_enable;
|
||||
bool audio_mixer_active;
|
||||
#endif
|
||||
bool missing_bios;
|
||||
bool force_nonblock;
|
||||
bool paused;
|
||||
bool idle;
|
||||
bool slowmotion;
|
||||
bool fastmotion;
|
||||
bool shutdown_initiated;
|
||||
bool core_shutdown_initiated;
|
||||
bool core_running;
|
||||
bool perfcnt_enable;
|
||||
bool video_active;
|
||||
bool video_started_fullscreen;
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
bool runahead_video_active;
|
||||
#endif
|
||||
bool game_options_active;
|
||||
bool folder_options_active;
|
||||
bool autosave;
|
||||
#ifdef HAVE_CONFIGFILE
|
||||
bool overrides_active;
|
||||
bool remaps_core_active;
|
||||
bool remaps_game_active;
|
||||
bool remaps_content_dir_active;
|
||||
#endif
|
||||
#ifdef HAVE_SCREENSHOTS
|
||||
bool max_frames_screenshot;
|
||||
char max_frames_screenshot_path[PATH_MAX_LENGTH];
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
/* Only used before init_netplay */
|
||||
bool netplay_enabled;
|
||||
bool netplay_is_client;
|
||||
/* Used to avoid recursive netplay calls */
|
||||
bool in_netplay;
|
||||
bool netplay_client_deferred;
|
||||
bool is_mitm;
|
||||
#endif
|
||||
bool has_set_username;
|
||||
bool rarch_error_on_init;
|
||||
bool rarch_force_fullscreen;
|
||||
bool has_set_core;
|
||||
bool has_set_verbosity;
|
||||
bool has_set_libretro;
|
||||
bool has_set_libretro_directory;
|
||||
bool has_set_save_path;
|
||||
bool has_set_state_path;
|
||||
#ifdef HAVE_PATCH
|
||||
bool has_set_ups_pref;
|
||||
bool has_set_bps_pref;
|
||||
bool has_set_ips_pref;
|
||||
#endif
|
||||
#ifdef HAVE_QT
|
||||
bool qt_is_inited;
|
||||
#endif
|
||||
bool has_set_log_to_file;
|
||||
bool rarch_is_inited;
|
||||
bool rarch_is_switching_display_mode;
|
||||
bool rarch_is_sram_load_disabled;
|
||||
bool rarch_is_sram_save_disabled;
|
||||
bool rarch_use_sram;
|
||||
bool rarch_ups_pref;
|
||||
bool rarch_bps_pref;
|
||||
bool rarch_ips_pref;
|
||||
#ifdef HAVE_PATCH
|
||||
bool rarch_patch_blocked;
|
||||
#endif
|
||||
bool video_driver_window_title_update;
|
||||
|
||||
/**
|
||||
* dynamic.c:dynamic_request_hw_context will try to set
|
||||
* flag data when the context
|
||||
* is in the middle of being rebuilt; in these cases we will save flag
|
||||
* data and set this to true.
|
||||
* When the context is reinit, it checks this, reads from
|
||||
* deferred_flag_data and cleans it.
|
||||
*
|
||||
* TODO - Dirty hack, fix it better
|
||||
*/
|
||||
bool deferred_video_context_driver_set_flags;
|
||||
bool ignore_environment_cb;
|
||||
bool core_set_shared_context;
|
||||
|
||||
/* Graphics driver requires RGBA byte order data (ABGR on little-endian)
|
||||
* for 32-bit.
|
||||
* This takes effect for overlay and shader cores that wants to load
|
||||
* data into graphics driver. Kinda hackish to place it here, it is only
|
||||
* used for GLES.
|
||||
* TODO: Refactor this better. */
|
||||
bool video_driver_use_rgba;
|
||||
|
||||
/* If set during context deinit, the driver should keep
|
||||
* graphics context alive to avoid having to reset all
|
||||
* context state. */
|
||||
bool video_driver_cache_context;
|
||||
|
||||
/* Set to true by driver if context caching succeeded. */
|
||||
bool video_driver_cache_context_ack;
|
||||
|
||||
#ifdef HAVE_ACCESSIBILITY
|
||||
/* Is text-to-speech accessibility turned on? */
|
||||
bool accessibility_enabled;
|
||||
#endif
|
||||
#ifdef HAVE_CONFIGFILE
|
||||
bool rarch_block_config_read;
|
||||
#endif
|
||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||
bool cli_shader_disable;
|
||||
#endif
|
||||
|
||||
bool location_driver_active;
|
||||
bool bluetooth_driver_active;
|
||||
bool wifi_driver_active;
|
||||
bool camera_driver_active;
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
bool video_driver_state_out_rgb32;
|
||||
#endif
|
||||
bool video_driver_crt_switching_active;
|
||||
bool video_driver_crt_dynamic_super_width;
|
||||
bool video_driver_threaded;
|
||||
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
bool has_variable_update;
|
||||
bool runahead_save_state_size_known;
|
||||
bool request_fast_savestate;
|
||||
bool hard_disable_audio;
|
||||
|
||||
bool input_is_dirty;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_NETWORKING)
|
||||
bool has_set_netplay_mode;
|
||||
bool has_set_netplay_ip_address;
|
||||
bool has_set_netplay_ip_port;
|
||||
bool has_set_netplay_stateless_mode;
|
||||
bool has_set_netplay_check_frames;
|
||||
#endif
|
||||
|
||||
bool input_driver_keyboard_linefeed_enable;
|
||||
|
||||
bool input_driver_block_hotkey;
|
||||
bool input_driver_block_libretro_input;
|
||||
bool input_driver_nonblock_state;
|
||||
bool input_driver_grab_mouse_state;
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
bool menu_input_dialog_keyboard_display;
|
||||
/* Is the menu driver still running? */
|
||||
bool menu_driver_alive;
|
||||
/* Are we binding a button inside the menu? */
|
||||
bool menu_driver_is_binding;
|
||||
#endif
|
||||
|
||||
bool recording_enable;
|
||||
bool streaming_enable;
|
||||
|
||||
bool midi_drv_input_enabled;
|
||||
bool midi_drv_output_enabled;
|
||||
|
||||
bool midi_drv_output_pending;
|
||||
|
||||
bool main_ui_companion_is_on_foreground;
|
||||
bool keyboard_mapping_blocked;
|
||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||
bool shader_presets_need_reload;
|
||||
#endif
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
bool runahead_available;
|
||||
bool runahead_secondary_core_available;
|
||||
bool runahead_force_input_dirty;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool retroarch_validate_per_core_options(char *s,
|
||||
size_t len, bool mkdir,
|
||||
const char *core_name, const char *game_name);
|
||||
|
||||
void core_option_manager_flush(
|
||||
config_file_t *conf,
|
||||
core_option_manager_t *opt);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
279
retroarch_data.h
279
retroarch_data.h
@ -74,12 +74,8 @@
|
||||
#define BSV_MOVIE_IS_PLAYBACK_OFF() (p_rarch->bsv_movie_state_handle && !p_rarch->bsv_movie_state.movie_playback)
|
||||
#endif
|
||||
|
||||
#define MEASURE_FRAME_TIME_SAMPLES_COUNT (2 * 1024)
|
||||
|
||||
#define TIME_TO_FPS(last_time, new_time, frames) ((1000000.0f * (frames)) / ((new_time) - (last_time)))
|
||||
|
||||
#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
|
||||
|
||||
#define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac|wav"
|
||||
|
||||
#define MIDI_DRIVER_BUF_SIZE 4096
|
||||
@ -1494,12 +1490,6 @@ struct input_keyboard_line
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
typedef struct input_game_focus_state
|
||||
{
|
||||
bool enabled;
|
||||
bool core_requested;
|
||||
} input_game_focus_state_t;
|
||||
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
typedef bool(*runahead_load_state_function)(const void*, size_t);
|
||||
#endif
|
||||
@ -1655,275 +1645,6 @@ struct discord_state
|
||||
typedef struct discord_state discord_state_t;
|
||||
#endif
|
||||
|
||||
struct runloop
|
||||
{
|
||||
double audio_source_ratio_original;
|
||||
double audio_source_ratio_current;
|
||||
struct retro_system_av_info av_info; /* double alignment */
|
||||
|
||||
retro_time_t libretro_core_runtime_last;
|
||||
retro_time_t libretro_core_runtime_usec;
|
||||
retro_time_t frame_limit_minimum_time;
|
||||
retro_time_t frame_limit_last_time;
|
||||
retro_time_t frame_time_samples[
|
||||
MEASURE_FRAME_TIME_SAMPLES_COUNT];
|
||||
|
||||
retro_usec_t frame_time_last; /* int64_t alignment */
|
||||
|
||||
uint64_t frame_time_count;
|
||||
uint64_t frame_count;
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
uint64_t last_frame_count_runahead;
|
||||
#endif
|
||||
|
||||
uint64_t free_audio_samples_count;
|
||||
|
||||
float *audio_output_samples_buf;
|
||||
float *audio_input_data;
|
||||
|
||||
int16_t *audio_output_samples_conv_buf;
|
||||
#ifdef HAVE_REWIND
|
||||
int16_t *audio_rewind_buf;
|
||||
#endif
|
||||
|
||||
struct retro_audio_callback audio_callback; /* ptr alignment */
|
||||
msg_queue_t msg_queue; /* ptr alignment */
|
||||
#ifdef HAVE_THREADS
|
||||
slock_t *msg_queue_lock;
|
||||
slock_t *display_lock;
|
||||
slock_t *context_lock;
|
||||
#endif
|
||||
|
||||
core_option_manager_t *core_options;
|
||||
retro_keyboard_event_t key_event; /* ptr alignment */
|
||||
retro_keyboard_event_t frontend_key_event; /* ptr alignment */
|
||||
|
||||
rarch_system_info_t system; /* ptr alignment */
|
||||
struct retro_frame_time_callback frame_time; /* ptr alignment */
|
||||
struct retro_audio_buffer_status_callback audio_buffer_status; /* ptr alignment */
|
||||
|
||||
void *audio_context_audio_data;
|
||||
void *audio_resampler_data;
|
||||
|
||||
#ifdef HAVE_REWIND
|
||||
size_t audio_rewind_ptr;
|
||||
size_t audio_rewind_size;
|
||||
#endif
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
size_t runahead_save_state_size;
|
||||
#endif
|
||||
size_t audio_buffer_size;
|
||||
size_t audio_data_ptr;
|
||||
size_t audio_chunk_size;
|
||||
size_t audio_chunk_nonblock_size;
|
||||
size_t audio_chunk_block_size;
|
||||
size_t msg_queue_size;
|
||||
|
||||
unsigned pending_windowed_scale;
|
||||
unsigned max_frames;
|
||||
unsigned audio_latency;
|
||||
unsigned free_audio_samples_buf[
|
||||
AUDIO_BUFFER_FREE_SAMPLES_COUNT];
|
||||
|
||||
struct retro_fastforwarding_override fastmotion_override; /* float alignment */
|
||||
float audio_rate_control_delta;
|
||||
float audio_input_sample_rate;
|
||||
float audio_volume_gain;
|
||||
#ifdef HAVE_AUDIOMIXER
|
||||
float audio_mixer_volume_gain;
|
||||
#endif
|
||||
|
||||
input_game_focus_state_t game_focus_state; /* bool alignment */
|
||||
#ifdef HAVE_GFX_WIDGETS
|
||||
bool widgets_active;
|
||||
bool widgets_persisting;
|
||||
bool widgets_paused;
|
||||
bool widgets_fast_forward;
|
||||
bool widgets_rewinding;
|
||||
#endif
|
||||
bool audio_active;
|
||||
bool audio_use_float;
|
||||
bool audio_suspended;
|
||||
bool audio_control;
|
||||
bool audio_mute_enable;
|
||||
#ifdef HAVE_AUDIOMIXER
|
||||
bool audio_mixer_mute_enable;
|
||||
bool audio_mixer_active;
|
||||
#endif
|
||||
bool missing_bios;
|
||||
bool force_nonblock;
|
||||
bool paused;
|
||||
bool idle;
|
||||
bool slowmotion;
|
||||
bool fastmotion;
|
||||
bool shutdown_initiated;
|
||||
bool core_shutdown_initiated;
|
||||
bool core_running;
|
||||
bool perfcnt_enable;
|
||||
bool video_active;
|
||||
bool video_started_fullscreen;
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
bool runahead_video_active;
|
||||
#endif
|
||||
bool game_options_active;
|
||||
bool folder_options_active;
|
||||
bool autosave;
|
||||
#ifdef HAVE_CONFIGFILE
|
||||
bool overrides_active;
|
||||
bool remaps_core_active;
|
||||
bool remaps_game_active;
|
||||
bool remaps_content_dir_active;
|
||||
#endif
|
||||
#ifdef HAVE_SCREENSHOTS
|
||||
bool max_frames_screenshot;
|
||||
char max_frames_screenshot_path[PATH_MAX_LENGTH];
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
/* Only used before init_netplay */
|
||||
bool netplay_enabled;
|
||||
bool netplay_is_client;
|
||||
/* Used to avoid recursive netplay calls */
|
||||
bool in_netplay;
|
||||
bool netplay_client_deferred;
|
||||
bool is_mitm;
|
||||
#endif
|
||||
bool has_set_username;
|
||||
bool rarch_error_on_init;
|
||||
bool rarch_force_fullscreen;
|
||||
bool has_set_core;
|
||||
bool has_set_verbosity;
|
||||
bool has_set_libretro;
|
||||
bool has_set_libretro_directory;
|
||||
bool has_set_save_path;
|
||||
bool has_set_state_path;
|
||||
#ifdef HAVE_PATCH
|
||||
bool has_set_ups_pref;
|
||||
bool has_set_bps_pref;
|
||||
bool has_set_ips_pref;
|
||||
#endif
|
||||
#ifdef HAVE_QT
|
||||
bool qt_is_inited;
|
||||
#endif
|
||||
bool has_set_log_to_file;
|
||||
bool rarch_is_inited;
|
||||
bool rarch_is_switching_display_mode;
|
||||
bool rarch_is_sram_load_disabled;
|
||||
bool rarch_is_sram_save_disabled;
|
||||
bool rarch_use_sram;
|
||||
bool rarch_ups_pref;
|
||||
bool rarch_bps_pref;
|
||||
bool rarch_ips_pref;
|
||||
#ifdef HAVE_PATCH
|
||||
bool rarch_patch_blocked;
|
||||
#endif
|
||||
bool video_driver_window_title_update;
|
||||
|
||||
/**
|
||||
* dynamic.c:dynamic_request_hw_context will try to set
|
||||
* flag data when the context
|
||||
* is in the middle of being rebuilt; in these cases we will save flag
|
||||
* data and set this to true.
|
||||
* When the context is reinit, it checks this, reads from
|
||||
* deferred_flag_data and cleans it.
|
||||
*
|
||||
* TODO - Dirty hack, fix it better
|
||||
*/
|
||||
bool deferred_video_context_driver_set_flags;
|
||||
bool ignore_environment_cb;
|
||||
bool core_set_shared_context;
|
||||
|
||||
/* Graphics driver requires RGBA byte order data (ABGR on little-endian)
|
||||
* for 32-bit.
|
||||
* This takes effect for overlay and shader cores that wants to load
|
||||
* data into graphics driver. Kinda hackish to place it here, it is only
|
||||
* used for GLES.
|
||||
* TODO: Refactor this better. */
|
||||
bool video_driver_use_rgba;
|
||||
|
||||
/* If set during context deinit, the driver should keep
|
||||
* graphics context alive to avoid having to reset all
|
||||
* context state. */
|
||||
bool video_driver_cache_context;
|
||||
|
||||
/* Set to true by driver if context caching succeeded. */
|
||||
bool video_driver_cache_context_ack;
|
||||
|
||||
#ifdef HAVE_ACCESSIBILITY
|
||||
/* Is text-to-speech accessibility turned on? */
|
||||
bool accessibility_enabled;
|
||||
#endif
|
||||
#ifdef HAVE_CONFIGFILE
|
||||
bool rarch_block_config_read;
|
||||
#endif
|
||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||
bool cli_shader_disable;
|
||||
#endif
|
||||
|
||||
bool location_driver_active;
|
||||
bool bluetooth_driver_active;
|
||||
bool wifi_driver_active;
|
||||
bool camera_driver_active;
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
bool video_driver_state_out_rgb32;
|
||||
#endif
|
||||
bool video_driver_crt_switching_active;
|
||||
bool video_driver_crt_dynamic_super_width;
|
||||
bool video_driver_threaded;
|
||||
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
bool has_variable_update;
|
||||
bool runahead_save_state_size_known;
|
||||
bool request_fast_savestate;
|
||||
bool hard_disable_audio;
|
||||
|
||||
bool input_is_dirty;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_NETWORKING)
|
||||
bool has_set_netplay_mode;
|
||||
bool has_set_netplay_ip_address;
|
||||
bool has_set_netplay_ip_port;
|
||||
bool has_set_netplay_stateless_mode;
|
||||
bool has_set_netplay_check_frames;
|
||||
#endif
|
||||
|
||||
bool input_driver_keyboard_linefeed_enable;
|
||||
|
||||
bool input_driver_block_hotkey;
|
||||
bool input_driver_block_libretro_input;
|
||||
bool input_driver_nonblock_state;
|
||||
bool input_driver_grab_mouse_state;
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
bool menu_input_dialog_keyboard_display;
|
||||
/* Is the menu driver still running? */
|
||||
bool menu_driver_alive;
|
||||
/* Are we binding a button inside the menu? */
|
||||
bool menu_driver_is_binding;
|
||||
#endif
|
||||
|
||||
bool recording_enable;
|
||||
bool streaming_enable;
|
||||
|
||||
bool midi_drv_input_enabled;
|
||||
bool midi_drv_output_enabled;
|
||||
|
||||
bool midi_drv_output_pending;
|
||||
|
||||
bool main_ui_companion_is_on_foreground;
|
||||
bool keyboard_mapping_blocked;
|
||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||
bool shader_presets_need_reload;
|
||||
#endif
|
||||
#ifdef HAVE_RUNAHEAD
|
||||
bool runahead_available;
|
||||
bool runahead_secondary_core_available;
|
||||
bool runahead_force_input_dirty;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct runloop runloop_state_t;
|
||||
|
||||
struct rarch_state
|
||||
{
|
||||
videocrt_switch_t crt_switch_st; /* double alignment */
|
||||
|
@ -44,14 +44,18 @@ static bool midi_driver_set_all_sounds_off(struct rarch_state *p_rarch);
|
||||
static const void *midi_driver_find_handle(int index);
|
||||
static bool midi_driver_flush(void);
|
||||
|
||||
static void runloop_deinit_core_options(
|
||||
retro_time_t runloop_core_runtime_tick(
|
||||
runloop_state_t *p_runloop,
|
||||
float slowmotion_ratio,
|
||||
retro_time_t current_time);
|
||||
void runloop_deinit_core_options(
|
||||
runloop_state_t *p_runloop,
|
||||
const char *path_core_options);
|
||||
static core_option_manager_t *runloop_init_core_variables(
|
||||
core_option_manager_t *runloop_init_core_variables(
|
||||
runloop_state_t *p_runloop,
|
||||
settings_t *settings,
|
||||
const struct retro_variable *vars);
|
||||
static core_option_manager_t *runloop_init_core_options(
|
||||
core_option_manager_t *runloop_init_core_options(
|
||||
runloop_state_t *p_runloop,
|
||||
settings_t *settings,
|
||||
const struct retro_core_option_definition *option_defs);
|
||||
|
771
runloop.c
Executable file
771
runloop.c
Executable file
@ -0,0 +1,771 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#include <rthreads/rthreads.h>
|
||||
#endif
|
||||
|
||||
#include "configuration.h"
|
||||
#include "file_path_special.h"
|
||||
#include "paths.h"
|
||||
#include "retroarch.h"
|
||||
#include "verbosity.h"
|
||||
|
||||
/**
|
||||
* runloop_game_specific_options:
|
||||
*
|
||||
* Returns: true (1) if a game specific core
|
||||
* options path has been found,
|
||||
* otherwise false (0).
|
||||
**/
|
||||
static bool runloop_game_specific_options(char **output)
|
||||
{
|
||||
char game_options_path[PATH_MAX_LENGTH];
|
||||
game_options_path[0] ='\0';
|
||||
|
||||
if (!retroarch_validate_game_options(
|
||||
game_options_path,
|
||||
sizeof(game_options_path), false) ||
|
||||
!path_is_valid(game_options_path))
|
||||
return false;
|
||||
|
||||
RARCH_LOG("%s %s\n",
|
||||
msg_hash_to_str(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT),
|
||||
game_options_path);
|
||||
*output = strdup(game_options_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* runloop_folder_specific_options:
|
||||
*
|
||||
* Returns: true (1) if a folder specific core
|
||||
* options path has been found,
|
||||
* otherwise false (0).
|
||||
**/
|
||||
static bool runloop_folder_specific_options(char **output)
|
||||
{
|
||||
char folder_options_path[PATH_MAX_LENGTH];
|
||||
folder_options_path[0] ='\0';
|
||||
|
||||
if (!retroarch_validate_folder_options(
|
||||
folder_options_path,
|
||||
sizeof(folder_options_path), false) ||
|
||||
!path_is_valid(folder_options_path))
|
||||
return false;
|
||||
|
||||
RARCH_LOG("%s %s\n",
|
||||
msg_hash_to_str(MSG_FOLDER_SPECIFIC_CORE_OPTIONS_FOUND_AT),
|
||||
folder_options_path);
|
||||
*output = strdup(folder_options_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *core_option_manager_parse_value_label(
|
||||
const char *value, const char *value_label)
|
||||
{
|
||||
/* 'value_label' may be NULL */
|
||||
const char *label = string_is_empty(value_label) ?
|
||||
value : value_label;
|
||||
|
||||
if (string_is_empty(label))
|
||||
return NULL;
|
||||
|
||||
/* Any label starting with a digit (or +/-)
|
||||
* cannot be a boolean string, and requires
|
||||
* no further processing */
|
||||
if (ISDIGIT((unsigned char)*label) ||
|
||||
(*label == '+') ||
|
||||
(*label == '-'))
|
||||
return label;
|
||||
|
||||
/* Core devs have a habit of using arbitrary
|
||||
* strings to label boolean values (i.e. enabled,
|
||||
* Enabled, on, On, ON, true, True, TRUE, disabled,
|
||||
* Disabled, off, Off, OFF, false, False, FALSE).
|
||||
* These should all be converted to standard ON/OFF
|
||||
* strings
|
||||
* > Note: We require some duplication here
|
||||
* (e.g. MENU_ENUM_LABEL_ENABLED *and*
|
||||
* MENU_ENUM_LABEL_VALUE_ENABLED) in order
|
||||
* to match both localised and non-localised
|
||||
* strings. This function is not performance
|
||||
* critical, so these extra comparisons do
|
||||
* no harm */
|
||||
if (string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) ||
|
||||
string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ENABLED)) ||
|
||||
string_is_equal_noncase(label, "enable") ||
|
||||
string_is_equal_noncase(label, "on") ||
|
||||
string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)) ||
|
||||
string_is_equal_noncase(label, "true") ||
|
||||
string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TRUE)))
|
||||
label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON);
|
||||
else if (string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) ||
|
||||
string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISABLED)) ||
|
||||
string_is_equal_noncase(label, "disable") ||
|
||||
string_is_equal_noncase(label, "off") ||
|
||||
string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)) ||
|
||||
string_is_equal_noncase(label, "false") ||
|
||||
string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FALSE)))
|
||||
label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
static bool core_option_manager_parse_variable(
|
||||
core_option_manager_t *opt, size_t idx,
|
||||
const struct retro_variable *var,
|
||||
config_file_t *config_src)
|
||||
{
|
||||
size_t i;
|
||||
union string_list_elem_attr attr;
|
||||
const char *val_start = NULL;
|
||||
char *value = NULL;
|
||||
char *desc_end = NULL;
|
||||
struct core_option *option = (struct core_option*)&opt->opts[idx];
|
||||
struct config_entry_list
|
||||
*entry = NULL;
|
||||
|
||||
/* All options are visible by default */
|
||||
option->visible = true;
|
||||
|
||||
if (!string_is_empty(var->key))
|
||||
option->key = strdup(var->key);
|
||||
if (!string_is_empty(var->value))
|
||||
value = strdup(var->value);
|
||||
|
||||
if (!string_is_empty(value))
|
||||
desc_end = strstr(value, "; ");
|
||||
|
||||
if (!desc_end)
|
||||
goto error;
|
||||
|
||||
*desc_end = '\0';
|
||||
|
||||
if (!string_is_empty(value))
|
||||
option->desc = strdup(value);
|
||||
|
||||
val_start = desc_end + 2;
|
||||
option->vals = string_split(val_start, "|");
|
||||
|
||||
if (!option->vals)
|
||||
goto error;
|
||||
|
||||
/* Legacy core option interface has no concept
|
||||
* of value labels
|
||||
* > Use actual values for display purposes */
|
||||
attr.i = 0;
|
||||
option->val_labels = string_list_new();
|
||||
|
||||
if (!option->val_labels)
|
||||
goto error;
|
||||
|
||||
/* > Loop over values and 'extract' labels */
|
||||
for (i = 0; i < option->vals->size; i++)
|
||||
{
|
||||
const char *value = option->vals->elems[i].data;
|
||||
const char *value_label = core_option_manager_parse_value_label(
|
||||
value, NULL);
|
||||
|
||||
/* Redundant safely check... */
|
||||
value_label = string_is_empty(value_label) ?
|
||||
value : value_label;
|
||||
|
||||
/* Append value label string */
|
||||
string_list_append(option->val_labels, value_label, attr);
|
||||
}
|
||||
|
||||
/* Legacy core option interface always uses first
|
||||
* defined value as the default */
|
||||
option->default_index = 0;
|
||||
option->index = 0;
|
||||
|
||||
if (config_src)
|
||||
entry = config_get_entry(config_src, option->key);
|
||||
else
|
||||
entry = config_get_entry(opt->conf, option->key);
|
||||
|
||||
/* Set current config value */
|
||||
if (entry && !string_is_empty(entry->value))
|
||||
{
|
||||
for (i = 0; i < option->vals->size; i++)
|
||||
{
|
||||
if (string_is_equal(option->vals->elems[i].data, entry->value))
|
||||
{
|
||||
option->index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(value);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
free(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool core_option_manager_parse_option(
|
||||
core_option_manager_t *opt, size_t idx,
|
||||
const struct retro_core_option_definition *option_def,
|
||||
config_file_t *config_src)
|
||||
{
|
||||
size_t i;
|
||||
union string_list_elem_attr attr;
|
||||
struct config_entry_list
|
||||
*entry = NULL;
|
||||
size_t num_vals = 0;
|
||||
struct core_option *option = (struct core_option*)&opt->opts[idx];
|
||||
const struct retro_core_option_value
|
||||
*values = option_def->values;
|
||||
|
||||
/* All options are visible by default */
|
||||
option->visible = true;
|
||||
|
||||
if (!string_is_empty(option_def->key))
|
||||
option->key = strdup(option_def->key);
|
||||
|
||||
if (!string_is_empty(option_def->desc))
|
||||
option->desc = strdup(option_def->desc);
|
||||
|
||||
if (!string_is_empty(option_def->info))
|
||||
option->info = strdup(option_def->info);
|
||||
|
||||
/* Get number of values */
|
||||
for (;;)
|
||||
{
|
||||
if (string_is_empty(values[num_vals].value))
|
||||
break;
|
||||
num_vals++;
|
||||
}
|
||||
|
||||
if (num_vals < 1)
|
||||
return false;
|
||||
|
||||
/* Initialise string lists */
|
||||
attr.i = 0;
|
||||
option->vals = string_list_new();
|
||||
option->val_labels = string_list_new();
|
||||
|
||||
if (!option->vals || !option->val_labels)
|
||||
return false;
|
||||
|
||||
/* Initialise default value */
|
||||
option->default_index = 0;
|
||||
option->index = 0;
|
||||
|
||||
/* Extract value/label pairs */
|
||||
for (i = 0; i < num_vals; i++)
|
||||
{
|
||||
const char *value = values[i].value;
|
||||
const char *value_label = values[i].label;
|
||||
|
||||
/* Append value string
|
||||
* > We know that 'value' is always valid */
|
||||
string_list_append(option->vals, value, attr);
|
||||
|
||||
/* Value label requires additional processing */
|
||||
value_label = core_option_manager_parse_value_label(
|
||||
value, value_label);
|
||||
|
||||
/* > Redundant safely check... */
|
||||
value_label = string_is_empty(value_label) ?
|
||||
value : value_label;
|
||||
|
||||
/* Append value label string */
|
||||
string_list_append(option->val_labels, value_label, attr);
|
||||
|
||||
/* Check whether this value is the default setting */
|
||||
if (!string_is_empty(option_def->default_value))
|
||||
{
|
||||
if (string_is_equal(option_def->default_value, value))
|
||||
{
|
||||
option->default_index = i;
|
||||
option->index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config_src)
|
||||
entry = config_get_entry(config_src, option->key);
|
||||
else
|
||||
entry = config_get_entry(opt->conf, option->key);
|
||||
|
||||
/* Set current config value */
|
||||
if (entry && !string_is_empty(entry->value))
|
||||
{
|
||||
for (i = 0; i < option->vals->size; i++)
|
||||
{
|
||||
if (string_is_equal(option->vals->elems[i].data, entry->value))
|
||||
{
|
||||
option->index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* core_option_manager_free:
|
||||
* @opt : options manager handle
|
||||
*
|
||||
* Frees core option manager handle.
|
||||
**/
|
||||
static void core_option_manager_free(core_option_manager_t *opt)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!opt)
|
||||
return;
|
||||
|
||||
for (i = 0; i < opt->size; i++)
|
||||
{
|
||||
if (opt->opts[i].desc)
|
||||
free(opt->opts[i].desc);
|
||||
if (opt->opts[i].info)
|
||||
free(opt->opts[i].info);
|
||||
if (opt->opts[i].key)
|
||||
free(opt->opts[i].key);
|
||||
|
||||
if (opt->opts[i].vals)
|
||||
string_list_free(opt->opts[i].vals);
|
||||
if (opt->opts[i].val_labels)
|
||||
string_list_free(opt->opts[i].val_labels);
|
||||
|
||||
opt->opts[i].desc = NULL;
|
||||
opt->opts[i].info = NULL;
|
||||
opt->opts[i].key = NULL;
|
||||
opt->opts[i].vals = NULL;
|
||||
}
|
||||
|
||||
if (opt->conf)
|
||||
config_file_free(opt->conf);
|
||||
free(opt->opts);
|
||||
free(opt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* core_option_manager_new:
|
||||
* @conf_path : Filesystem path to write core option config file to.
|
||||
* @src_conf_path : Filesystem path from which to load initial config settings.
|
||||
* @option_defs : Pointer to variable array handle.
|
||||
*
|
||||
* Creates and initializes a core manager handle.
|
||||
*
|
||||
* Returns: handle to new core manager handle, otherwise NULL.
|
||||
**/
|
||||
static core_option_manager_t *core_option_manager_new(
|
||||
const char *conf_path, const char *src_conf_path,
|
||||
const struct retro_core_option_definition *option_defs)
|
||||
{
|
||||
const struct retro_core_option_definition *option_def;
|
||||
size_t size = 0;
|
||||
config_file_t *config_src = NULL;
|
||||
core_option_manager_t *opt = (core_option_manager_t*)
|
||||
malloc(sizeof(*opt));
|
||||
|
||||
if (!opt)
|
||||
return NULL;
|
||||
|
||||
opt->conf = NULL;
|
||||
opt->conf_path[0] = '\0';
|
||||
opt->opts = NULL;
|
||||
opt->size = 0;
|
||||
opt->updated = false;
|
||||
|
||||
if (!string_is_empty(conf_path))
|
||||
if (!(opt->conf = config_file_new_from_path_to_string(conf_path)))
|
||||
if (!(opt->conf = config_file_new_alloc()))
|
||||
goto error;
|
||||
|
||||
strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path));
|
||||
|
||||
/* Load source config file, if required */
|
||||
if (!string_is_empty(src_conf_path))
|
||||
config_src = config_file_new_from_path_to_string(src_conf_path);
|
||||
|
||||
/* Note: 'option_def->info == NULL' is valid */
|
||||
for (option_def = option_defs;
|
||||
option_def->key && option_def->desc && option_def->values[0].value;
|
||||
option_def++)
|
||||
size++;
|
||||
|
||||
if (size == 0)
|
||||
goto error;
|
||||
|
||||
opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts));
|
||||
if (!opt->opts)
|
||||
goto error;
|
||||
|
||||
opt->size = size;
|
||||
size = 0;
|
||||
|
||||
/* Note: 'option_def->info == NULL' is valid */
|
||||
for (option_def = option_defs;
|
||||
option_def->key && option_def->desc && option_def->values[0].value;
|
||||
size++, option_def++)
|
||||
if (!core_option_manager_parse_option(opt, size, option_def, config_src))
|
||||
goto error;
|
||||
|
||||
if (config_src)
|
||||
config_file_free(config_src);
|
||||
|
||||
return opt;
|
||||
|
||||
error:
|
||||
if (config_src)
|
||||
config_file_free(config_src);
|
||||
core_option_manager_free(opt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* core_option_manager_new_vars:
|
||||
* @conf_path : Filesystem path to write core option config file to.
|
||||
* @src_conf_path : Filesystem path from which to load initial config settings.
|
||||
* @vars : Pointer to variable array handle.
|
||||
*
|
||||
* Legacy version of core_option_manager_new().
|
||||
* Creates and initializes a core manager handle.
|
||||
*
|
||||
* Returns: handle to new core manager handle, otherwise NULL.
|
||||
**/
|
||||
static core_option_manager_t *core_option_manager_new_vars(
|
||||
const char *conf_path, const char *src_conf_path,
|
||||
const struct retro_variable *vars)
|
||||
{
|
||||
const struct retro_variable *var;
|
||||
size_t size = 0;
|
||||
config_file_t *config_src = NULL;
|
||||
core_option_manager_t *opt = (core_option_manager_t*)
|
||||
malloc(sizeof(*opt));
|
||||
|
||||
if (!opt)
|
||||
return NULL;
|
||||
|
||||
opt->conf = NULL;
|
||||
opt->conf_path[0] = '\0';
|
||||
opt->opts = NULL;
|
||||
opt->size = 0;
|
||||
opt->updated = false;
|
||||
|
||||
if (!string_is_empty(conf_path))
|
||||
if (!(opt->conf = config_file_new_from_path_to_string(conf_path)))
|
||||
if (!(opt->conf = config_file_new_alloc()))
|
||||
goto error;
|
||||
|
||||
strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path));
|
||||
|
||||
/* Load source config file, if required */
|
||||
if (!string_is_empty(src_conf_path))
|
||||
config_src = config_file_new_from_path_to_string(src_conf_path);
|
||||
|
||||
for (var = vars; var->key && var->value; var++)
|
||||
size++;
|
||||
|
||||
if (size == 0)
|
||||
goto error;
|
||||
|
||||
opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts));
|
||||
if (!opt->opts)
|
||||
goto error;
|
||||
|
||||
opt->size = size;
|
||||
size = 0;
|
||||
|
||||
for (var = vars; var->key && var->value; size++, var++)
|
||||
{
|
||||
if (!core_option_manager_parse_variable(opt, size, var, config_src))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (config_src)
|
||||
config_file_free(config_src);
|
||||
|
||||
return opt;
|
||||
|
||||
error:
|
||||
if (config_src)
|
||||
config_file_free(config_src);
|
||||
core_option_manager_free(opt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fetches core options path for current core/content
|
||||
* - path: path from which options should be read
|
||||
* from/saved to
|
||||
* - src_path: in the event that 'path' file does not
|
||||
* yet exist, provides source path from which initial
|
||||
* options should be extracted
|
||||
*
|
||||
* NOTE: caller must ensure
|
||||
* path and src_path are NULL-terminated
|
||||
* */
|
||||
void runloop_init_core_options_path(
|
||||
runloop_state_t *p_runloop,
|
||||
settings_t *settings,
|
||||
char *path, size_t len,
|
||||
char *src_path, size_t src_len)
|
||||
{
|
||||
char *game_options_path = NULL;
|
||||
char *folder_options_path = NULL;
|
||||
bool game_specific_options = settings->bools.game_specific_options;
|
||||
|
||||
/* Check whether game-specific options exist */
|
||||
if (game_specific_options &&
|
||||
runloop_game_specific_options(&game_options_path))
|
||||
{
|
||||
/* Notify system that we have a valid core options
|
||||
* override */
|
||||
path_set(RARCH_PATH_CORE_OPTIONS, game_options_path);
|
||||
p_runloop->game_options_active = true;
|
||||
p_runloop->folder_options_active = false;
|
||||
|
||||
/* Copy options path */
|
||||
strlcpy(path, game_options_path, len);
|
||||
|
||||
free(game_options_path);
|
||||
}
|
||||
/* Check whether folder-specific options exist */
|
||||
else if (game_specific_options &&
|
||||
runloop_folder_specific_options(&folder_options_path))
|
||||
{
|
||||
/* Notify system that we have a valid core options
|
||||
* override */
|
||||
path_set(RARCH_PATH_CORE_OPTIONS, folder_options_path);
|
||||
p_runloop->game_options_active = false;
|
||||
p_runloop->folder_options_active = true;
|
||||
|
||||
/* Copy options path */
|
||||
strlcpy(path, folder_options_path, len);
|
||||
|
||||
free(folder_options_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
char global_options_path[PATH_MAX_LENGTH];
|
||||
char per_core_options_path[PATH_MAX_LENGTH];
|
||||
bool per_core_options_exist = false;
|
||||
bool per_core_options = !settings->bools.global_core_options;
|
||||
const char *path_core_options = settings->paths.path_core_options;
|
||||
|
||||
global_options_path[0] = '\0';
|
||||
per_core_options_path[0] = '\0';
|
||||
|
||||
if (per_core_options)
|
||||
{
|
||||
const char *core_name = p_runloop->system.info.library_name;
|
||||
/* Get core-specific options path
|
||||
* > if retroarch_validate_per_core_options() returns
|
||||
* false, then per-core options are disabled (due to
|
||||
* unknown system errors...) */
|
||||
per_core_options = retroarch_validate_per_core_options(
|
||||
per_core_options_path, sizeof(per_core_options_path), true,
|
||||
core_name, core_name);
|
||||
|
||||
/* If we can use per-core options, check whether an options
|
||||
* file already exists */
|
||||
if (per_core_options)
|
||||
per_core_options_exist = path_is_valid(per_core_options_path);
|
||||
}
|
||||
|
||||
/* If not using per-core options, or if a per-core options
|
||||
* file does not yet exist, must fetch 'global' options path */
|
||||
if (!per_core_options || !per_core_options_exist)
|
||||
{
|
||||
const char *options_path = path_core_options;
|
||||
|
||||
if (!string_is_empty(options_path))
|
||||
strlcpy(global_options_path,
|
||||
options_path, sizeof(global_options_path));
|
||||
else if (!path_is_empty(RARCH_PATH_CONFIG))
|
||||
fill_pathname_resolve_relative(
|
||||
global_options_path, path_get(RARCH_PATH_CONFIG),
|
||||
FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(global_options_path));
|
||||
}
|
||||
|
||||
/* Allocate correct path/src_path strings */
|
||||
if (per_core_options)
|
||||
{
|
||||
strlcpy(path, per_core_options_path, len);
|
||||
|
||||
if (!per_core_options_exist)
|
||||
strlcpy(src_path, global_options_path, src_len);
|
||||
}
|
||||
else
|
||||
strlcpy(path, global_options_path, len);
|
||||
|
||||
/* Notify system that we *do not* have a valid core options
|
||||
* options override */
|
||||
p_runloop->game_options_active = false;
|
||||
p_runloop->folder_options_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
core_option_manager_t *runloop_init_core_variables(
|
||||
runloop_state_t *p_runloop,
|
||||
settings_t *settings,
|
||||
const struct retro_variable *vars)
|
||||
{
|
||||
char options_path[PATH_MAX_LENGTH];
|
||||
char src_options_path[PATH_MAX_LENGTH];
|
||||
|
||||
/* Ensure these are NULL-terminated */
|
||||
options_path[0] = '\0';
|
||||
src_options_path[0] = '\0';
|
||||
|
||||
/* Get core options file path */
|
||||
runloop_init_core_options_path(
|
||||
p_runloop,
|
||||
settings,
|
||||
options_path, sizeof(options_path),
|
||||
src_options_path, sizeof(src_options_path));
|
||||
|
||||
if (!string_is_empty(options_path))
|
||||
return core_option_manager_new_vars(options_path, src_options_path, vars);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void runloop_deinit_core_options(
|
||||
runloop_state_t *p_runloop,
|
||||
const char *path_core_options)
|
||||
{
|
||||
/* Check whether game-specific options file is being used */
|
||||
if (!string_is_empty(path_core_options))
|
||||
{
|
||||
config_file_t *conf_tmp = NULL;
|
||||
|
||||
/* We only need to save configuration settings for
|
||||
* the current core
|
||||
* > If game-specific options file exists, have
|
||||
* to read it (to ensure file only gets written
|
||||
* if config values change)
|
||||
* > Otherwise, create a new, empty config_file_t
|
||||
* object */
|
||||
if (path_is_valid(path_core_options))
|
||||
conf_tmp = config_file_new_from_path_to_string(path_core_options);
|
||||
|
||||
if (!conf_tmp)
|
||||
conf_tmp = config_file_new_alloc();
|
||||
|
||||
if (conf_tmp)
|
||||
{
|
||||
core_option_manager_flush(
|
||||
conf_tmp,
|
||||
p_runloop->core_options);
|
||||
RARCH_LOG("[Core Options]: Saved %s-specific core options to \"%s\"\n",
|
||||
p_runloop->game_options_active
|
||||
? "game"
|
||||
: "folder",
|
||||
path_core_options);
|
||||
config_file_write(conf_tmp, path_core_options, true);
|
||||
config_file_free(conf_tmp);
|
||||
conf_tmp = NULL;
|
||||
}
|
||||
path_clear(RARCH_PATH_CORE_OPTIONS);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *path = p_runloop->core_options->conf_path;
|
||||
core_option_manager_flush(
|
||||
p_runloop->core_options->conf,
|
||||
p_runloop->core_options);
|
||||
RARCH_LOG("[Core Options]: Saved core options file to \"%s\"\n", path);
|
||||
config_file_write(p_runloop->core_options->conf, path, true);
|
||||
}
|
||||
|
||||
p_runloop->game_options_active = false;
|
||||
p_runloop->folder_options_active = false;
|
||||
|
||||
if (p_runloop->core_options)
|
||||
core_option_manager_free(p_runloop->core_options);
|
||||
p_runloop->core_options = NULL;
|
||||
}
|
||||
|
||||
|
||||
retro_time_t runloop_core_runtime_tick(
|
||||
runloop_state_t *p_runloop,
|
||||
float slowmotion_ratio,
|
||||
retro_time_t current_time)
|
||||
{
|
||||
retro_time_t frame_time =
|
||||
(1.0 / p_runloop->av_info.timing.fps) * 1000000;
|
||||
bool runloop_slowmotion = p_runloop->slowmotion;
|
||||
bool runloop_fastmotion = p_runloop->fastmotion;
|
||||
|
||||
/* Account for slow motion */
|
||||
if (runloop_slowmotion)
|
||||
return (retro_time_t)((double)frame_time * slowmotion_ratio);
|
||||
|
||||
/* Account for fast forward */
|
||||
if (runloop_fastmotion)
|
||||
{
|
||||
/* Doing it this way means we miss the first frame after
|
||||
* turning fast forward on, but it saves the overhead of
|
||||
* having to do:
|
||||
* retro_time_t current_usec = cpu_features_get_time_usec();
|
||||
* libretro_core_runtime_last = current_usec;
|
||||
* every frame when fast forward is off. */
|
||||
retro_time_t current_usec = current_time;
|
||||
retro_time_t potential_frame_time = current_usec -
|
||||
p_runloop->libretro_core_runtime_last;
|
||||
p_runloop->libretro_core_runtime_last = current_usec;
|
||||
|
||||
if (potential_frame_time < frame_time)
|
||||
return potential_frame_time;
|
||||
}
|
||||
|
||||
return frame_time;
|
||||
}
|
||||
|
||||
core_option_manager_t *runloop_init_core_options(
|
||||
runloop_state_t *p_runloop,
|
||||
settings_t *settings,
|
||||
const struct retro_core_option_definition *option_defs)
|
||||
{
|
||||
char options_path[PATH_MAX_LENGTH];
|
||||
char src_options_path[PATH_MAX_LENGTH];
|
||||
|
||||
/* Ensure these are NULL-terminated */
|
||||
options_path[0] = '\0';
|
||||
src_options_path[0] = '\0';
|
||||
|
||||
/* Get core options file path */
|
||||
runloop_init_core_options_path(
|
||||
p_runloop,
|
||||
settings,
|
||||
options_path, sizeof(options_path),
|
||||
src_options_path, sizeof(src_options_path));
|
||||
|
||||
if (!string_is_empty(options_path))
|
||||
return core_option_manager_new(
|
||||
options_path, src_options_path, option_defs);
|
||||
return NULL;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user