2012-04-21 23:13:50 +02:00
/* RetroArch - A frontend for libretro.
2014-01-01 01:50:59 +01:00
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
2017-03-22 03:09:18 +01:00
* Copyright ( C ) 2011 - 2017 - Daniel De Matteis
2015-01-07 17:46:50 +01:00
* Copyright ( C ) 2012 - 2015 - Michael Lelli
2017-08-05 00:37:26 -05:00
* Copyright ( C ) 2015 - 2017 - Andrés Suárez
2014-04-12 13:25:48 +02:00
*
2012-04-21 23:13:50 +02:00
* RetroArch is free software : you can redistribute it and / or modify it under the terms
2010-05-28 18:21:33 +02:00
* 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 .
*
2012-04-21 23:13:50 +02:00
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
2010-05-28 18:21:33 +02:00
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
2012-04-21 23:31:57 +02:00
* You should have received a copy of the GNU General Public License along with RetroArch .
2010-05-28 18:21:33 +02:00
* If not , see < http : //www.gnu.org/licenses/>.
*/
2016-09-06 23:52:33 +02:00
# ifdef _WIN32
# ifdef _XBOX
# include <xtl.h>
# else
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# endif
2018-12-10 20:03:03 -05:00
# if defined(DEBUG) && defined(HAVE_DRMINGW)
# include "exchndl.h"
# endif
2016-09-06 23:52:33 +02:00
# endif
2010-05-26 21:27:37 +02:00
# include <stdlib.h>
2017-05-11 09:11:46 +02:00
# include <stdarg.h>
2014-10-15 07:00:51 +02:00
# include <stdint.h>
2010-05-26 21:27:37 +02:00
# include <string.h>
2011-09-27 15:31:25 +02:00
# include <ctype.h>
2011-10-06 23:43:48 +02:00
# include <errno.h>
2015-12-05 21:31:46 +01:00
# include <setjmp.h>
2017-05-11 09:11:46 +02:00
# include <math.h>
2019-03-07 19:17:54 -05:00
# include <locale.h>
2015-12-05 21:31:46 +01:00
2014-10-22 04:27:51 +02:00
# include <boolean.h>
2015-12-26 07:07:01 +01:00
# include <string/stdstring.h>
2016-03-20 14:53:54 +01:00
# include <lists/string_list.h>
2019-06-17 15:10:22 +02:00
# include <retro_math.h>
2017-06-28 04:41:38 +02:00
# include <retro_timers.h>
2015-06-14 16:45:20 +02:00
2019-06-17 15:10:22 +02:00
# include <gfx/scaler/pixconv.h>
# include <gfx/scaler/scaler.h>
# include <gfx/video_frame.h>
2015-06-14 16:45:20 +02:00
# include <compat/strl.h>
2019-04-16 00:42:29 -04:00
# include <compat/strcasestr.h>
2015-06-14 16:45:20 +02:00
# include <compat/getopt.h>
2019-06-17 12:49:21 +02:00
# include <audio/conversion/float_to_s16.h>
# include <audio/conversion/s16_to_float.h>
2017-05-15 01:28:34 +02:00
# include <audio/audio_mixer.h>
2019-06-17 12:49:21 +02:00
# include <audio/dsp_filter.h>
2015-06-14 16:45:20 +02:00
# include <compat/posix_string.h>
2017-12-14 20:05:46 +01:00
# include <streams/file_stream.h>
2019-06-16 16:52:48 +02:00
# include <streams/interface_stream.h>
2015-06-14 16:45:20 +02:00
# include <file/file_path.h>
2016-02-05 13:51:30 +01:00
# include <retro_assert.h>
2016-10-01 06:02:18 +02:00
# include <retro_miscellaneous.h>
2017-05-11 09:11:46 +02:00
# include <queues/message_queue.h>
# include <queues/task_queue.h>
2016-05-10 20:31:27 +02:00
# include <features/features_cpu.h>
2019-03-07 19:17:54 -05:00
# include <lists/dir_list.h>
# include <net/net_http.h>
2019-06-17 15:10:22 +02:00
# include "config.def.h"
2019-03-01 01:22:35 +01:00
# include "runtime_file.h"
2016-05-10 20:31:27 +02:00
2016-09-08 06:07:43 +02:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2019-02-27 16:47:39 +01:00
# include <audio/audio_resampler.h>
2016-09-08 06:07:43 +02:00
# ifdef HAVE_MENU
# include "menu/menu_driver.h"
2018-11-22 15:45:52 +01:00
# include "menu/menu_animation.h"
2018-09-25 16:46:15 +02:00
# include "menu/menu_input.h"
2017-05-11 09:11:46 +02:00
# include "menu/widgets/menu_dialog.h"
2017-05-25 15:40:29 +02:00
# include "menu/widgets/menu_input_dialog.h"
2019-02-21 10:23:21 +01:00
# ifdef HAVE_MENU_WIDGETS
# include "menu/widgets/menu_widgets.h"
# endif
2017-05-11 09:11:46 +02:00
# endif
# ifdef HAVE_CHEEVOS
2019-05-29 14:26:22 -03:00
# include "cheevos-new/cheevos.h"
2016-09-08 06:07:43 +02:00
# endif
2018-05-28 23:43:30 -05:00
# ifdef HAVE_DISCORD
# include "discord/discord.h"
# endif
2016-10-02 22:13:34 -04:00
# ifdef HAVE_NETWORKING
# include "network/netplay/netplay.h"
# endif
2017-05-11 09:11:46 +02:00
# if defined(HAVE_HTTPSERVER) && defined(HAVE_ZLIB)
# include "network/httpserver/httpserver.h"
# endif
# ifdef HAVE_THREADS
# include <rthreads/rthreads.h>
# endif
# include "autosave.h"
2019-01-05 13:47:05 -08:00
# include "command.h"
2016-09-08 06:07:43 +02:00
# include "config.features.h"
2016-01-19 23:15:19 +01:00
# include "content.h"
2016-03-22 02:56:06 +01:00
# include "core_type.h"
2015-12-07 08:56:11 +01:00
# include "core_info.h"
2016-03-22 03:49:05 +01:00
# include "dynamic.h"
2016-09-11 16:31:23 +02:00
# include "driver.h"
2017-05-11 09:11:46 +02:00
# include "input/input_driver.h"
2015-07-01 19:30:34 +02:00
# include "msg_hash.h"
2016-09-17 14:49:35 +02:00
# include "dirs.h"
2016-09-17 12:10:46 +02:00
# include "paths.h"
2016-06-11 21:55:55 +02:00
# include "file_path_special.h"
2017-05-11 09:11:46 +02:00
# include "ui/ui_companion_driver.h"
2015-11-23 12:03:38 +01:00
# include "verbosity.h"
2015-06-14 16:45:20 +02:00
2015-12-05 09:09:31 +01:00
# include "frontend/frontend_driver.h"
2019-03-07 19:17:54 -05:00
# ifdef HAVE_THREADS
# include "../gfx/video_thread_wrapper.h"
# endif
2019-06-17 15:10:22 +02:00
# include "../gfx/video_display_server.h"
# include "../gfx/video_crt_switch.h"
2019-02-27 16:47:39 +01:00
# include "wifi/wifi_driver.h"
# include "led/led_driver.h"
# include "midi/midi_driver.h"
2016-05-08 05:29:10 +02:00
# include "core.h"
2015-04-06 20:22:33 -05:00
# include "configuration.h"
2017-05-11 09:11:46 +02:00
# include "list_special.h"
# include "managers/core_option_manager.h"
2016-05-09 18:20:52 +02:00
# include "managers/cheat_manager.h"
2017-05-11 09:11:46 +02:00
# include "managers/state_manager.h"
2019-06-17 12:49:21 +02:00
# include "tasks/task_audio_mixer.h"
2019-01-20 03:16:58 +01:00
# include "tasks/task_content.h"
2016-05-16 17:19:16 +02:00
# include "tasks/tasks_internal.h"
2018-01-26 20:27:29 -05:00
# include "performance_counters.h"
2015-01-24 23:42:31 +01:00
2016-09-01 17:49:28 +02:00
# include "version.h"
# include "version_git.h"
2010-12-24 01:07:27 +01:00
2015-10-28 00:55:11 +01:00
# include "retroarch.h"
2018-03-29 15:38:22 +02:00
# ifdef HAVE_RUNAHEAD
2018-03-28 14:22:07 -05:00
# include "runahead/run_ahead.h"
2018-03-29 15:38:22 +02:00
# endif
2018-03-28 14:22:07 -05:00
2019-06-17 12:49:21 +02:00
# include "audio/audio_thread_wrapper.h"
2019-06-13 22:34:00 +02:00
# define _PSUPP(var, name, desc) printf(" %s:\n\t\t%s: %s\n", name, desc, var ? "yes" : "no")
2016-09-17 14:23:44 +02:00
2019-06-17 12:49:21 +02:00
# define FAIL_CPU(simd_type) do { \
RARCH_ERR ( simd_type " code is compiled in, but CPU does not support this feature. Cannot continue. \n " ) ; \
retroarch_fail ( 1 , " validate_cpu_features() " ) ; \
} while ( 0 )
# ifdef HAVE_ZLIB
# define DEFAULT_EXT "zip"
# else
# define DEFAULT_EXT ""
# endif
# define SHADER_FILE_WATCH_DELAY_MSEC 500
# define HOLD_START_DELAY_SEC 2
# define QUIT_DELAY_USEC 3 * 1000000 /* 3 seconds */
# define DEBUG_INFO_FILENAME "debug_info.txt"
/* Descriptive names for options without short variant.
*
* Please keep the name in sync with the option name .
* Order does not matter . */
enum
{
RA_OPT_MENU = 256 , /* must be outside the range of a char */
RA_OPT_STATELESS ,
RA_OPT_CHECK_FRAMES ,
RA_OPT_PORT ,
RA_OPT_SPECTATE ,
RA_OPT_NICK ,
RA_OPT_COMMAND ,
RA_OPT_APPENDCONFIG ,
RA_OPT_BPS ,
RA_OPT_IPS ,
RA_OPT_NO_PATCH ,
RA_OPT_RECORDCONFIG ,
RA_OPT_SUBSYSTEM ,
RA_OPT_SIZE ,
RA_OPT_FEATURES ,
RA_OPT_VERSION ,
RA_OPT_EOF_EXIT ,
RA_OPT_LOG_FILE ,
RA_OPT_MAX_FRAMES ,
RA_OPT_MAX_FRAMES_SCREENSHOT ,
RA_OPT_MAX_FRAMES_SCREENSHOT_PATH
} ;
enum runloop_state
{
RUNLOOP_STATE_ITERATE = 0 ,
RUNLOOP_STATE_POLLED_AND_SLEEP ,
RUNLOOP_STATE_MENU_ITERATE ,
RUNLOOP_STATE_END ,
RUNLOOP_STATE_QUIT
} ;
typedef struct runloop_ctx_msg_info
{
const char * msg ;
unsigned prio ;
unsigned duration ;
bool flush ;
} runloop_ctx_msg_info_t ;
2019-06-17 15:37:34 +02:00
static struct global g_extern ;
2019-06-17 12:49:21 +02:00
static jmp_buf error_sjlj_context ;
static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN ;
static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN ;
static char error_string [ 255 ] = { 0 } ;
static char runtime_shader_preset [ 255 ] = { 0 } ;
# ifdef HAVE_THREAD_STORAGE
static sthread_tls_t rarch_tls ;
const void * MAGIC_POINTER = ( void * ) ( uintptr_t ) 0x0DEFACED ;
# endif
static retro_bits_t has_set_libretro_device ;
static bool has_set_core = false ;
# ifdef HAVE_DISCORD
bool discord_is_inited = false ;
# endif
static bool rarch_is_inited = false ;
static bool rarch_error_on_init = false ;
static bool rarch_force_fullscreen = false ;
static bool rarch_is_switching_display_mode = false ;
static bool has_set_verbosity = false ;
static bool has_set_libretro = false ;
static bool has_set_libretro_directory = false ;
static bool has_set_save_path = false ;
static bool has_set_state_path = false ;
static bool has_set_netplay_mode = false ;
static bool has_set_netplay_ip_address = false ;
static bool has_set_netplay_ip_port = false ;
static bool has_set_netplay_stateless_mode = false ;
static bool has_set_netplay_check_frames = false ;
static bool has_set_ups_pref = false ;
static bool has_set_bps_pref = false ;
static bool has_set_ips_pref = false ;
static bool has_set_log_to_file = false ;
static bool rarch_is_sram_load_disabled = false ;
static bool rarch_is_sram_save_disabled = false ;
static bool rarch_use_sram = false ;
static bool rarch_ups_pref = false ;
static bool rarch_bps_pref = false ;
static bool rarch_ips_pref = false ;
static bool runloop_force_nonblock = false ;
static bool runloop_paused = false ;
static bool runloop_idle = false ;
static bool runloop_slowmotion = false ;
bool runloop_fastmotion = false ;
static bool runloop_shutdown_initiated = false ;
static bool runloop_core_shutdown_initiated = false ;
static bool runloop_perfcnt_enable = false ;
static bool runloop_overrides_active = false ;
static bool runloop_remaps_core_active = false ;
static bool runloop_remaps_game_active = false ;
static bool runloop_remaps_content_dir_active = false ;
static bool runloop_game_options_active = false ;
static bool runloop_autosave = false ;
static rarch_system_info_t runloop_system ;
static struct retro_frame_time_callback runloop_frame_time ;
static retro_keyboard_event_t runloop_key_event = NULL ;
static retro_keyboard_event_t runloop_frontend_key_event = NULL ;
static core_option_manager_t * runloop_core_options = NULL ;
static msg_queue_t * runloop_msg_queue = NULL ;
static unsigned runloop_pending_windowed_scale = 0 ;
static unsigned runloop_max_frames = 0 ;
static bool runloop_max_frames_screenshot = false ;
static char runloop_max_frames_screenshot_path [ PATH_MAX_LENGTH ] = { 0 } ;
static unsigned fastforward_after_frames = 0 ;
static retro_usec_t runloop_frame_time_last = 0 ;
static retro_time_t frame_limit_minimum_time = 0.0 ;
static retro_time_t frame_limit_last_time = 0.0 ;
static retro_time_t libretro_core_runtime_last = 0 ;
static retro_time_t libretro_core_runtime_usec = 0 ;
static char runtime_content_path [ PATH_MAX_LENGTH ] = { 0 } ;
static char runtime_core_path [ PATH_MAX_LENGTH ] = { 0 } ;
static bool log_file_created = false ;
static char timestamped_log_file_name [ 64 ] = { 0 } ;
static bool log_file_override_active = false ;
static char log_file_override_path [ PATH_MAX_LENGTH ] = { 0 } ;
extern bool input_driver_flushing_input ;
static char launch_arguments [ 4096 ] ;
2019-06-17 16:58:43 +02:00
/* Configuration global state */
static settings_t * configuration_settings = NULL ;
settings_t * config_get_ptr ( void )
{
return configuration_settings ;
}
2019-06-17 15:10:22 +02:00
/* Message queue */
# ifdef HAVE_THREADS
static slock_t * _runloop_msg_queue_lock = NULL ;
# define runloop_msg_queue_lock_internal() slock_lock(_runloop_msg_queue_lock)
# define runloop_msg_queue_unlock_internal() slock_unlock(_runloop_msg_queue_lock)
void runloop_msg_queue_lock ( void )
{
runloop_msg_queue_lock_internal ( ) ;
}
void runloop_msg_queue_unlock ( void )
{
runloop_msg_queue_unlock_internal ( ) ;
}
# endif
static void retroarch_msg_queue_deinit ( void )
{
# ifdef HAVE_THREADS
runloop_msg_queue_lock_internal ( ) ;
# endif
if ( ! runloop_msg_queue )
return ;
msg_queue_free ( runloop_msg_queue ) ;
# ifdef HAVE_THREADS
runloop_msg_queue_unlock_internal ( ) ;
slock_free ( _runloop_msg_queue_lock ) ;
_runloop_msg_queue_lock = NULL ;
# endif
runloop_msg_queue = NULL ;
}
static void retroarch_msg_queue_init ( void )
{
retroarch_msg_queue_deinit ( ) ;
runloop_msg_queue = msg_queue_new ( 8 ) ;
# ifdef HAVE_THREADS
_runloop_msg_queue_lock = slock_new ( ) ;
# endif
}
2019-06-17 16:23:46 +02:00
/* Recording */
static const record_driver_t * record_drivers [ ] = {
# ifdef HAVE_FFMPEG
& record_ffmpeg ,
# endif
& record_null ,
NULL ,
} ;
unsigned recording_width = 0 ;
unsigned recording_height = 0 ;
size_t recording_gpu_width = 0 ;
size_t recording_gpu_height = 0 ;
static bool recording_enable = false ;
static bool streaming_enable = false ;
static const record_driver_t * recording_driver = NULL ;
static void * recording_data = NULL ;
static uint8_t * video_driver_record_gpu_buffer = NULL ;
/**
* record_driver_find_ident :
* @ idx : index of driver to get handle to .
*
* Returns : Human - readable identifier of record driver at index . Can be NULL
* if nothing found .
* */
const char * record_driver_find_ident ( int idx )
{
const record_driver_t * drv = record_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv - > ident ;
}
/**
* record_driver_find_handle :
* @ idx : index of driver to get handle to .
*
* Returns : handle to record driver at index . Can be NULL
* if nothing found .
* */
const void * record_driver_find_handle ( int idx )
{
const void * drv = record_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv ;
}
/**
* config_get_record_driver_options :
*
* Get an enumerated list of all record driver names , separated by ' | ' .
*
* Returns : string listing of all record driver names , separated by ' | ' .
* */
const char * config_get_record_driver_options ( void )
{
return char_list_new_special ( STRING_LIST_RECORD_DRIVERS , NULL ) ;
}
#if 0
/* TODO/FIXME - not used apparently */
static void find_record_driver ( void )
{
int i ;
driver_ctx_info_t drv ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 16:23:46 +02:00
drv . label = " record_driver " ;
drv . s = settings - > arrays . record_driver ;
driver_ctl ( RARCH_DRIVER_CTL_FIND_INDEX , & drv ) ;
i = ( int ) drv . len ;
if ( i > = 0 )
recording_driver = ( const record_driver_t * ) record_driver_find_handle ( i ) ;
else
{
if ( verbosity_is_enabled ( ) )
{
unsigned d ;
RARCH_ERR ( " [recording] Couldn't find any record driver named \" %s \" \n " ,
settings - > arrays . record_driver ) ;
RARCH_LOG_OUTPUT ( " Available record drivers are: \n " ) ;
for ( d = 0 ; record_driver_find_handle ( d ) ; d + + )
RARCH_LOG_OUTPUT ( " \t %s \n " , record_driver_find_ident ( d ) ) ;
RARCH_WARN ( " [recording] Going to default to first record driver... \n " ) ;
}
recording_driver = ( const record_driver_t * ) record_driver_find_handle ( 0 ) ;
if ( ! recording_driver )
retroarch_fail ( 1 , " find_record_driver() " ) ;
}
}
/**
* ffemu_find_backend :
* @ ident : Identifier of driver to find .
*
* Finds a recording driver with the name @ ident .
*
* Returns : recording driver handle if successful , otherwise
* NULL .
* */
static const record_driver_t * ffemu_find_backend ( const char * ident )
{
unsigned i ;
for ( i = 0 ; record_drivers [ i ] ; i + + )
{
if ( string_is_equal ( record_drivers [ i ] - > ident , ident ) )
return record_drivers [ i ] ;
}
return NULL ;
}
static void recording_driver_free_state ( void )
{
/* TODO/FIXME - this is not being called anywhere */
recording_gpu_width = 0 ;
recording_gpu_height = 0 ;
recording_width = 0 ;
recording_height = 0 ;
}
# endif
/**
* gfx_ctx_init_first :
* @ backend : Recording backend handle .
* @ data : Recording data handle .
* @ params : Recording info parameters .
*
* Finds first suitable recording context driver and initializes .
*
* Returns : true ( 1 ) if successful , otherwise false ( 0 ) .
* */
static bool record_driver_init_first (
const record_driver_t * * backend , void * * data ,
const struct record_params * params )
{
unsigned i ;
for ( i = 0 ; record_drivers [ i ] ; i + + )
{
void * handle = record_drivers [ i ] - > init ( params ) ;
if ( ! handle )
continue ;
* backend = record_drivers [ i ] ;
* data = handle ;
return true ;
}
return false ;
}
static void recording_dump_frame ( const void * data , unsigned width ,
unsigned height , size_t pitch , bool is_idle )
{
struct record_video_data ffemu_data ;
ffemu_data . data = data ;
ffemu_data . width = width ;
ffemu_data . height = height ;
ffemu_data . pitch = ( int ) pitch ;
ffemu_data . is_dupe = false ;
if ( video_driver_record_gpu_buffer ! = NULL )
{
struct video_viewport vp ;
vp . x = 0 ;
vp . y = 0 ;
vp . width = 0 ;
vp . height = 0 ;
vp . full_width = 0 ;
vp . full_height = 0 ;
video_driver_get_viewport_info ( & vp ) ;
if ( ! vp . width | | ! vp . height )
{
RARCH_WARN ( " [recording] %s \n " ,
msg_hash_to_str ( MSG_VIEWPORT_SIZE_CALCULATION_FAILED ) ) ;
command_event ( CMD_EVENT_GPU_RECORD_DEINIT , NULL ) ;
recording_dump_frame ( data , width , height , pitch , is_idle ) ;
return ;
}
/* User has resized. We kinda have a problem now. */
if ( vp . width ! = recording_gpu_width | |
vp . height ! = recording_gpu_height )
{
RARCH_WARN ( " [recording] %s \n " , msg_hash_to_str ( MSG_RECORDING_TERMINATED_DUE_TO_RESIZE ) ) ;
runloop_msg_queue_push (
msg_hash_to_str ( MSG_RECORDING_TERMINATED_DUE_TO_RESIZE ) ,
1 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
command_event ( CMD_EVENT_RECORD_DEINIT , NULL ) ;
return ;
}
/* Big bottleneck.
* Since we might need to do read - backs asynchronously ,
* it might take 3 - 4 times before this returns true . */
if ( ! video_driver_read_viewport ( video_driver_record_gpu_buffer , is_idle ) )
return ;
ffemu_data . pitch = ( int ) ( recording_gpu_width * 3 ) ;
ffemu_data . width = ( unsigned ) recording_gpu_width ;
ffemu_data . height = ( unsigned ) recording_gpu_height ;
ffemu_data . data = video_driver_record_gpu_buffer + ( ffemu_data . height - 1 ) * ffemu_data . pitch ;
ffemu_data . pitch = - ffemu_data . pitch ;
}
else
ffemu_data . is_dupe = ! data ;
recording_driver - > push_video ( recording_data , & ffemu_data ) ;
}
bool recording_deinit ( void )
{
if ( ! recording_data | | ! recording_driver )
return false ;
if ( recording_driver - > finalize )
recording_driver - > finalize ( recording_data ) ;
if ( recording_driver - > free )
recording_driver - > free ( recording_data ) ;
recording_data = NULL ;
recording_driver = NULL ;
command_event ( CMD_EVENT_GPU_RECORD_DEINIT , NULL ) ;
return true ;
}
bool recording_is_enabled ( void )
{
return recording_enable ;
}
void recording_set_state ( bool state )
{
recording_enable = state ;
}
bool streaming_is_enabled ( void )
{
return streaming_enable ;
}
void streaming_set_state ( bool state )
{
streaming_enable = state ;
}
/**
* recording_init :
*
* Initializes recording .
*
* Returns : true ( 1 ) if successful , otherwise false ( 0 ) .
* */
bool recording_init ( void )
{
char output [ PATH_MAX_LENGTH ] ;
char buf [ PATH_MAX_LENGTH ] ;
struct record_params params = { 0 } ;
struct retro_system_av_info * av_info = video_viewport_get_system_av_info ( ) ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 16:23:46 +02:00
global_t * global = & g_extern ;
if ( ! recording_enable )
return false ;
output [ 0 ] = ' \0 ' ;
if ( rarch_ctl ( RARCH_CTL_IS_DUMMY_CORE , NULL ) )
{
RARCH_WARN ( " [recording] %s \n " ,
msg_hash_to_str ( MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED ) ) ;
return false ;
}
if ( ! settings - > bools . video_gpu_record
& & video_driver_is_hw_context ( ) )
{
RARCH_WARN ( " [recording] %s. \n " ,
msg_hash_to_str ( MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING ) ) ;
return false ;
}
RARCH_LOG ( " [recording] %s: FPS: %.4f, Sample rate: %.4f \n " ,
msg_hash_to_str ( MSG_CUSTOM_TIMING_GIVEN ) ,
( float ) av_info - > timing . fps ,
( float ) av_info - > timing . sample_rate ) ;
if ( ! string_is_empty ( global - > record . path ) )
strlcpy ( output , global - > record . path , sizeof ( output ) ) ;
else
{
if ( streaming_is_enabled ( ) )
if ( ! string_is_empty ( settings - > paths . path_stream_url ) )
strlcpy ( output , settings - > paths . path_stream_url , sizeof ( output ) ) ;
else
/* Fallback, stream locally to 127.0.0.1 */
snprintf ( output , sizeof ( output ) , " udp://127.0.0.1:%u " , settings - > uints . video_stream_port ) ;
else
{
const char * game_name = path_basename ( path_get ( RARCH_PATH_BASENAME ) ) ;
if ( settings - > uints . video_record_quality < RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST )
{
fill_str_dated_filename ( buf , game_name ,
" mkv " , sizeof ( buf ) ) ;
fill_pathname_join ( output , global - > record . output_dir , buf , sizeof ( output ) ) ;
}
else if ( settings - > uints . video_record_quality > = RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST & & settings - > uints . video_record_quality < RECORD_CONFIG_TYPE_RECORDING_GIF )
{
fill_str_dated_filename ( buf , game_name ,
" webm " , sizeof ( buf ) ) ;
fill_pathname_join ( output , global - > record . output_dir , buf , sizeof ( output ) ) ;
}
else if ( settings - > uints . video_record_quality > = RECORD_CONFIG_TYPE_RECORDING_GIF & & settings - > uints . video_record_quality < RECORD_CONFIG_TYPE_RECORDING_APNG )
{
fill_str_dated_filename ( buf , game_name ,
" gif " , sizeof ( buf ) ) ;
fill_pathname_join ( output , global - > record . output_dir , buf , sizeof ( output ) ) ;
}
else
{
fill_str_dated_filename ( buf , game_name ,
" png " , sizeof ( buf ) ) ;
fill_pathname_join ( output , global - > record . output_dir , buf , sizeof ( output ) ) ;
}
}
}
params . out_width = av_info - > geometry . base_width ;
params . out_height = av_info - > geometry . base_height ;
params . fb_width = av_info - > geometry . max_width ;
params . fb_height = av_info - > geometry . max_height ;
params . channels = 2 ;
params . filename = output ;
params . fps = av_info - > timing . fps ;
params . samplerate = av_info - > timing . sample_rate ;
params . pix_fmt = ( video_driver_get_pixel_format ( ) = = RETRO_PIXEL_FORMAT_XRGB8888 ) ?
FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565 ;
params . config = NULL ;
if ( ! string_is_empty ( global - > record . config ) )
params . config = global - > record . config ;
else
{
if ( streaming_is_enabled ( ) )
{
params . config = settings - > paths . path_stream_config ;
params . preset = ( enum record_config_type )
settings - > uints . video_stream_quality ;
}
else
{
params . config = settings - > paths . path_record_config ;
params . preset = ( enum record_config_type )
settings - > uints . video_record_quality ;
}
}
if ( video_driver_supports_recording ( ) )
{
unsigned gpu_size ;
struct video_viewport vp ;
vp . x = 0 ;
vp . y = 0 ;
vp . width = 0 ;
vp . height = 0 ;
vp . full_width = 0 ;
vp . full_height = 0 ;
video_driver_get_viewport_info ( & vp ) ;
if ( ! vp . width | | ! vp . height )
{
RARCH_ERR ( " [recording] Failed to get viewport information from video driver. "
" Cannot start recording ... \n " ) ;
return false ;
}
params . out_width = vp . width ;
params . out_height = vp . height ;
params . fb_width = next_pow2 ( vp . width ) ;
params . fb_height = next_pow2 ( vp . height ) ;
if ( settings - > bools . video_force_aspect & &
( video_driver_get_aspect_ratio ( ) > 0.0f ) )
params . aspect_ratio = video_driver_get_aspect_ratio ( ) ;
else
params . aspect_ratio = ( float ) vp . width / vp . height ;
params . pix_fmt = FFEMU_PIX_BGR24 ;
recording_gpu_width = vp . width ;
recording_gpu_height = vp . height ;
RARCH_LOG ( " [recording] %s %u x %u \n " , msg_hash_to_str ( MSG_DETECTED_VIEWPORT_OF ) ,
vp . width , vp . height ) ;
gpu_size = vp . width * vp . height * 3 ;
if ( ! video_driver_gpu_record_init ( gpu_size ) )
return false ;
}
else
{
if ( recording_width | | recording_height )
{
params . out_width = recording_width ;
params . out_height = recording_height ;
}
if ( settings - > bools . video_force_aspect & &
( video_driver_get_aspect_ratio ( ) > 0.0f ) )
params . aspect_ratio = video_driver_get_aspect_ratio ( ) ;
else
params . aspect_ratio = ( float ) params . out_width / params . out_height ;
if ( settings - > bools . video_post_filter_record
& & video_driver_frame_filter_alive ( ) )
{
unsigned max_width = 0 ;
unsigned max_height = 0 ;
params . pix_fmt = FFEMU_PIX_RGB565 ;
if ( video_driver_frame_filter_is_32bit ( ) )
params . pix_fmt = FFEMU_PIX_ARGB8888 ;
rarch_softfilter_get_max_output_size (
video_driver_frame_filter_get_ptr ( ) ,
& max_width , & max_height ) ;
params . fb_width = next_pow2 ( max_width ) ;
params . fb_height = next_pow2 ( max_height ) ;
}
}
RARCH_LOG ( " [recording] %s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u) \n " ,
msg_hash_to_str ( MSG_RECORDING_TO ) ,
output ,
params . out_width , params . out_height ,
params . fb_width , params . fb_height ,
( unsigned ) params . pix_fmt ) ;
if ( ! record_driver_init_first ( & recording_driver , & recording_data , & params ) )
{
RARCH_ERR ( " [recording] %s \n " , msg_hash_to_str ( MSG_FAILED_TO_START_RECORDING ) ) ;
command_event ( CMD_EVENT_GPU_RECORD_DEINIT , NULL ) ;
return false ;
}
return true ;
}
void * recording_driver_get_data_ptr ( void )
{
return recording_data ;
}
void recording_driver_update_streaming_url ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 16:23:46 +02:00
const char * youtube_url = " rtmp://a.rtmp.youtube.com/live2/ " ;
const char * twitch_url = " rtmp://live.twitch.tv/app/ " ;
if ( ! settings )
return ;
switch ( settings - > uints . streaming_mode )
{
case STREAMING_MODE_TWITCH :
{
if ( ! string_is_empty ( settings - > arrays . twitch_stream_key ) )
snprintf ( settings - > paths . path_stream_url , sizeof ( settings - > paths . path_stream_url ) ,
" %s%s " , twitch_url , settings - > arrays . twitch_stream_key ) ;
else
{
/* To-Do: Show input box for twitch_stream_key*/
RARCH_LOG ( " [recording] twitch streaming key empty \n " ) ;
}
break ;
}
case STREAMING_MODE_YOUTUBE :
{
if ( ! string_is_empty ( settings - > arrays . youtube_stream_key ) )
{
snprintf ( settings - > paths . path_stream_url , sizeof ( settings - > paths . path_stream_url ) ,
" %s%s " , youtube_url , settings - > arrays . youtube_stream_key ) ;
}
else
{
/* To-Do: Show input box for youtube_stream_key*/
RARCH_LOG ( " [recording] youtube streaming key empty \n " ) ;
}
break ;
}
case STREAMING_MODE_LOCAL :
/* To-Do: figure out default interface and bind to that instead */
snprintf ( settings - > paths . path_stream_url , sizeof ( settings - > paths . path_stream_url ) ,
" udp://%s:%u " , " 127.0.0.1 " , settings - > uints . video_stream_port ) ;
break ;
case STREAMING_MODE_CUSTOM :
default :
/* Do nothing, let the user input the URL */
break ;
}
}
2019-06-17 12:49:21 +02:00
/* Audio */
# define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
# define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac"
/**
* db_to_gain :
* @ db : Decibels .
*
* Converts decibels to voltage gain .
*
* Returns : voltage gain value .
* */
# define db_to_gain(db) (powf(10.0f, (db) / 20.0f))
static const audio_driver_t * audio_drivers [ ] = {
# ifdef HAVE_ALSA
& audio_alsa ,
# if !defined(__QNX__) && defined(HAVE_THREADS)
& audio_alsathread ,
# endif
# endif
# ifdef HAVE_TINYALSA
& audio_tinyalsa ,
# endif
# if defined(HAVE_AUDIOIO)
& audio_audioio ,
# endif
# if defined(HAVE_OSS) || defined(HAVE_OSS_BSD)
& audio_oss ,
# endif
# ifdef HAVE_RSOUND
& audio_rsound ,
# endif
# ifdef HAVE_COREAUDIO
& audio_coreaudio ,
# endif
# ifdef HAVE_COREAUDIO3
& audio_coreaudio3 ,
# endif
# ifdef HAVE_AL
& audio_openal ,
# endif
# ifdef HAVE_SL
& audio_opensl ,
# endif
# ifdef HAVE_ROAR
& audio_roar ,
# endif
# ifdef HAVE_JACK
& audio_jack ,
# endif
# if defined(HAVE_SDL) || defined(HAVE_SDL2)
& audio_sdl ,
# endif
# ifdef HAVE_XAUDIO
& audio_xa ,
# endif
# ifdef HAVE_DSOUND
& audio_dsound ,
# endif
# ifdef HAVE_WASAPI
& audio_wasapi ,
# endif
# ifdef HAVE_PULSE
& audio_pulse ,
# endif
# ifdef __CELLOS_LV2__
& audio_ps3 ,
# endif
# ifdef XENON
& audio_xenon360 ,
# endif
# ifdef GEKKO
& audio_gx ,
# endif
# ifdef WIIU
& audio_ax ,
# endif
# ifdef EMSCRIPTEN
& audio_rwebaudio ,
# endif
# if defined(PSP) || defined(VITA) || defined(ORBIS)
& audio_psp ,
# endif
# if defined(PS2)
& audio_ps2 ,
# endif
# ifdef _3DS
& audio_ctr_csnd ,
& audio_ctr_dsp ,
# endif
# ifdef SWITCH
& audio_switch_thread ,
& audio_switch ,
# endif
& audio_null ,
NULL ,
} ;
static struct audio_mixer_stream audio_mixer_streams [ AUDIO_MIXER_MAX_SYSTEM_STREAMS ] = { { 0 } } ;
static size_t audio_driver_chunk_size = 0 ;
static size_t audio_driver_chunk_nonblock_size = 0 ;
static size_t audio_driver_chunk_block_size = 0 ;
static size_t audio_driver_rewind_ptr = 0 ;
static size_t audio_driver_rewind_size = 0 ;
static int16_t * audio_driver_rewind_buf = NULL ;
static int16_t * audio_driver_output_samples_conv_buf = NULL ;
static unsigned audio_driver_free_samples_buf [ AUDIO_BUFFER_FREE_SAMPLES_COUNT ] ;
static uint64_t audio_driver_free_samples_count = 0 ;
static size_t audio_driver_buffer_size = 0 ;
static size_t audio_driver_data_ptr = 0 ;
static bool audio_driver_control = false ;
static bool audio_driver_mixer_mute_enable = false ;
static bool audio_driver_mute_enable = false ;
static bool audio_driver_use_float = false ;
static bool audio_driver_active = false ;
static bool audio_mixer_active = false ;
static float audio_driver_rate_control_delta = 0.0f ;
static float audio_driver_input = 0.0f ;
static float audio_driver_volume_gain = 0.0f ;
static float audio_driver_mixer_volume_gain = 0.0f ;
static float * audio_driver_input_data = NULL ;
static float * audio_driver_output_samples_buf = NULL ;
static double audio_source_ratio_original = 0.0f ;
static double audio_source_ratio_current = 0.0f ;
static struct retro_audio_callback audio_callback = { 0 } ;
static retro_dsp_filter_t * audio_driver_dsp = NULL ;
static struct string_list * audio_driver_devices_list = NULL ;
static const retro_resampler_t * audio_driver_resampler = NULL ;
static void * audio_driver_resampler_data = NULL ;
static const audio_driver_t * current_audio = NULL ;
static void * audio_driver_context_audio_data = NULL ;
static bool audio_suspended = false ;
static bool audio_is_threaded = false ;
static void audio_mixer_play_stop_sequential_cb (
audio_mixer_sound_t * sound , unsigned reason ) ;
static void audio_mixer_play_stop_cb (
audio_mixer_sound_t * sound , unsigned reason ) ;
static void audio_mixer_menu_stop_cb (
audio_mixer_sound_t * sound , unsigned reason ) ;
static enum resampler_quality audio_driver_get_resampler_quality ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
if ( ! settings )
return RESAMPLER_QUALITY_DONTCARE ;
return ( enum resampler_quality ) settings - > uints . audio_resampler_quality ;
}
audio_mixer_stream_t * audio_driver_mixer_get_stream ( unsigned i )
{
if ( i > ( AUDIO_MIXER_MAX_SYSTEM_STREAMS - 1 ) )
return NULL ;
return & audio_mixer_streams [ i ] ;
}
const char * audio_driver_mixer_get_stream_name ( unsigned i )
{
if ( i > ( AUDIO_MIXER_MAX_SYSTEM_STREAMS - 1 ) )
return " N/A " ;
if ( ! string_is_empty ( audio_mixer_streams [ i ] . name ) )
return audio_mixer_streams [ i ] . name ;
return " N/A " ;
}
/**
* compute_audio_buffer_statistics :
*
* Computes audio buffer statistics .
*
* */
bool compute_audio_buffer_statistics ( audio_statistics_t * stats )
{
unsigned i , low_water_size , high_water_size , avg , stddev ;
uint64_t accum = 0 ;
uint64_t accum_var = 0 ;
unsigned low_water_count = 0 ;
unsigned high_water_count = 0 ;
unsigned samples = MIN (
( unsigned ) audio_driver_free_samples_count ,
AUDIO_BUFFER_FREE_SAMPLES_COUNT ) ;
if ( ! stats | | samples < 3 )
return false ;
stats - > samples = ( unsigned ) audio_driver_free_samples_count ;
# ifdef WARPUP
/* uint64 to double not implemented, fair chance
* signed int64 to double doesn ' t exist either */
/* https://forums.libretro.com/t/unsupported-platform-help/13903/ */
( void ) stddev ;
# elif defined(_MSC_VER) && _MSC_VER <= 1200
/* FIXME: error C2520: conversion from unsigned __int64
* to double not implemented , use signed __int64 */
( void ) stddev ;
# else
for ( i = 1 ; i < samples ; i + + )
accum + = audio_driver_free_samples_buf [ i ] ;
avg = ( unsigned ) accum / ( samples - 1 ) ;
for ( i = 1 ; i < samples ; i + + )
{
int diff = avg - audio_driver_free_samples_buf [ i ] ;
accum_var + = diff * diff ;
}
stddev = ( unsigned )
sqrt ( ( double ) accum_var / ( samples - 2 ) ) ;
stats - > average_buffer_saturation = ( 1.0f - ( float ) avg
/ audio_driver_buffer_size ) * 100.0 ;
stats - > std_deviation_percentage = ( ( float ) stddev
/ audio_driver_buffer_size ) * 100.0 ;
# endif
low_water_size = ( unsigned ) ( audio_driver_buffer_size * 3 / 4 ) ;
high_water_size = ( unsigned ) ( audio_driver_buffer_size / 4 ) ;
for ( i = 1 ; i < samples ; i + + )
{
if ( audio_driver_free_samples_buf [ i ] > = low_water_size )
low_water_count + + ;
else if ( audio_driver_free_samples_buf [ i ] < = high_water_size )
high_water_count + + ;
}
stats - > close_to_underrun = ( 100.0 * low_water_count ) / ( samples - 1 ) ;
stats - > close_to_blocking = ( 100.0 * high_water_count ) / ( samples - 1 ) ;
return true ;
}
static void report_audio_buffer_statistics ( void )
{
audio_statistics_t audio_stats = { 0.0f } ;
if ( ! compute_audio_buffer_statistics ( & audio_stats ) )
return ;
# ifdef DEBUG
RARCH_LOG ( " [Audio]: Average audio buffer saturation: %.2f %%, "
" standard deviation (percentage points): %.2f %%. \n "
" [Audio]: Amount of time spent close to underrun: %.2f %%. "
" Close to blocking: %.2f %%. \n " ,
audio_stats . average_buffer_saturation ,
audio_stats . std_deviation_percentage ,
audio_stats . close_to_underrun ,
audio_stats . close_to_blocking ) ;
# endif
}
/**
* audio_driver_find_handle :
* @ idx : index of driver to get handle to .
*
* Returns : handle to audio driver at index . Can be NULL
* if nothing found .
* */
const void * audio_driver_find_handle ( int idx )
{
const void * drv = audio_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv ;
}
/**
* audio_driver_find_ident :
* @ idx : index of driver to get handle to .
*
* Returns : Human - readable identifier of audio driver at index . Can be NULL
* if nothing found .
* */
const char * audio_driver_find_ident ( int idx )
{
const audio_driver_t * drv = audio_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv - > ident ;
}
/**
* config_get_audio_driver_options :
*
* Get an enumerated list of all audio driver names , separated by ' | ' .
*
* Returns : string listing of all audio driver names , separated by ' | ' .
* */
const char * config_get_audio_driver_options ( void )
{
return char_list_new_special ( STRING_LIST_AUDIO_DRIVERS , NULL ) ;
}
static void audio_driver_deinit_resampler ( void )
{
if ( audio_driver_resampler & & audio_driver_resampler_data )
audio_driver_resampler - > free ( audio_driver_resampler_data ) ;
audio_driver_resampler = NULL ;
audio_driver_resampler_data = NULL ;
}
static bool audio_driver_deinit_internal ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
if ( current_audio & & current_audio - > free )
{
if ( audio_driver_context_audio_data )
current_audio - > free ( audio_driver_context_audio_data ) ;
audio_driver_context_audio_data = NULL ;
}
if ( audio_driver_output_samples_conv_buf )
free ( audio_driver_output_samples_conv_buf ) ;
audio_driver_output_samples_conv_buf = NULL ;
audio_driver_data_ptr = 0 ;
if ( audio_driver_rewind_buf )
free ( audio_driver_rewind_buf ) ;
audio_driver_rewind_buf = NULL ;
audio_driver_rewind_size = 0 ;
if ( settings & & ! settings - > bools . audio_enable )
{
audio_driver_active = false ;
return false ;
}
audio_driver_deinit_resampler ( ) ;
if ( audio_driver_input_data )
free ( audio_driver_input_data ) ;
audio_driver_input_data = NULL ;
if ( audio_driver_output_samples_buf )
free ( audio_driver_output_samples_buf ) ;
audio_driver_output_samples_buf = NULL ;
command_event ( CMD_EVENT_DSP_FILTER_DEINIT , NULL ) ;
report_audio_buffer_statistics ( ) ;
return true ;
}
static void audio_driver_mixer_deinit ( void )
{
unsigned i ;
audio_mixer_active = false ;
for ( i = 0 ; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS ; i + + )
{
audio_driver_mixer_stop_stream ( i ) ;
audio_driver_mixer_remove_stream ( i ) ;
}
audio_mixer_done ( ) ;
}
static bool audio_driver_free_devices_list ( void )
{
if ( ! current_audio | | ! current_audio - > device_list_free
| | ! audio_driver_context_audio_data )
return false ;
current_audio - > device_list_free ( audio_driver_context_audio_data ,
audio_driver_devices_list ) ;
audio_driver_devices_list = NULL ;
return true ;
}
static bool audio_driver_deinit ( void )
{
audio_driver_mixer_deinit ( ) ;
audio_driver_free_devices_list ( ) ;
if ( ! audio_driver_deinit_internal ( ) )
return false ;
return true ;
}
static void audio_driver_mixer_init ( unsigned audio_out_rate )
{
audio_mixer_init ( audio_out_rate ) ;
}
static bool audio_driver_find_driver ( void )
{
int i ;
driver_ctx_info_t drv ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
drv . label = " audio_driver " ;
drv . s = settings - > arrays . audio_driver ;
driver_ctl ( RARCH_DRIVER_CTL_FIND_INDEX , & drv ) ;
i = ( int ) drv . len ;
if ( i > = 0 )
current_audio = ( const audio_driver_t * ) audio_driver_find_handle ( i ) ;
else
{
if ( verbosity_is_enabled ( ) )
{
unsigned d ;
RARCH_ERR ( " Couldn't find any audio driver named \" %s \" \n " ,
settings - > arrays . audio_driver ) ;
RARCH_LOG_OUTPUT ( " Available audio drivers are: \n " ) ;
for ( d = 0 ; audio_driver_find_handle ( d ) ; d + + )
RARCH_LOG_OUTPUT ( " \t %s \n " , audio_driver_find_ident ( d ) ) ;
RARCH_WARN ( " Going to default to first audio driver... \n " ) ;
}
current_audio = ( const audio_driver_t * ) audio_driver_find_handle ( 0 ) ;
if ( ! current_audio )
retroarch_fail ( 1 , " audio_driver_find() " ) ;
}
return true ;
}
static bool audio_driver_init_internal ( bool audio_cb_inited )
{
unsigned new_rate = 0 ;
float * aud_inp_data = NULL ;
float * samples_buf = NULL ;
int16_t * conv_buf = NULL ;
int16_t * rewind_buf = NULL ;
size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
/* Accomodate rewind since at some point we might have two full buffers. */
size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO *
settings - > floats . slowmotion_ratio ;
convert_s16_to_float_init_simd ( ) ;
convert_float_to_s16_init_simd ( ) ;
conv_buf = ( int16_t * ) malloc ( outsamples_max
* sizeof ( int16_t ) ) ;
/* Used for recording even if audio isn't enabled. */
retro_assert ( conv_buf ! = NULL ) ;
if ( ! conv_buf )
goto error ;
audio_driver_output_samples_conv_buf = conv_buf ;
audio_driver_chunk_block_size = AUDIO_CHUNK_SIZE_BLOCKING ;
audio_driver_chunk_nonblock_size = AUDIO_CHUNK_SIZE_NONBLOCKING ;
audio_driver_chunk_size = audio_driver_chunk_block_size ;
/* Needs to be able to hold full content of a full max_bufsamples
* in addition to its own . */
rewind_buf = ( int16_t * ) malloc ( max_bufsamples * sizeof ( int16_t ) ) ;
retro_assert ( rewind_buf ! = NULL ) ;
if ( ! rewind_buf )
goto error ;
audio_driver_rewind_buf = rewind_buf ;
audio_driver_rewind_size = max_bufsamples ;
if ( ! settings - > bools . audio_enable )
{
audio_driver_active = false ;
return false ;
}
audio_driver_find_driver ( ) ;
# ifdef HAVE_THREADS
if ( audio_cb_inited )
{
audio_is_threaded = true ;
RARCH_LOG ( " [Audio]: Starting threaded audio driver ... \n " ) ;
if ( ! audio_init_thread (
& current_audio ,
& audio_driver_context_audio_data ,
* settings - > arrays . audio_device
? settings - > arrays . audio_device : NULL ,
settings - > uints . audio_out_rate , & new_rate ,
settings - > uints . audio_latency ,
settings - > uints . audio_block_frames ,
current_audio ) )
{
RARCH_ERR ( " Cannot open threaded audio driver ... Exiting ... \n " ) ;
retroarch_fail ( 1 , " audio_driver_init_internal() " ) ;
}
}
else
# endif
{
audio_is_threaded = false ;
audio_driver_context_audio_data =
current_audio - > init ( * settings - > arrays . audio_device ?
settings - > arrays . audio_device : NULL ,
settings - > uints . audio_out_rate ,
settings - > uints . audio_latency ,
settings - > uints . audio_block_frames ,
& new_rate ) ;
}
if ( new_rate ! = 0 )
{
configuration_set_int ( settings , settings - > uints . audio_out_rate , new_rate ) ;
}
if ( ! audio_driver_context_audio_data )
{
RARCH_ERR ( " Failed to initialize audio driver. Will continue without audio. \n " ) ;
audio_driver_active = false ;
}
audio_driver_use_float = false ;
if ( audio_driver_active
& & current_audio - > use_float ( audio_driver_context_audio_data ) )
audio_driver_use_float = true ;
if ( ! settings - > bools . audio_sync & & audio_driver_active )
{
command_event ( CMD_EVENT_AUDIO_SET_NONBLOCKING_STATE , NULL ) ;
audio_driver_chunk_size = audio_driver_chunk_nonblock_size ;
}
if ( audio_driver_input < = 0.0f )
{
/* Should never happen. */
RARCH_WARN ( " Input rate is invalid (%.3f Hz). Using output rate (%u Hz). \n " ,
audio_driver_input , settings - > uints . audio_out_rate ) ;
audio_driver_input = settings - > uints . audio_out_rate ;
}
audio_source_ratio_original = audio_source_ratio_current =
( double ) settings - > uints . audio_out_rate / audio_driver_input ;
if ( ! retro_resampler_realloc (
& audio_driver_resampler_data ,
& audio_driver_resampler ,
settings - > arrays . audio_resampler ,
audio_driver_get_resampler_quality ( ) ,
audio_source_ratio_original ) )
{
RARCH_ERR ( " Failed to initialize resampler \" %s \" . \n " ,
settings - > arrays . audio_resampler ) ;
audio_driver_active = false ;
}
aud_inp_data = ( float * ) malloc ( max_bufsamples * sizeof ( float ) ) ;
retro_assert ( aud_inp_data ! = NULL ) ;
if ( ! aud_inp_data )
goto error ;
audio_driver_input_data = aud_inp_data ;
audio_driver_data_ptr = 0 ;
retro_assert ( settings - > uints . audio_out_rate <
audio_driver_input * AUDIO_MAX_RATIO ) ;
samples_buf = ( float * ) malloc ( outsamples_max * sizeof ( float ) ) ;
retro_assert ( samples_buf ! = NULL ) ;
if ( ! samples_buf )
goto error ;
audio_driver_output_samples_buf = samples_buf ;
audio_driver_control = false ;
if (
! audio_cb_inited
& & audio_driver_active
& & settings - > bools . audio_rate_control
)
{
/* Audio rate control requires write_avail
* and buffer_size to be implemented . */
if ( current_audio - > buffer_size )
{
audio_driver_buffer_size =
current_audio - > buffer_size ( audio_driver_context_audio_data ) ;
audio_driver_control = true ;
}
else
RARCH_WARN ( " Audio rate control was desired, but driver does not support needed features. \n " ) ;
}
command_event ( CMD_EVENT_DSP_FILTER_INIT , NULL ) ;
audio_driver_free_samples_count = 0 ;
audio_driver_mixer_init ( settings - > uints . audio_out_rate ) ;
/* Threaded driver is initially stopped. */
if (
audio_driver_active
& & audio_cb_inited
)
audio_driver_start ( false ) ;
return true ;
error :
return audio_driver_deinit ( ) ;
}
void audio_driver_set_nonblocking_state ( bool enable )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
if (
audio_driver_active
& & audio_driver_context_audio_data
)
current_audio - > set_nonblock_state (
audio_driver_context_audio_data ,
settings - > bools . audio_sync ? enable : true ) ;
audio_driver_chunk_size = enable ?
audio_driver_chunk_nonblock_size :
audio_driver_chunk_block_size ;
}
/**
* audio_driver_flush :
* @ data : pointer to audio buffer .
* @ right : amount of samples to write .
*
* Writes audio samples to audio driver . Will first
* perform DSP processing ( if enabled ) and resampling .
* */
static void audio_driver_flush ( const int16_t * data , size_t samples ,
bool is_slowmotion )
{
struct resampler_data src_data ;
float audio_volume_gain = ! audio_driver_mute_enable ?
audio_driver_volume_gain : 0.0f ;
src_data . data_out = NULL ;
src_data . output_frames = 0 ;
convert_s16_to_float ( audio_driver_input_data , data , samples ,
audio_volume_gain ) ;
src_data . data_in = audio_driver_input_data ;
src_data . input_frames = samples > > 1 ;
if ( audio_driver_dsp )
{
struct retro_dsp_data dsp_data ;
dsp_data . input = NULL ;
dsp_data . input_frames = 0 ;
dsp_data . output = NULL ;
dsp_data . output_frames = 0 ;
dsp_data . input = audio_driver_input_data ;
dsp_data . input_frames = ( unsigned ) ( samples > > 1 ) ;
retro_dsp_filter_process ( audio_driver_dsp , & dsp_data ) ;
if ( dsp_data . output )
{
src_data . data_in = dsp_data . output ;
src_data . input_frames = dsp_data . output_frames ;
}
}
src_data . data_out = audio_driver_output_samples_buf ;
if ( audio_driver_control )
{
/* Readjust the audio input rate. */
int half_size = ( int ) ( audio_driver_buffer_size / 2 ) ;
int avail =
( int ) current_audio - > write_avail ( audio_driver_context_audio_data ) ;
int delta_mid = avail - half_size ;
double direction = ( double ) delta_mid / half_size ;
double adjust = 1.0 + audio_driver_rate_control_delta * direction ;
unsigned write_idx = audio_driver_free_samples_count + + &
( AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1 ) ;
audio_driver_free_samples_buf
[ write_idx ] = avail ;
audio_source_ratio_current =
audio_source_ratio_original * adjust ;
#if 0
if ( verbosity_is_enabled ( ) )
{
RARCH_LOG_OUTPUT ( " [Audio]: Audio buffer is %u%% full \n " ,
( unsigned ) ( 100 - ( avail * 100 ) / audio_driver_buffer_size ) ) ;
RARCH_LOG_OUTPUT ( " [Audio]: New rate: %lf, Orig rate: %lf \n " ,
audio_source_ratio_current ,
audio_source_ratio_original ) ;
}
# endif
}
src_data . ratio = audio_source_ratio_current ;
if ( is_slowmotion )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
src_data . ratio * = settings - > floats . slowmotion_ratio ;
}
audio_driver_resampler - > process ( audio_driver_resampler_data , & src_data ) ;
if ( audio_mixer_active )
{
bool override = audio_driver_mixer_mute_enable ? true :
( audio_driver_mixer_volume_gain ! = 1.0f ) ? true : false ;
float mixer_gain = ! audio_driver_mixer_mute_enable ?
audio_driver_mixer_volume_gain : 0.0f ;
audio_mixer_mix ( audio_driver_output_samples_buf ,
src_data . output_frames , mixer_gain , override ) ;
}
{
const void * output_data = audio_driver_output_samples_buf ;
unsigned output_frames = ( unsigned ) src_data . output_frames ;
if ( audio_driver_use_float )
output_frames * = sizeof ( float ) ;
else
{
convert_float_to_s16 ( audio_driver_output_samples_conv_buf ,
( const float * ) output_data , output_frames * 2 ) ;
output_data = audio_driver_output_samples_conv_buf ;
output_frames * = sizeof ( int16_t ) ;
}
if ( current_audio - > write ( audio_driver_context_audio_data ,
output_data , output_frames * 2 ) < 0 )
audio_driver_active = false ;
}
}
/**
* audio_driver_sample :
* @ left : value of the left audio channel .
* @ right : value of the right audio channel .
*
* Audio sample render callback function .
* */
void audio_driver_sample ( int16_t left , int16_t right )
{
if ( audio_suspended )
return ;
audio_driver_output_samples_conv_buf [ audio_driver_data_ptr + + ] = left ;
audio_driver_output_samples_conv_buf [ audio_driver_data_ptr + + ] = right ;
if ( audio_driver_data_ptr < audio_driver_chunk_size )
return ;
2019-06-17 16:23:46 +02:00
if ( recording_data & & recording_driver & & recording_driver - > push_audio )
{
struct record_audio_data ffemu_data ;
ffemu_data . data = audio_driver_output_samples_conv_buf ;
ffemu_data . frames = audio_driver_data_ptr / 2 ;
recording_driver - > push_audio ( recording_data , & ffemu_data ) ;
}
2019-06-17 12:49:21 +02:00
if ( ! ( runloop_paused | |
! audio_driver_active | |
! audio_driver_input_data | |
! audio_driver_output_samples_buf ) )
audio_driver_flush ( audio_driver_output_samples_conv_buf ,
audio_driver_data_ptr , runloop_slowmotion ) ;
audio_driver_data_ptr = 0 ;
}
static void audio_driver_menu_sample ( void )
{
static int16_t samples_buf [ 1024 ] = { 0 } ;
struct retro_system_av_info * av_info = video_viewport_get_system_av_info ( ) ;
const struct retro_system_timing * info =
( const struct retro_system_timing * ) & av_info - > timing ;
unsigned sample_count = ( info - > sample_rate / info - > fps ) * 2 ;
bool check_flush = ! (
runloop_paused | |
! audio_driver_active | |
! audio_driver_input_data | |
! audio_driver_output_samples_buf ) ;
while ( sample_count > 1024 )
{
2019-06-17 16:23:46 +02:00
if ( recording_data & & recording_driver & & recording_driver - > push_audio )
{
struct record_audio_data ffemu_data ;
ffemu_data . data = samples_buf ;
ffemu_data . frames = 1024 / 2 ;
recording_driver - > push_audio ( recording_data , & ffemu_data ) ;
}
2019-06-17 12:49:21 +02:00
if ( check_flush )
audio_driver_flush ( samples_buf , 1024 , runloop_slowmotion ) ;
sample_count - = 1024 ;
}
2019-06-17 16:23:46 +02:00
if ( recording_data & & recording_driver & & recording_driver - > push_audio )
{
struct record_audio_data ffemu_data ;
ffemu_data . data = samples_buf ;
ffemu_data . frames = sample_count / 2 ;
recording_driver - > push_audio ( recording_data , & ffemu_data ) ;
}
2019-06-17 12:49:21 +02:00
if ( check_flush )
audio_driver_flush ( samples_buf , sample_count , runloop_slowmotion ) ;
}
/**
* audio_driver_sample_batch :
* @ data : pointer to audio buffer .
* @ frames : amount of audio frames to push .
*
* Batched audio sample render callback function .
*
* Returns : amount of frames sampled . Will be equal to @ frames
* unless @ frames exceeds ( AUDIO_CHUNK_SIZE_NONBLOCKING / 2 ) .
* */
size_t audio_driver_sample_batch ( const int16_t * data , size_t frames )
{
if ( frames > ( AUDIO_CHUNK_SIZE_NONBLOCKING > > 1 ) )
frames = AUDIO_CHUNK_SIZE_NONBLOCKING > > 1 ;
if ( audio_suspended )
return frames ;
2019-06-17 16:23:46 +02:00
if ( recording_data & & recording_driver & & recording_driver - > push_audio )
{
struct record_audio_data ffemu_data ;
ffemu_data . data = data ;
ffemu_data . frames = ( frames < < 1 ) / 2 ;
recording_driver - > push_audio ( recording_data , & ffemu_data ) ;
}
2019-06-17 12:49:21 +02:00
if ( ! (
runloop_paused | |
! audio_driver_active | |
! audio_driver_input_data | |
! audio_driver_output_samples_buf ) )
audio_driver_flush ( data , frames < < 1 , runloop_slowmotion ) ;
return frames ;
}
/**
* audio_driver_sample_rewind :
* @ left : value of the left audio channel .
* @ right : value of the right audio channel .
*
* Audio sample render callback function ( rewind version ) .
* This callback function will be used instead of
* audio_driver_sample when rewinding is activated .
* */
void audio_driver_sample_rewind ( int16_t left , int16_t right )
{
if ( audio_driver_rewind_ptr = = 0 )
return ;
audio_driver_rewind_buf [ - - audio_driver_rewind_ptr ] = right ;
audio_driver_rewind_buf [ - - audio_driver_rewind_ptr ] = left ;
}
/**
* audio_driver_sample_batch_rewind :
* @ data : pointer to audio buffer .
* @ frames : amount of audio frames to push .
*
* Batched audio sample render callback function ( rewind version ) .
*
* This callback function will be used instead of
* audio_driver_sample_batch when rewinding is activated .
*
* Returns : amount of frames sampled . Will be equal to @ frames
* unless @ frames exceeds ( AUDIO_CHUNK_SIZE_NONBLOCKING / 2 ) .
* */
size_t audio_driver_sample_batch_rewind ( const int16_t * data , size_t frames )
{
size_t i ;
size_t samples = frames < < 1 ;
for ( i = 0 ; i < samples ; i + + )
{
if ( audio_driver_rewind_ptr > 0 )
audio_driver_rewind_buf [ - - audio_driver_rewind_ptr ] = data [ i ] ;
}
return frames ;
}
void audio_driver_dsp_filter_free ( void )
{
if ( audio_driver_dsp )
retro_dsp_filter_free ( audio_driver_dsp ) ;
audio_driver_dsp = NULL ;
}
2019-06-17 13:06:56 +02:00
bool audio_driver_dsp_filter_init ( const char * device )
2019-06-17 12:49:21 +02:00
{
struct string_list * plugs = NULL ;
# if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
char * basedir = ( char * ) calloc ( PATH_MAX_LENGTH , sizeof ( * basedir ) ) ;
char * ext_name = ( char * ) calloc ( PATH_MAX_LENGTH , sizeof ( * ext_name ) ) ;
size_t str_size = PATH_MAX_LENGTH * sizeof ( char ) ;
fill_pathname_basedir ( basedir , device , str_size ) ;
if ( ! frontend_driver_get_core_extension ( ext_name , str_size ) )
2019-06-17 13:06:56 +02:00
{
free ( ext_name ) ;
free ( basedir ) ;
return false ;
}
2019-06-17 12:49:21 +02:00
plugs = dir_list_new ( basedir , ext_name , false , true , false , false ) ;
2019-06-17 13:06:56 +02:00
free ( ext_name ) ;
free ( basedir ) ;
2019-06-17 12:49:21 +02:00
if ( ! plugs )
2019-06-17 13:06:56 +02:00
return false ;
2019-06-17 12:49:21 +02:00
# endif
audio_driver_dsp = retro_dsp_filter_new (
device , plugs , audio_driver_input ) ;
if ( ! audio_driver_dsp )
2019-06-17 13:06:56 +02:00
return false ;
2019-06-17 12:49:21 +02:00
2019-06-17 13:06:56 +02:00
return true ;
2019-06-17 12:49:21 +02:00
}
void audio_driver_set_buffer_size ( size_t bufsize )
{
audio_driver_buffer_size = bufsize ;
}
static void audio_driver_monitor_adjust_system_rates ( void )
{
float timing_skew ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 12:49:21 +02:00
float video_refresh_rate = settings - > floats . video_refresh_rate ;
float max_timing_skew = settings - > floats . audio_max_timing_skew ;
struct retro_system_av_info * av_info = video_viewport_get_system_av_info ( ) ;
const struct retro_system_timing * info =
( const struct retro_system_timing * ) & av_info - > timing ;
if ( info - > sample_rate < = 0.0 )
return ;
timing_skew = fabs ( 1.0f - info - > fps / video_refresh_rate ) ;
audio_driver_input = info - > sample_rate ;
if ( timing_skew < = max_timing_skew & & ! settings - > bools . vrr_runloop_enable )
audio_driver_input * = ( video_refresh_rate / info - > fps ) ;
RARCH_LOG ( " [Audio]: Set audio input rate to: %.2f Hz. \n " ,
audio_driver_input ) ;
}
void audio_driver_setup_rewind ( void )
{
unsigned i ;
/* Push audio ready to be played. */
audio_driver_rewind_ptr = audio_driver_rewind_size ;
for ( i = 0 ; i < audio_driver_data_ptr ; i + = 2 )
{
if ( audio_driver_rewind_ptr > 0 )
audio_driver_rewind_buf [ - - audio_driver_rewind_ptr ] =
audio_driver_output_samples_conv_buf [ i + 1 ] ;
if ( audio_driver_rewind_ptr > 0 )
audio_driver_rewind_buf [ - - audio_driver_rewind_ptr ] =
audio_driver_output_samples_conv_buf [ i + 0 ] ;
}
audio_driver_data_ptr = 0 ;
}
bool audio_driver_get_devices_list ( void * * data )
{
struct string_list * * ptr = ( struct string_list * * ) data ;
if ( ! ptr )
return false ;
* ptr = audio_driver_devices_list ;
return true ;
}
bool audio_driver_mixer_extension_supported ( const char * ext )
{
union string_list_elem_attr attr ;
unsigned i ;
bool ret = false ;
struct string_list * str_list = string_list_new ( ) ;
attr . i = 0 ;
# ifdef HAVE_STB_VORBIS
string_list_append ( str_list , " ogg " , attr ) ;
# endif
# ifdef HAVE_IBXM
string_list_append ( str_list , " mod " , attr ) ;
string_list_append ( str_list , " s3m " , attr ) ;
string_list_append ( str_list , " xm " , attr ) ;
# endif
# ifdef HAVE_DR_FLAC
string_list_append ( str_list , " flac " , attr ) ;
# endif
# ifdef HAVE_DR_MP3
string_list_append ( str_list , " mp3 " , attr ) ;
# endif
string_list_append ( str_list , " wav " , attr ) ;
for ( i = 0 ; i < str_list - > size ; i + + )
{
const char * str_ext = str_list - > elems [ i ] . data ;
if ( string_is_equal_noncase ( str_ext , ext ) )
{
ret = true ;
break ;
}
}
string_list_free ( str_list ) ;
return ret ;
}
static int audio_mixer_find_index ( audio_mixer_sound_t * sound )
{
unsigned i ;
for ( i = 0 ; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS ; i + + )
{
audio_mixer_sound_t * handle = audio_mixer_streams [ i ] . handle ;
if ( handle = = sound )
return i ;
}
return - 1 ;
}
static void audio_mixer_play_stop_cb (
audio_mixer_sound_t * sound , unsigned reason )
{
int idx = audio_mixer_find_index ( sound ) ;
switch ( reason )
{
case AUDIO_MIXER_SOUND_FINISHED :
audio_mixer_destroy ( sound ) ;
if ( idx > = 0 )
{
unsigned i = ( unsigned ) idx ;
if ( ! string_is_empty ( audio_mixer_streams [ i ] . name ) )
free ( audio_mixer_streams [ i ] . name ) ;
audio_mixer_streams [ i ] . name = NULL ;
audio_mixer_streams [ i ] . state = AUDIO_STREAM_STATE_NONE ;
audio_mixer_streams [ i ] . volume = 0.0f ;
audio_mixer_streams [ i ] . buf = NULL ;
audio_mixer_streams [ i ] . stop_cb = NULL ;
audio_mixer_streams [ i ] . handle = NULL ;
audio_mixer_streams [ i ] . voice = NULL ;
}
break ;
case AUDIO_MIXER_SOUND_STOPPED :
break ;
case AUDIO_MIXER_SOUND_REPEATED :
break ;
}
}
static void audio_mixer_menu_stop_cb (
audio_mixer_sound_t * sound , unsigned reason )
{
int idx = audio_mixer_find_index ( sound ) ;
switch ( reason )
{
case AUDIO_MIXER_SOUND_FINISHED :
if ( idx > = 0 )
{
unsigned i = ( unsigned ) idx ;
audio_mixer_streams [ i ] . state = AUDIO_STREAM_STATE_STOPPED ;
audio_mixer_streams [ i ] . volume = 0.0f ;
}
break ;
case AUDIO_MIXER_SOUND_STOPPED :
break ;
case AUDIO_MIXER_SOUND_REPEATED :
break ;
}
}
static void audio_mixer_play_stop_sequential_cb (
audio_mixer_sound_t * sound , unsigned reason )
{
int idx = audio_mixer_find_index ( sound ) ;
switch ( reason )
{
case AUDIO_MIXER_SOUND_FINISHED :
audio_mixer_destroy ( sound ) ;
if ( idx > = 0 )
{
unsigned i = ( unsigned ) idx ;
if ( ! string_is_empty ( audio_mixer_streams [ i ] . name ) )
free ( audio_mixer_streams [ i ] . name ) ;
if ( i < AUDIO_MIXER_MAX_STREAMS )
audio_mixer_streams [ i ] . stream_type = AUDIO_STREAM_TYPE_USER ;
else
audio_mixer_streams [ i ] . stream_type = AUDIO_STREAM_TYPE_SYSTEM ;
audio_mixer_streams [ i ] . name = NULL ;
audio_mixer_streams [ i ] . state = AUDIO_STREAM_STATE_NONE ;
audio_mixer_streams [ i ] . volume = 0.0f ;
audio_mixer_streams [ i ] . buf = NULL ;
audio_mixer_streams [ i ] . stop_cb = NULL ;
audio_mixer_streams [ i ] . handle = NULL ;
audio_mixer_streams [ i ] . voice = NULL ;
i + + ;
for ( ; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS ; i + + )
{
if ( audio_mixer_streams [ i ] . state = = AUDIO_STREAM_STATE_STOPPED )
{
audio_driver_mixer_play_stream_sequential ( i ) ;
break ;
}
}
}
break ;
case AUDIO_MIXER_SOUND_STOPPED :
break ;
case AUDIO_MIXER_SOUND_REPEATED :
break ;
}
}
static bool audio_driver_mixer_get_free_stream_slot ( unsigned * id , enum audio_mixer_stream_type type )
{
unsigned i = ( type = = AUDIO_STREAM_TYPE_USER ) ? 0 : AUDIO_MIXER_MAX_STREAMS ;
unsigned count = ( type = = AUDIO_STREAM_TYPE_USER ) ? AUDIO_MIXER_MAX_STREAMS : AUDIO_MIXER_MAX_SYSTEM_STREAMS ;
for ( ; i < count ; i + + )
{
if ( audio_mixer_streams [ i ] . state = = AUDIO_STREAM_STATE_NONE )
{
* id = i ;
return true ;
}
}
return false ;
}
bool audio_driver_mixer_add_stream ( audio_mixer_stream_params_t * params )
{
unsigned free_slot = 0 ;
audio_mixer_voice_t * voice = NULL ;
audio_mixer_sound_t * handle = NULL ;
audio_mixer_stop_cb_t stop_cb = audio_mixer_play_stop_cb ;
bool looped = false ;
void * buf = NULL ;
if ( params - > stream_type = = AUDIO_STREAM_TYPE_NONE )
return false ;
switch ( params - > slot_selection_type )
{
case AUDIO_MIXER_SLOT_SELECTION_MANUAL :
free_slot = params - > slot_selection_idx ;
break ;
case AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC :
default :
if ( ! audio_driver_mixer_get_free_stream_slot (
& free_slot , params - > stream_type ) )
return false ;
break ;
}
if ( params - > state = = AUDIO_STREAM_STATE_NONE )
return false ;
buf = malloc ( params - > bufsize ) ;
if ( ! buf )
return false ;
memcpy ( buf , params - > buf , params - > bufsize ) ;
switch ( params - > type )
{
case AUDIO_MIXER_TYPE_WAV :
handle = audio_mixer_load_wav ( buf , ( int32_t ) params - > bufsize ) ;
break ;
case AUDIO_MIXER_TYPE_OGG :
handle = audio_mixer_load_ogg ( buf , ( int32_t ) params - > bufsize ) ;
break ;
case AUDIO_MIXER_TYPE_MOD :
handle = audio_mixer_load_mod ( buf , ( int32_t ) params - > bufsize ) ;
break ;
case AUDIO_MIXER_TYPE_FLAC :
# ifdef HAVE_DR_FLAC
handle = audio_mixer_load_flac ( buf , ( int32_t ) params - > bufsize ) ;
# endif
break ;
case AUDIO_MIXER_TYPE_MP3 :
# ifdef HAVE_DR_MP3
handle = audio_mixer_load_mp3 ( buf , ( int32_t ) params - > bufsize ) ;
# endif
break ;
case AUDIO_MIXER_TYPE_NONE :
break ;
}
if ( ! handle )
{
free ( buf ) ;
return false ;
}
switch ( params - > state )
{
case AUDIO_STREAM_STATE_PLAYING_LOOPED :
looped = true ;
voice = audio_mixer_play ( handle , looped , params - > volume , stop_cb ) ;
break ;
case AUDIO_STREAM_STATE_PLAYING :
voice = audio_mixer_play ( handle , looped , params - > volume , stop_cb ) ;
break ;
case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL :
stop_cb = audio_mixer_play_stop_sequential_cb ;
voice = audio_mixer_play ( handle , looped , params - > volume , stop_cb ) ;
break ;
default :
break ;
}
audio_mixer_active = true ;
audio_mixer_streams [ free_slot ] . name = ! string_is_empty ( params - > basename ) ? strdup ( params - > basename ) : NULL ;
audio_mixer_streams [ free_slot ] . buf = buf ;
audio_mixer_streams [ free_slot ] . handle = handle ;
audio_mixer_streams [ free_slot ] . voice = voice ;
audio_mixer_streams [ free_slot ] . stream_type = params - > stream_type ;
audio_mixer_streams [ free_slot ] . type = params - > type ;
audio_mixer_streams [ free_slot ] . state = params - > state ;
audio_mixer_streams [ free_slot ] . volume = params - > volume ;
audio_mixer_streams [ free_slot ] . stop_cb = stop_cb ;
return true ;
}
enum audio_mixer_state audio_driver_mixer_get_stream_state ( unsigned i )
{
if ( i > = AUDIO_MIXER_MAX_SYSTEM_STREAMS )
return AUDIO_STREAM_STATE_NONE ;
return audio_mixer_streams [ i ] . state ;
}
static void audio_driver_mixer_play_stream_internal ( unsigned i , unsigned type )
{
bool set_state = false ;
if ( i > = AUDIO_MIXER_MAX_SYSTEM_STREAMS )
return ;
switch ( audio_mixer_streams [ i ] . state )
{
case AUDIO_STREAM_STATE_STOPPED :
audio_mixer_streams [ i ] . voice = audio_mixer_play ( audio_mixer_streams [ i ] . handle ,
( type = = AUDIO_STREAM_STATE_PLAYING_LOOPED ) ? true : false ,
1.0f , audio_mixer_streams [ i ] . stop_cb ) ;
set_state = true ;
break ;
case AUDIO_STREAM_STATE_PLAYING :
case AUDIO_STREAM_STATE_PLAYING_LOOPED :
case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL :
case AUDIO_STREAM_STATE_NONE :
break ;
}
if ( set_state )
audio_mixer_streams [ i ] . state = ( enum audio_mixer_state ) type ;
}
static void audio_driver_load_menu_bgm_callback ( retro_task_t * task ,
void * task_data , void * user_data , const char * error )
{
bool contentless = false ;
bool is_inited = false ;
content_get_status ( & contentless , & is_inited ) ;
if ( ! is_inited )
audio_driver_mixer_play_menu_sound_looped ( AUDIO_MIXER_SYSTEM_SLOT_BGM ) ;
}
void audio_driver_load_menu_sounds ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
const char * path_ok = NULL ;
const char * path_cancel = NULL ;
const char * path_notice = NULL ;
const char * path_bgm = NULL ;
struct string_list * list = NULL ;
2019-06-17 12:49:21 +02:00
struct string_list * list_fallback = NULL ;
2019-06-17 16:58:43 +02:00
unsigned i = 0 ;
char * sounds_path = ( char * )
malloc ( PATH_MAX_LENGTH * sizeof ( char ) ) ;
char * sounds_fallback_path = ( char * )
malloc ( PATH_MAX_LENGTH * sizeof ( char ) ) ;
2019-06-17 12:49:21 +02:00
sounds_path [ 0 ] = sounds_fallback_path [ 0 ] = ' \0 ' ;
fill_pathname_join (
sounds_fallback_path ,
settings - > paths . directory_assets ,
" sounds " ,
PATH_MAX_LENGTH * sizeof ( char )
) ;
2019-06-17 16:58:43 +02:00
fill_pathname_application_special (
sounds_path ,
PATH_MAX_LENGTH * sizeof ( char ) ,
APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS ) ;
2019-06-17 12:49:21 +02:00
list = dir_list_new ( sounds_path , MENU_SOUND_FORMATS , false , false , false , false ) ;
list_fallback = dir_list_new ( sounds_fallback_path , MENU_SOUND_FORMATS , false , false , false , false ) ;
if ( ! list )
{
list = list_fallback ;
list_fallback = NULL ;
}
if ( ! list | | list - > size = = 0 )
goto end ;
if ( list_fallback & & list_fallback - > size > 0 )
{
for ( i = 0 ; i < list_fallback - > size ; i + + )
{
if ( list - > size = = 0 | | ! string_list_find_elem ( list , list_fallback - > elems [ i ] . data ) )
{
union string_list_elem_attr attr = { 0 } ;
string_list_append ( list , list_fallback - > elems [ i ] . data , attr ) ;
}
}
}
for ( i = 0 ; i < list - > size ; i + + )
{
const char * path = list - > elems [ i ] . data ;
const char * ext = path_get_extension ( path ) ;
char basename_noext [ PATH_MAX_LENGTH ] ;
basename_noext [ 0 ] = ' \0 ' ;
fill_pathname_base_noext ( basename_noext , path , sizeof ( basename_noext ) ) ;
if ( audio_driver_mixer_extension_supported ( ext ) )
{
if ( string_is_equal_noncase ( basename_noext , " ok " ) )
path_ok = path ;
if ( string_is_equal_noncase ( basename_noext , " cancel " ) )
path_cancel = path ;
if ( string_is_equal_noncase ( basename_noext , " notice " ) )
path_notice = path ;
if ( string_is_equal_noncase ( basename_noext , " bgm " ) )
path_bgm = path ;
}
}
if ( path_ok & & settings - > bools . audio_enable_menu_ok )
task_push_audio_mixer_load ( path_ok , NULL , NULL , true , AUDIO_MIXER_SLOT_SELECTION_MANUAL , AUDIO_MIXER_SYSTEM_SLOT_OK ) ;
if ( path_cancel & & settings - > bools . audio_enable_menu_cancel )
task_push_audio_mixer_load ( path_cancel , NULL , NULL , true , AUDIO_MIXER_SLOT_SELECTION_MANUAL , AUDIO_MIXER_SYSTEM_SLOT_CANCEL ) ;
if ( path_notice & & settings - > bools . audio_enable_menu_notice )
task_push_audio_mixer_load ( path_notice , NULL , NULL , true , AUDIO_MIXER_SLOT_SELECTION_MANUAL , AUDIO_MIXER_SYSTEM_SLOT_NOTICE ) ;
if ( path_bgm & & settings - > bools . audio_enable_menu_bgm )
task_push_audio_mixer_load ( path_bgm , audio_driver_load_menu_bgm_callback , NULL , true , AUDIO_MIXER_SLOT_SELECTION_MANUAL , AUDIO_MIXER_SYSTEM_SLOT_BGM ) ;
end :
if ( list )
string_list_free ( list ) ;
if ( list_fallback )
string_list_free ( list_fallback ) ;
if ( sounds_path )
free ( sounds_path ) ;
if ( sounds_fallback_path )
free ( sounds_fallback_path ) ;
}
void audio_driver_mixer_play_stream ( unsigned i )
{
audio_mixer_streams [ i ] . stop_cb = audio_mixer_play_stop_cb ;
audio_driver_mixer_play_stream_internal ( i , AUDIO_STREAM_STATE_PLAYING ) ;
}
void audio_driver_mixer_play_menu_sound_looped ( unsigned i )
{
audio_mixer_streams [ i ] . stop_cb = audio_mixer_menu_stop_cb ;
audio_driver_mixer_play_stream_internal ( i , AUDIO_STREAM_STATE_PLAYING_LOOPED ) ;
}
void audio_driver_mixer_play_menu_sound ( unsigned i )
{
audio_mixer_streams [ i ] . stop_cb = audio_mixer_menu_stop_cb ;
audio_driver_mixer_play_stream_internal ( i , AUDIO_STREAM_STATE_PLAYING ) ;
}
void audio_driver_mixer_play_stream_looped ( unsigned i )
{
audio_mixer_streams [ i ] . stop_cb = audio_mixer_play_stop_cb ;
audio_driver_mixer_play_stream_internal ( i , AUDIO_STREAM_STATE_PLAYING_LOOPED ) ;
}
void audio_driver_mixer_play_stream_sequential ( unsigned i )
{
audio_mixer_streams [ i ] . stop_cb = audio_mixer_play_stop_sequential_cb ;
audio_driver_mixer_play_stream_internal ( i , AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL ) ;
}
float audio_driver_mixer_get_stream_volume ( unsigned i )
{
if ( i > = AUDIO_MIXER_MAX_SYSTEM_STREAMS )
return 0.0f ;
return audio_mixer_streams [ i ] . volume ;
}
void audio_driver_mixer_set_stream_volume ( unsigned i , float vol )
{
audio_mixer_voice_t * voice = NULL ;
if ( i > = AUDIO_MIXER_MAX_SYSTEM_STREAMS )
return ;
audio_mixer_streams [ i ] . volume = vol ;
voice = audio_mixer_streams [ i ] . voice ;
if ( voice )
audio_mixer_voice_set_volume ( voice , db_to_gain ( vol ) ) ;
}
void audio_driver_mixer_stop_stream ( unsigned i )
{
bool set_state = false ;
if ( i > = AUDIO_MIXER_MAX_SYSTEM_STREAMS )
return ;
switch ( audio_mixer_streams [ i ] . state )
{
case AUDIO_STREAM_STATE_PLAYING :
case AUDIO_STREAM_STATE_PLAYING_LOOPED :
case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL :
set_state = true ;
break ;
case AUDIO_STREAM_STATE_STOPPED :
case AUDIO_STREAM_STATE_NONE :
break ;
}
if ( set_state )
{
audio_mixer_voice_t * voice = audio_mixer_streams [ i ] . voice ;
if ( voice )
audio_mixer_stop ( voice ) ;
audio_mixer_streams [ i ] . state = AUDIO_STREAM_STATE_STOPPED ;
audio_mixer_streams [ i ] . volume = 1.0f ;
}
}
2016-09-17 14:23:44 +02:00
2019-06-17 12:49:21 +02:00
void audio_driver_mixer_remove_stream ( unsigned i )
{
bool destroy = false ;
2017-05-11 09:11:46 +02:00
2019-06-17 12:49:21 +02:00
if ( i > = AUDIO_MIXER_MAX_SYSTEM_STREAMS )
return ;
2018-01-25 19:09:55 -05:00
2019-06-17 12:49:21 +02:00
switch ( audio_mixer_streams [ i ] . state )
{
case AUDIO_STREAM_STATE_PLAYING :
case AUDIO_STREAM_STATE_PLAYING_LOOPED :
case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL :
audio_driver_mixer_stop_stream ( i ) ;
destroy = true ;
break ;
case AUDIO_STREAM_STATE_STOPPED :
destroy = true ;
break ;
case AUDIO_STREAM_STATE_NONE :
break ;
}
2019-02-25 19:12:50 +01:00
2019-06-17 12:49:21 +02:00
if ( destroy )
{
audio_mixer_sound_t * handle = audio_mixer_streams [ i ] . handle ;
if ( handle )
audio_mixer_destroy ( handle ) ;
if ( ! string_is_empty ( audio_mixer_streams [ i ] . name ) )
free ( audio_mixer_streams [ i ] . name ) ;
2019-06-17 15:10:22 +02:00
audio_mixer_streams [ i ] . state = AUDIO_STREAM_STATE_NONE ;
audio_mixer_streams [ i ] . stop_cb = NULL ;
audio_mixer_streams [ i ] . volume = 0.0f ;
audio_mixer_streams [ i ] . handle = NULL ;
audio_mixer_streams [ i ] . voice = NULL ;
audio_mixer_streams [ i ] . name = NULL ;
}
}
bool audio_driver_set_callback ( const void * data )
{
const struct retro_audio_callback * cb = ( const struct retro_audio_callback * ) data ;
if ( cb )
audio_callback = * cb ;
return true ;
}
bool audio_driver_enable_callback ( void )
{
if ( ! audio_callback . callback )
return false ;
if ( audio_callback . set_state )
audio_callback . set_state ( true ) ;
return true ;
}
bool audio_driver_disable_callback ( void )
{
if ( ! audio_callback . callback )
return false ;
if ( audio_callback . set_state )
audio_callback . set_state ( false ) ;
return true ;
}
/* Sets audio monitor rate to new value. */
static void audio_driver_monitor_set_rate ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
double new_src_ratio = ( double ) settings - > uints . audio_out_rate /
audio_driver_input ;
audio_source_ratio_original = new_src_ratio ;
audio_source_ratio_current = new_src_ratio ;
}
bool audio_driver_callback ( void )
{
if ( ! audio_callback . callback )
return false ;
if ( audio_callback . callback )
audio_callback . callback ( ) ;
return true ;
}
bool audio_driver_has_callback ( void )
{
if ( audio_callback . callback )
return true ;
return false ;
}
bool audio_driver_toggle_mute ( void )
{
audio_driver_mute_enable = ! audio_driver_mute_enable ;
return true ;
}
bool audio_driver_mixer_toggle_mute ( void )
{
audio_driver_mixer_mute_enable = ! audio_driver_mixer_mute_enable ;
return true ;
}
static INLINE bool audio_driver_alive ( void )
{
if ( current_audio
& & current_audio - > alive
& & audio_driver_context_audio_data )
return current_audio - > alive ( audio_driver_context_audio_data ) ;
return false ;
}
bool audio_driver_start ( bool is_shutdown )
{
if ( ! current_audio | | ! current_audio - > start
| | ! audio_driver_context_audio_data )
goto error ;
if ( ! current_audio - > start ( audio_driver_context_audio_data , is_shutdown ) )
goto error ;
return true ;
error :
RARCH_ERR ( " %s \n " ,
msg_hash_to_str ( MSG_FAILED_TO_START_AUDIO_DRIVER ) ) ;
audio_driver_active = false ;
return false ;
}
bool audio_driver_stop ( void )
{
if ( ! current_audio | | ! current_audio - > stop
| | ! audio_driver_context_audio_data )
return false ;
if ( ! audio_driver_alive ( ) )
return false ;
return current_audio - > stop ( audio_driver_context_audio_data ) ;
}
static void audio_driver_unset_callback ( void )
{
audio_callback . callback = NULL ;
audio_callback . set_state = NULL ;
}
void audio_driver_frame_is_reverse ( void )
{
/* We just rewound. Flush rewind audio buffer. */
2019-06-17 16:23:46 +02:00
if ( recording_data & & recording_driver & & recording_driver - > push_audio )
{
struct record_audio_data ffemu_data ;
ffemu_data . data = audio_driver_rewind_buf + audio_driver_rewind_ptr ;
ffemu_data . frames = ( audio_driver_rewind_size - audio_driver_rewind_ptr ) / 2 ;
recording_driver - > push_audio ( recording_data , & ffemu_data ) ;
}
2019-06-17 15:10:22 +02:00
if ( ! (
runloop_paused | |
! audio_driver_active | |
! audio_driver_input_data | |
! audio_driver_output_samples_buf ) )
audio_driver_flush (
audio_driver_rewind_buf + audio_driver_rewind_ptr ,
audio_driver_rewind_size - audio_driver_rewind_ptr ,
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 ;
}
static void audio_driver_destroy ( void )
{
audio_driver_active = false ;
current_audio = NULL ;
}
void audio_set_bool ( enum audio_action action , bool val )
{
switch ( action )
{
case AUDIO_ACTION_MIXER :
audio_mixer_active = val ;
break ;
case AUDIO_ACTION_NONE :
default :
break ;
}
}
void audio_set_float ( enum audio_action action , float val )
{
switch ( action )
{
case AUDIO_ACTION_VOLUME_GAIN :
audio_driver_volume_gain = db_to_gain ( val ) ;
break ;
case AUDIO_ACTION_MIXER_VOLUME_GAIN :
audio_driver_mixer_volume_gain = db_to_gain ( val ) ;
break ;
case AUDIO_ACTION_RATE_CONTROL_DELTA :
audio_driver_rate_control_delta = val ;
break ;
case AUDIO_ACTION_NONE :
default :
break ;
}
}
float * audio_get_float_ptr ( enum audio_action action )
{
switch ( action )
{
case AUDIO_ACTION_RATE_CONTROL_DELTA :
return & audio_driver_rate_control_delta ;
case AUDIO_ACTION_NONE :
default :
break ;
}
return NULL ;
}
bool * audio_get_bool_ptr ( enum audio_action action )
{
switch ( action )
{
case AUDIO_ACTION_MIXER_MUTE_ENABLE :
return & audio_driver_mixer_mute_enable ;
case AUDIO_ACTION_MUTE_ENABLE :
return & audio_driver_mute_enable ;
case AUDIO_ACTION_NONE :
default :
break ;
}
return NULL ;
}
static const char * audio_driver_get_ident ( void )
{
if ( ! current_audio )
return NULL ;
return current_audio - > ident ;
}
/* Video */
# 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 FPS_UPDATE_INTERVAL 256
# ifdef HAVE_THREADS
# define video_driver_is_threaded_internal() ((!video_driver_is_hw_context() && video_driver_threaded) ? true : false)
# else
# define video_driver_is_threaded_internal() (false)
# endif
# ifdef HAVE_THREADS
# define video_driver_lock() \
if ( display_lock ) \
slock_lock ( display_lock )
# define video_driver_unlock() \
if ( display_lock ) \
slock_unlock ( display_lock )
# define video_driver_context_lock() \
if ( context_lock ) \
slock_lock ( context_lock )
# define video_driver_context_unlock() \
if ( context_lock ) \
slock_unlock ( context_lock )
# define video_driver_lock_free() \
slock_free ( display_lock ) ; \
slock_free ( context_lock ) ; \
display_lock = NULL ; \
context_lock = NULL
# define video_driver_threaded_lock(is_threaded) \
if ( is_threaded ) \
video_driver_lock ( )
# define video_driver_threaded_unlock(is_threaded) \
if ( is_threaded ) \
video_driver_unlock ( )
# else
# define video_driver_lock() ((void)0)
# define video_driver_unlock() ((void)0)
# define video_driver_lock_free() ((void)0)
# define video_driver_threaded_lock(is_threaded) ((void)0)
# define video_driver_threaded_unlock(is_threaded) ((void)0)
# define video_driver_context_lock() ((void)0)
# define video_driver_context_unlock() ((void)0)
# endif
typedef struct video_pixel_scaler
{
struct scaler_ctx * scaler ;
void * scaler_out ;
} video_pixel_scaler_t ;
bool ( * video_driver_cb_has_focus ) ( void ) ;
/* Opaque handles to currently running window.
* Used by e . g . input drivers which bind to a window .
* Drivers are responsible for setting these if an input driver
* could potentially make use of this . */
static uintptr_t video_driver_display = 0 ;
static uintptr_t video_driver_window = 0 ;
static rarch_softfilter_t * video_driver_state_filter = NULL ;
static void * video_driver_state_buffer = NULL ;
static unsigned video_driver_state_scale = 0 ;
static unsigned video_driver_state_out_bpp = 0 ;
static bool video_driver_state_out_rgb32 = false ;
static bool video_driver_crt_switching_active = false ;
static bool video_driver_crt_dynamic_super_width = false ;
static struct retro_system_av_info video_driver_av_info ;
static enum retro_pixel_format video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555 ;
static const void * frame_cache_data = NULL ;
static unsigned frame_cache_width = 0 ;
static unsigned frame_cache_height = 0 ;
static size_t frame_cache_pitch = 0 ;
static bool video_driver_threaded = false ;
static float video_driver_core_hz = 0.0f ;
static float video_driver_aspect_ratio = 0.0f ;
static unsigned video_driver_width = 0 ;
static unsigned video_driver_height = 0 ;
static enum rarch_display_type video_driver_display_type = RARCH_DISPLAY_NONE ;
static char video_driver_title_buf [ 64 ] = { 0 } ;
static char video_driver_window_title [ 512 ] = { 0 } ;
static bool video_driver_window_title_update = true ;
static retro_time_t video_driver_frame_time_samples [ MEASURE_FRAME_TIME_SAMPLES_COUNT ] ;
static uint64_t video_driver_frame_time_count = 0 ;
static uint64_t video_driver_frame_count = 0 ;
static void * video_driver_data = NULL ;
static video_driver_t * current_video = NULL ;
/* Interface for "poking". */
static const video_poke_interface_t * video_driver_poke = NULL ;
/* Used for 15-bit -> 16-bit conversions that take place before
* being passed to video driver . */
static video_pixel_scaler_t * video_driver_scaler_ptr = NULL ;
static struct retro_hw_render_callback hw_render ;
static const struct
retro_hw_render_context_negotiation_interface *
hw_render_context_negotiation = NULL ;
/* 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 . */
static bool video_driver_use_rgba = false ;
static bool video_driver_active = false ;
static video_driver_frame_t frame_bak = NULL ;
/* If set during context deinit, the driver should keep
* graphics context alive to avoid having to reset all
* context state . */
static bool video_driver_cache_context = false ;
/* Set to true by driver if context caching succeeded. */
static bool video_driver_cache_context_ack = false ;
# ifdef HAVE_THREADS
static slock_t * display_lock = NULL ;
static slock_t * context_lock = NULL ;
# endif
static gfx_ctx_driver_t current_video_context ;
static void * video_context_data = NULL ;
/**
* 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
*/
static bool deferred_video_context_driver_set_flags = false ;
static gfx_ctx_flags_t deferred_flag_data = { 0 } ;
static bool video_started_fullscreen = false ;
static char video_driver_gpu_device_string [ 128 ] = { 0 } ;
static char video_driver_gpu_api_version_string [ 128 ] = { 0 } ;
struct aspect_ratio_elem aspectratio_lut [ ASPECT_RATIO_END ] = {
{ " 4:3 " , 1.3333f } ,
{ " 16:9 " , 1.7778f } ,
{ " 16:10 " , 1.6f } ,
{ " 16:15 " , 16.0f / 15.0f } ,
{ " 21:9 " , 21.0f / 9.0f } ,
{ " 1:1 " , 1.0f } ,
{ " 2:1 " , 2.0f } ,
{ " 3:2 " , 1.5f } ,
{ " 3:4 " , 0.75f } ,
{ " 4:1 " , 4.0f } ,
{ " 9:16 " , 0.5625f } ,
{ " 5:4 " , 1.25f } ,
{ " 6:5 " , 1.2f } ,
{ " 7:9 " , 0.7777f } ,
{ " 8:3 " , 2.6666f } ,
{ " 8:7 " , 1.1428f } ,
{ " 19:12 " , 1.5833f } ,
{ " 19:14 " , 1.3571f } ,
{ " 30:17 " , 1.7647f } ,
{ " 32:9 " , 3.5555f } ,
{ " Config " , 0.0f } ,
{ " Square pixel " , 1.0f } ,
{ " Core provided " , 1.0f } ,
{ " Custom " , 0.0f }
} ;
static const video_driver_t * video_drivers [ ] = {
# ifdef HAVE_OPENGL
& video_gl2 ,
# endif
# if defined(HAVE_OPENGL_CORE)
& video_gl_core ,
# endif
# ifdef HAVE_OPENGL1
& video_gl1 ,
# endif
# ifdef HAVE_VULKAN
& video_vulkan ,
# endif
# ifdef HAVE_METAL
& video_metal ,
# endif
# ifdef XENON
& video_xenon360 ,
# endif
# if defined(HAVE_D3D12)
& video_d3d12 ,
# endif
# if defined(HAVE_D3D11)
& video_d3d11 ,
# endif
# if defined(HAVE_D3D10)
& video_d3d10 ,
# endif
# if defined(HAVE_D3D9)
& video_d3d9 ,
# endif
# if defined(HAVE_D3D8)
& video_d3d8 ,
# endif
# ifdef HAVE_VITA2D
& video_vita2d ,
# endif
# ifdef PSP
& video_psp1 ,
# endif
# ifdef PS2
& video_ps2 ,
# endif
# ifdef _3DS
& video_ctr ,
# endif
# ifdef SWITCH
& video_switch ,
# endif
# ifdef HAVE_SDL
& video_sdl ,
# endif
# ifdef HAVE_SDL2
& video_sdl2 ,
# endif
# ifdef HAVE_XVIDEO
& video_xvideo ,
# endif
# ifdef GEKKO
& video_gx ,
# endif
# ifdef WIIU
& video_wiiu ,
# endif
# ifdef HAVE_VG
& video_vg ,
# endif
# ifdef HAVE_OMAP
& video_omap ,
# endif
# ifdef HAVE_EXYNOS
& video_exynos ,
# endif
# ifdef HAVE_DISPMANX
& video_dispmanx ,
# endif
# ifdef HAVE_SUNXI
& video_sunxi ,
# endif
# ifdef HAVE_PLAIN_DRM
& video_drm ,
# endif
# ifdef HAVE_XSHM
& video_xshm ,
# endif
# if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
& video_gdi ,
# endif
# ifdef DJGPP
& video_vga ,
# endif
# ifdef HAVE_SIXEL
& video_sixel ,
# endif
# ifdef HAVE_CACA
& video_caca ,
# endif
& video_null ,
NULL ,
} ;
static const gfx_ctx_driver_t * gfx_ctx_drivers [ ] = {
# if defined(ORBIS)
& orbis_ctx ,
# endif
# if defined(HAVE_LIBNX) && defined(HAVE_OPENGL)
& switch_ctx ,
# endif
# if defined(__CELLOS_LV2__)
& gfx_ctx_ps3 ,
# endif
# if defined(HAVE_VIDEOCORE)
& gfx_ctx_videocore ,
# endif
# if defined(HAVE_MALI_FBDEV)
& gfx_ctx_mali_fbdev ,
# endif
# if defined(HAVE_VIVANTE_FBDEV)
& gfx_ctx_vivante_fbdev ,
# endif
# if defined(HAVE_OPENDINGUX_FBDEV)
& gfx_ctx_opendingux_fbdev ,
# endif
# if defined(_WIN32) && (defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE) || defined(HAVE_VULKAN))
& gfx_ctx_wgl ,
# endif
# if defined(HAVE_WAYLAND)
& gfx_ctx_wayland ,
# endif
# if defined(HAVE_X11) && !defined(HAVE_OPENGLES)
# if defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE) || defined(HAVE_VULKAN)
& gfx_ctx_x ,
# endif
# endif
# if defined(HAVE_X11) && defined(HAVE_OPENGL) && defined(HAVE_EGL)
& gfx_ctx_x_egl ,
# endif
# if defined(HAVE_KMS)
& gfx_ctx_drm ,
# endif
# if defined(ANDROID)
& gfx_ctx_android ,
# endif
# if defined(__QNX__)
& gfx_ctx_qnx ,
# endif
# if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL)
& gfx_ctx_cocoagl ,
# endif
# if defined(__APPLE__) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE)
& gfx_ctx_cgl ,
# endif
# if (defined(HAVE_SDL) || defined(HAVE_SDL2)) && (defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE))
& gfx_ctx_sdl_gl ,
# endif
# ifdef HAVE_OSMESA
& gfx_ctx_osmesa ,
# endif
# ifdef EMSCRIPTEN
& gfx_ctx_emscripten ,
# endif
# if defined(HAVE_VULKAN) && defined(HAVE_VULKAN_DISPLAY)
& gfx_ctx_khr_display ,
# endif
# if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
& gfx_ctx_gdi ,
# endif
# ifdef HAVE_SIXEL
& gfx_ctx_sixel ,
# endif
& gfx_ctx_null ,
NULL
} ;
typedef struct {
enum gfx_ctx_api api ;
struct string_list * list ;
} gfx_api_gpu_map ;
static gfx_api_gpu_map gpu_map [ ] = {
{ GFX_CTX_VULKAN_API , NULL }
} ;
bool video_driver_started_fullscreen ( void )
{
return video_started_fullscreen ;
}
/* Stub functions */
static void update_window_title_null ( void * data , void * data2 )
{
}
static void swap_buffers_null ( void * data , void * data2 )
{
}
static bool get_metrics_null ( void * data , enum display_metric_types type ,
float * value )
{
return false ;
}
static bool set_resize_null ( void * a , unsigned b , unsigned c )
{
return false ;
}
/**
* video_driver_find_handle :
* @ idx : index of driver to get handle to .
*
* Returns : handle to video driver at index . Can be NULL
* if nothing found .
* */
const void * video_driver_find_handle ( int idx )
{
const void * drv = video_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv ;
}
/**
* video_driver_find_ident :
* @ idx : index of driver to get handle to .
*
* Returns : Human - readable identifier of video driver at index . Can be NULL
* if nothing found .
* */
const char * video_driver_find_ident ( int idx )
{
const video_driver_t * drv = video_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv - > ident ;
}
/**
* config_get_video_driver_options :
*
* Get an enumerated list of all video driver names , separated by ' | ' .
*
* Returns : string listing of all video driver names , separated by ' | ' .
* */
const char * config_get_video_driver_options ( void )
{
return char_list_new_special ( STRING_LIST_VIDEO_DRIVERS , NULL ) ;
}
bool video_driver_is_threaded ( void )
{
return video_driver_is_threaded_internal ( ) ;
}
# ifdef HAVE_VULKAN
static bool hw_render_context_is_vulkan ( enum retro_hw_context_type type )
{
return type = = RETRO_HW_CONTEXT_VULKAN ;
}
# endif
# if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
static bool hw_render_context_is_gl ( enum retro_hw_context_type type )
{
switch ( type )
{
case RETRO_HW_CONTEXT_OPENGL :
case RETRO_HW_CONTEXT_OPENGLES2 :
case RETRO_HW_CONTEXT_OPENGL_CORE :
case RETRO_HW_CONTEXT_OPENGLES3 :
case RETRO_HW_CONTEXT_OPENGLES_VERSION :
return true ;
default :
break ;
}
return false ;
}
# endif
bool * video_driver_get_threaded ( void )
{
return & video_driver_threaded ;
}
void video_driver_set_threaded ( bool val )
{
video_driver_threaded = val ;
}
/**
* video_driver_get_ptr :
*
* Use this if you need the real video driver
* and driver data pointers .
*
* Returns : video driver ' s userdata .
* */
void * video_driver_get_ptr ( bool force_nonthreaded_data )
{
# ifdef HAVE_THREADS
if ( video_driver_is_threaded_internal ( ) & & ! force_nonthreaded_data )
return video_thread_get_ptr ( NULL ) ;
# endif
return video_driver_data ;
}
const char * video_driver_get_ident ( void )
{
return ( current_video ) ? current_video - > ident : NULL ;
}
const video_poke_interface_t * video_driver_get_poke ( void )
{
return video_driver_poke ;
}
static bool video_context_has_focus ( void )
{
return current_video_context . has_focus & & current_video_context . has_focus ( video_context_data ) ;
}
static bool video_driver_has_focus ( void )
{
return current_video & & current_video - > focus & & current_video - > focus ( video_driver_data ) ;
}
static bool null_driver_has_focus ( void )
{
return true ;
}
static void video_context_driver_reset ( void )
{
if ( ! current_video_context . get_metrics )
current_video_context . get_metrics = get_metrics_null ;
if ( ! current_video_context . update_window_title )
current_video_context . update_window_title = update_window_title_null ;
if ( ! current_video_context . set_resize )
current_video_context . set_resize = set_resize_null ;
if ( ! current_video_context . swap_buffers )
current_video_context . swap_buffers = swap_buffers_null ;
if ( current_video_context . has_focus )
video_driver_cb_has_focus = video_context_has_focus ;
}
bool video_context_driver_set ( const gfx_ctx_driver_t * data )
{
if ( ! data )
return false ;
current_video_context = * data ;
video_context_driver_reset ( ) ;
return true ;
}
void video_context_driver_destroy ( void )
{
current_video_context . init = NULL ;
current_video_context . bind_api = NULL ;
current_video_context . swap_interval = NULL ;
current_video_context . set_video_mode = NULL ;
current_video_context . get_video_size = NULL ;
current_video_context . get_video_output_size = NULL ;
current_video_context . get_video_output_prev = NULL ;
current_video_context . get_video_output_next = NULL ;
current_video_context . get_metrics = get_metrics_null ;
current_video_context . translate_aspect = NULL ;
current_video_context . update_window_title = update_window_title_null ;
current_video_context . check_window = NULL ;
current_video_context . set_resize = set_resize_null ;
current_video_context . has_focus = NULL ;
current_video_context . suppress_screensaver = NULL ;
current_video_context . has_windowed = NULL ;
current_video_context . swap_buffers = swap_buffers_null ;
current_video_context . input_driver = NULL ;
current_video_context . get_proc_address = NULL ;
current_video_context . image_buffer_init = NULL ;
current_video_context . image_buffer_write = NULL ;
current_video_context . show_mouse = NULL ;
current_video_context . ident = NULL ;
current_video_context . get_flags = NULL ;
current_video_context . set_flags = NULL ;
current_video_context . bind_hw_render = NULL ;
current_video_context . get_context_data = NULL ;
current_video_context . make_current = NULL ;
}
/**
* video_driver_get_current_framebuffer :
*
* Gets pointer to current hardware renderer framebuffer object .
* Used by RETRO_ENVIRONMENT_SET_HW_RENDER .
*
* Returns : pointer to hardware framebuffer object , otherwise 0.
* */
uintptr_t video_driver_get_current_framebuffer ( void )
{
if ( video_driver_poke & & video_driver_poke - > get_current_framebuffer )
return video_driver_poke - > get_current_framebuffer ( video_driver_data ) ;
return 0 ;
}
retro_proc_address_t video_driver_get_proc_address ( const char * sym )
{
if ( video_driver_poke & & video_driver_poke - > get_proc_address )
return video_driver_poke - > get_proc_address ( video_driver_data , sym ) ;
return NULL ;
}
bool video_driver_set_shader ( enum rarch_shader_type type ,
const char * path )
{
if ( current_video - > set_shader )
return current_video - > set_shader ( video_driver_data , type , path ) ;
return false ;
}
static void video_driver_filter_free ( void )
{
if ( video_driver_state_filter )
rarch_softfilter_free ( video_driver_state_filter ) ;
video_driver_state_filter = NULL ;
if ( video_driver_state_buffer )
{
# ifdef _3DS
linearFree ( video_driver_state_buffer ) ;
# else
free ( video_driver_state_buffer ) ;
# endif
}
video_driver_state_buffer = NULL ;
video_driver_state_scale = 0 ;
video_driver_state_out_bpp = 0 ;
video_driver_state_out_rgb32 = false ;
}
static void video_driver_init_filter ( enum retro_pixel_format colfmt_int )
{
unsigned pow2_x , pow2_y , maxsize ;
void * buf = NULL ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
struct retro_game_geometry * geom = & video_driver_av_info . geometry ;
unsigned width = geom - > max_width ;
unsigned height = geom - > max_height ;
/* Deprecated format. Gets pre-converted. */
enum retro_pixel_format colfmt =
( colfmt_int = = RETRO_PIXEL_FORMAT_0RGB1555 ) ?
RETRO_PIXEL_FORMAT_RGB565 : colfmt_int ;
if ( video_driver_is_hw_context ( ) )
{
RARCH_WARN ( " Cannot use CPU filters when hardware rendering is used. \n " ) ;
return ;
}
video_driver_state_filter = rarch_softfilter_new (
settings - > paths . path_softfilter_plugin ,
RARCH_SOFTFILTER_THREADS_AUTO , colfmt , width , height ) ;
if ( ! video_driver_state_filter )
{
RARCH_ERR ( " [Video]: Failed to load filter. \n " ) ;
return ;
}
rarch_softfilter_get_max_output_size ( video_driver_state_filter ,
& width , & height ) ;
pow2_x = next_pow2 ( width ) ;
pow2_y = next_pow2 ( height ) ;
maxsize = MAX ( pow2_x , pow2_y ) ;
video_driver_state_scale = maxsize / RARCH_SCALE_BASE ;
video_driver_state_out_rgb32 = rarch_softfilter_get_output_format (
video_driver_state_filter ) = =
RETRO_PIXEL_FORMAT_XRGB8888 ;
video_driver_state_out_bpp = video_driver_state_out_rgb32 ?
sizeof ( uint32_t ) :
sizeof ( uint16_t ) ;
/* TODO: Aligned output. */
# ifdef _3DS
buf = linearMemAlign (
width * height * video_driver_state_out_bpp , 0x80 ) ;
# else
buf = malloc (
width * height * video_driver_state_out_bpp ) ;
# endif
if ( ! buf )
{
RARCH_ERR ( " [Video]: Softfilter initialization failed. \n " ) ;
video_driver_filter_free ( ) ;
return ;
}
video_driver_state_buffer = buf ;
}
static void video_driver_init_input ( const input_driver_t * tmp )
{
const input_driver_t * * input = input_get_double_ptr ( ) ;
if ( * input )
return ;
/* Video driver didn't provide an input driver,
* so we use configured one . */
RARCH_LOG ( " [Video]: Graphics driver did not initialize an input driver. "
" Attempting to pick a suitable driver. \n " ) ;
if ( tmp )
* input = tmp ;
else
input_driver_find_driver ( ) ;
/* This should never really happen as tmp (driver.input) is always
* found before this in find_driver_input ( ) , or we have aborted
* in a similar fashion anyways . */
if ( ! input_get_ptr ( ) )
goto error ;
if ( input_driver_init ( ) )
return ;
error :
RARCH_ERR ( " [Video]: Cannot initialize input driver. Exiting ... \n " ) ;
retroarch_fail ( 1 , " video_driver_init_input() " ) ;
}
/**
* video_driver_monitor_compute_fps_statistics :
*
* Computes monitor FPS statistics .
* */
static void video_driver_monitor_compute_fps_statistics ( void )
{
double avg_fps = 0.0 ;
double stddev = 0.0 ;
unsigned samples = 0 ;
if ( video_driver_frame_time_count <
( 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT ) )
{
RARCH_LOG (
" [Video]: Does not have enough samples for monitor refresh rate "
" estimation. Requires to run for at least %u frames. \n " ,
2 * MEASURE_FRAME_TIME_SAMPLES_COUNT ) ;
return ;
}
if ( video_monitor_fps_statistics ( & avg_fps , & stddev , & samples ) )
{
RARCH_LOG ( " [Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time "
" deviation, based on %u last samples). \n " ,
avg_fps , 100.0 * stddev , samples ) ;
}
}
static void video_driver_pixel_converter_free ( void )
{
if ( ! video_driver_scaler_ptr )
return ;
scaler_ctx_gen_reset ( video_driver_scaler_ptr - > scaler ) ;
if ( video_driver_scaler_ptr - > scaler )
free ( video_driver_scaler_ptr - > scaler ) ;
video_driver_scaler_ptr - > scaler = NULL ;
if ( video_driver_scaler_ptr - > scaler_out )
free ( video_driver_scaler_ptr - > scaler_out ) ;
video_driver_scaler_ptr - > scaler_out = NULL ;
if ( video_driver_scaler_ptr )
free ( video_driver_scaler_ptr ) ;
video_driver_scaler_ptr = NULL ;
}
static void video_driver_free_internal ( void )
{
# ifdef HAVE_THREADS
bool is_threaded = video_driver_is_threaded_internal ( ) ;
# endif
# ifdef HAVE_VIDEO_LAYOUT
video_layout_deinit ( ) ;
# endif
command_event ( CMD_EVENT_OVERLAY_DEINIT , NULL ) ;
if ( ! video_driver_is_video_cache_context ( ) )
video_driver_free_hw_context ( ) ;
if ( ! input_driver_is_data_ptr_same ( video_driver_data ) )
input_driver_deinit ( ) ;
if ( video_driver_data
& & current_video & & current_video - > free
)
current_video - > free ( video_driver_data ) ;
video_driver_pixel_converter_free ( ) ;
video_driver_filter_free ( ) ;
command_event ( CMD_EVENT_SHADER_DIR_DEINIT , NULL ) ;
# ifdef HAVE_THREADS
if ( is_threaded )
return ;
# endif
video_driver_monitor_compute_fps_statistics ( ) ;
}
2019-06-17 16:58:43 +02:00
# define video_driver_get_hw_context_internal() (&hw_render)
struct retro_hw_render_callback * video_driver_get_hw_context ( void )
{
return video_driver_get_hw_context_internal ( ) ;
}
2019-06-17 15:10:22 +02:00
static bool video_driver_pixel_converter_init ( unsigned size )
{
struct retro_hw_render_callback * hwr =
2019-06-17 16:58:43 +02:00
video_driver_get_hw_context_internal ( ) ;
2019-06-17 15:10:22 +02:00
void * scalr_out = NULL ;
video_pixel_scaler_t * scalr = NULL ;
struct scaler_ctx * scalr_ctx = NULL ;
/* If pixel format is not 0RGB1555, we don't need to do
* any internal pixel conversion . */
if ( video_driver_pix_fmt ! = RETRO_PIXEL_FORMAT_0RGB1555 )
return true ;
/* No need to perform pixel conversion for HW rendering contexts. */
if ( hwr & & hwr - > context_type ! = RETRO_HW_CONTEXT_NONE )
return true ;
RARCH_WARN ( " 0RGB1555 pixel format is deprecated, "
" and will be slower. For 15/16-bit, RGB565 "
" format is preferred. \n " ) ;
scalr = ( video_pixel_scaler_t * ) calloc ( 1 , sizeof ( * scalr ) ) ;
if ( ! scalr )
goto error ;
video_driver_scaler_ptr = scalr ;
scalr_ctx = ( struct scaler_ctx * ) calloc ( 1 , sizeof ( * scalr_ctx ) ) ;
if ( ! scalr_ctx )
goto error ;
video_driver_scaler_ptr - > scaler = scalr_ctx ;
video_driver_scaler_ptr - > scaler - > scaler_type = SCALER_TYPE_POINT ;
video_driver_scaler_ptr - > scaler - > in_fmt = SCALER_FMT_0RGB1555 ;
/* TODO: Pick either ARGB8888 or RGB565 depending on driver. */
video_driver_scaler_ptr - > scaler - > out_fmt = SCALER_FMT_RGB565 ;
if ( ! scaler_ctx_gen_filter ( scalr_ctx ) )
goto error ;
scalr_out = calloc ( sizeof ( uint16_t ) , size * size ) ;
if ( ! scalr_out )
goto error ;
video_driver_scaler_ptr - > scaler_out = scalr_out ;
return true ;
error :
video_driver_pixel_converter_free ( ) ;
video_driver_filter_free ( ) ;
return false ;
}
static bool video_driver_init_internal ( bool * video_is_threaded )
{
video_info_t video ;
unsigned max_dim , scale , width , height ;
video_viewport_t * custom_vp = NULL ;
const input_driver_t * tmp = NULL ;
rarch_system_info_t * system = NULL ;
static uint16_t dummy_pixels [ 32 ] = { 0 } ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
struct retro_game_geometry * geom = & video_driver_av_info . geometry ;
if ( ! string_is_empty ( settings - > paths . path_softfilter_plugin ) )
video_driver_init_filter ( video_driver_pix_fmt ) ;
max_dim = MAX ( geom - > max_width , geom - > max_height ) ;
scale = next_pow2 ( max_dim ) / RARCH_SCALE_BASE ;
scale = MAX ( scale , 1 ) ;
if ( video_driver_state_filter )
scale = video_driver_state_scale ;
/* Update core-dependent aspect ratio values. */
video_driver_set_viewport_square_pixel ( ) ;
video_driver_set_viewport_core ( ) ;
video_driver_set_viewport_config ( ) ;
/* Update CUSTOM viewport. */
custom_vp = video_viewport_get_custom ( ) ;
if ( settings - > uints . video_aspect_ratio_idx = = ASPECT_RATIO_CUSTOM )
{
float default_aspect = aspectratio_lut [ ASPECT_RATIO_CORE ] . value ;
aspectratio_lut [ ASPECT_RATIO_CUSTOM ] . value =
( custom_vp - > width & & custom_vp - > height ) ?
( float ) custom_vp - > width / custom_vp - > height : default_aspect ;
}
video_driver_set_aspect_ratio_value (
aspectratio_lut [ settings - > uints . video_aspect_ratio_idx ] . value ) ;
if ( settings - > bools . video_fullscreen | | retroarch_is_forced_fullscreen ( ) )
{
width = settings - > uints . video_fullscreen_x ;
height = settings - > uints . video_fullscreen_y ;
}
else
{
/* To-Do: remove when the new window resizing core is hooked */
if ( settings - > bools . video_window_save_positions & &
( settings - > uints . window_position_width | | settings - > uints . window_position_height ) )
{
width = settings - > uints . window_position_width ;
height = settings - > uints . window_position_height ;
}
else
{
if ( settings - > bools . video_force_aspect )
{
/* Do rounding here to simplify integer scale correctness. */
unsigned base_width =
roundf ( geom - > base_height * video_driver_get_aspect_ratio ( ) ) ;
width = roundf ( base_width * settings - > floats . video_scale ) ;
}
else
width = roundf ( geom - > base_width * settings - > floats . video_scale ) ;
height = roundf ( geom - > base_height * settings - > floats . video_scale ) ;
}
}
if ( width & & height )
RARCH_LOG ( " [Video]: Video @ %ux%u \n " , width , height ) ;
else
RARCH_LOG ( " [Video]: Video @ fullscreen \n " ) ;
video_driver_display_type_set ( RARCH_DISPLAY_NONE ) ;
video_driver_display_set ( 0 ) ;
video_driver_window_set ( 0 ) ;
if ( ! video_driver_pixel_converter_init ( RARCH_SCALE_BASE * scale ) )
{
RARCH_ERR ( " [Video]: Failed to initialize pixel converter. \n " ) ;
goto error ;
}
video . width = width ;
video . height = height ;
video . fullscreen = settings - > bools . video_fullscreen | | retroarch_is_forced_fullscreen ( ) ;
video . vsync = settings - > bools . video_vsync & & ! rarch_ctl ( RARCH_CTL_IS_NONBLOCK_FORCED , NULL ) ;
video . force_aspect = settings - > bools . video_force_aspect ;
video . font_enable = settings - > bools . video_font_enable ;
video . swap_interval = settings - > uints . video_swap_interval ;
# ifdef GEKKO
video . viwidth = settings - > uints . video_viwidth ;
video . vfilter = settings - > bools . video_vfilter ;
# endif
video . smooth = settings - > bools . video_smooth ;
video . input_scale = scale ;
video . rgb32 = video_driver_state_filter ?
video_driver_state_out_rgb32 :
( video_driver_pix_fmt = = RETRO_PIXEL_FORMAT_XRGB8888 ) ;
video . parent = 0 ;
video_started_fullscreen = video . fullscreen ;
/* Reset video frame count */
video_driver_frame_count = 0 ;
tmp = input_get_ptr ( ) ;
/* Need to grab the "real" video driver interface on a reinit. */
video_driver_find_driver ( ) ;
# ifdef HAVE_THREADS
video . is_threaded = video_driver_is_threaded_internal ( ) ;
* video_is_threaded = video . is_threaded ;
if ( video . is_threaded )
{
/* Can't do hardware rendering with threaded driver currently. */
RARCH_LOG ( " [Video]: Starting threaded video driver ... \n " ) ;
if ( ! video_init_thread ( ( const video_driver_t * * ) & current_video ,
& video_driver_data ,
input_get_double_ptr ( ) , input_driver_get_data_ptr ( ) ,
current_video , video ) )
{
RARCH_ERR ( " [Video]: Cannot open threaded video driver ... Exiting ... \n " ) ;
goto error ;
}
}
else
# endif
video_driver_data = current_video - > init (
& video , input_get_double_ptr ( ) ,
input_driver_get_data_ptr ( ) ) ;
if ( ! video_driver_data )
{
RARCH_ERR ( " [Video]: Cannot open video driver ... Exiting ... \n " ) ;
goto error ;
}
if ( current_video - > focus )
video_driver_cb_has_focus = video_driver_has_focus ;
video_driver_poke = NULL ;
if ( current_video - > poke_interface )
current_video - > poke_interface ( video_driver_data , & video_driver_poke ) ;
if ( current_video - > viewport_info & &
( ! custom_vp - > width | |
! custom_vp - > height ) )
{
/* Force custom viewport to have sane parameters. */
custom_vp - > width = width ;
custom_vp - > height = height ;
video_driver_get_viewport_info ( custom_vp ) ;
}
system = runloop_get_system_info ( ) ;
video_driver_set_rotation (
( settings - > uints . video_rotation + system - > rotation ) % 4 ) ;
current_video - > suppress_screensaver ( video_driver_data ,
settings - > bools . ui_suspend_screensaver_enable ) ;
video_driver_init_input ( tmp ) ;
command_event ( CMD_EVENT_OVERLAY_DEINIT , NULL ) ;
command_event ( CMD_EVENT_OVERLAY_INIT , NULL ) ;
# ifdef HAVE_VIDEO_LAYOUT
if ( settings - > bools . video_layout_enable )
{
video_layout_init ( video_driver_data , video_driver_layout_render_interface ( ) ) ;
video_layout_load ( settings - > paths . path_video_layout ) ;
video_layout_view_select ( settings - > uints . video_layout_selected_view ) ;
}
# endif
if ( ! core_is_game_loaded ( ) )
video_driver_cached_frame_set ( & dummy_pixels , 4 , 4 , 8 ) ;
# if defined(PSP)
video_driver_set_texture_frame ( & dummy_pixels , false , 1 , 1 , 1.0f ) ;
# endif
video_context_driver_reset ( ) ;
video_display_server_init ( ) ;
if ( ( enum rotation ) settings - > uints . screen_orientation ! = ORIENTATION_NORMAL )
video_display_server_set_screen_orientation ( ( enum rotation ) settings - > uints . screen_orientation ) ;
command_event ( CMD_EVENT_SHADER_DIR_INIT , NULL ) ;
return true ;
error :
retroarch_fail ( 1 , " init_video() " ) ;
return false ;
}
bool video_driver_set_viewport ( unsigned width , unsigned height ,
bool force_fullscreen , bool allow_rotate )
{
if ( ! current_video | | ! current_video - > set_viewport )
return false ;
current_video - > set_viewport ( video_driver_data , width , height ,
force_fullscreen , allow_rotate ) ;
return true ;
}
bool video_driver_set_rotation ( unsigned rotation )
{
if ( ! current_video | | ! current_video - > set_rotation )
return false ;
current_video - > set_rotation ( video_driver_data , rotation ) ;
return true ;
}
bool video_driver_set_video_mode ( unsigned width ,
unsigned height , bool fullscreen )
{
gfx_ctx_mode_t mode ;
if ( video_driver_poke & & video_driver_poke - > set_video_mode )
{
video_driver_poke - > set_video_mode ( video_driver_data ,
width , height , fullscreen ) ;
return true ;
}
mode . width = width ;
mode . height = height ;
mode . fullscreen = fullscreen ;
return video_context_driver_set_video_mode ( & mode ) ;
}
bool video_driver_get_video_output_size ( unsigned * width , unsigned * height )
{
if ( ! video_driver_poke | | ! video_driver_poke - > get_video_output_size )
return false ;
video_driver_poke - > get_video_output_size ( video_driver_data ,
width , height ) ;
return true ;
}
void video_driver_set_osd_msg ( const char * msg , const void * data , void * font )
{
video_frame_info_t video_info ;
video_driver_build_info ( & video_info ) ;
if ( video_driver_poke & & video_driver_poke - > set_osd_msg )
video_driver_poke - > set_osd_msg ( video_driver_data , & video_info , msg , data , font ) ;
}
void video_driver_set_texture_enable ( bool enable , bool fullscreen )
{
if ( video_driver_poke & & video_driver_poke - > set_texture_enable )
video_driver_poke - > set_texture_enable ( video_driver_data ,
enable , fullscreen ) ;
}
void video_driver_set_texture_frame ( const void * frame , bool rgb32 ,
unsigned width , unsigned height , float alpha )
{
if ( video_driver_poke & & video_driver_poke - > set_texture_frame )
video_driver_poke - > set_texture_frame ( video_driver_data ,
frame , rgb32 , width , height , alpha ) ;
}
# ifdef HAVE_OVERLAY
bool video_driver_overlay_interface ( const video_overlay_interface_t * * iface )
{
if ( ! current_video | | ! current_video - > overlay_interface )
return false ;
current_video - > overlay_interface ( video_driver_data , iface ) ;
return true ;
}
# endif
# ifdef HAVE_VIDEO_LAYOUT
const video_layout_render_interface_t * video_driver_layout_render_interface ( void )
{
if ( ! current_video | | ! current_video - > video_layout_render_interface )
return NULL ;
return current_video - > video_layout_render_interface ( video_driver_data ) ;
}
# endif
void * video_driver_read_frame_raw ( unsigned * width ,
unsigned * height , size_t * pitch )
{
if ( ! current_video | | ! current_video - > read_frame_raw )
return NULL ;
return current_video - > read_frame_raw ( video_driver_data , width ,
height , pitch ) ;
}
void video_driver_set_filtering ( unsigned index , bool smooth )
{
if ( video_driver_poke & & video_driver_poke - > set_filtering )
video_driver_poke - > set_filtering ( video_driver_data , index , smooth ) ;
}
void video_driver_cached_frame_set ( const void * data , unsigned width ,
unsigned height , size_t pitch )
{
if ( data )
frame_cache_data = data ;
frame_cache_width = width ;
frame_cache_height = height ;
frame_cache_pitch = pitch ;
}
void video_driver_cached_frame_get ( const void * * data , unsigned * width ,
unsigned * height , size_t * pitch )
{
if ( data )
* data = frame_cache_data ;
if ( width )
* width = frame_cache_width ;
if ( height )
* height = frame_cache_height ;
if ( pitch )
* pitch = frame_cache_pitch ;
}
void video_driver_get_size ( unsigned * width , unsigned * height )
{
# ifdef HAVE_THREADS
bool is_threaded = video_driver_is_threaded_internal ( ) ;
video_driver_threaded_lock ( is_threaded ) ;
# endif
if ( width )
* width = video_driver_width ;
if ( height )
* height = video_driver_height ;
# ifdef HAVE_THREADS
video_driver_threaded_unlock ( is_threaded ) ;
# endif
}
void video_driver_set_size ( unsigned * width , unsigned * height )
{
# ifdef HAVE_THREADS
bool is_threaded = video_driver_is_threaded_internal ( ) ;
video_driver_threaded_lock ( is_threaded ) ;
# endif
if ( width )
video_driver_width = * width ;
if ( height )
video_driver_height = * height ;
# ifdef HAVE_THREADS
video_driver_threaded_unlock ( is_threaded ) ;
# endif
}
/**
* video_monitor_set_refresh_rate :
* @ hz : New refresh rate for monitor .
*
* Sets monitor refresh rate to new value .
* */
void video_monitor_set_refresh_rate ( float hz )
{
char msg [ 128 ] ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
snprintf ( msg , sizeof ( msg ) ,
" Setting refresh rate to: %.3f Hz. " , hz ) ;
runloop_msg_queue_push ( msg , 1 , 180 , false , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_LOG ( " %s \n " , msg ) ;
configuration_set_float ( settings ,
settings - > floats . video_refresh_rate ,
hz ) ;
}
/**
* video_monitor_fps_statistics
* @ refresh_rate : Monitor refresh rate .
* @ deviation : Deviation from measured refresh rate .
* @ sample_points : Amount of sampled points .
*
* Gets the monitor FPS statistics based on the current
* runtime .
*
* Returns : true ( 1 ) on success .
* false ( 0 ) if :
* a ) threaded video mode is enabled
* b ) less than 2 frame time samples .
* c ) FPS monitor enable is off .
* */
bool video_monitor_fps_statistics ( double * refresh_rate ,
double * deviation , unsigned * sample_points )
{
unsigned i ;
retro_time_t accum = 0 ;
retro_time_t avg = 0 ;
retro_time_t accum_var = 0 ;
unsigned samples = 0 ;
# ifdef HAVE_THREADS
if ( video_driver_is_threaded_internal ( ) )
return false ;
# endif
samples = MIN ( MEASURE_FRAME_TIME_SAMPLES_COUNT ,
( unsigned ) video_driver_frame_time_count ) ;
if ( samples < 2 )
return false ;
/* Measure statistics on frame time (microsecs), *not* FPS. */
for ( i = 0 ; i < samples ; i + + )
{
accum + = video_driver_frame_time_samples [ i ] ;
#if 0
RARCH_LOG ( " [Video]: Interval #%u: %d usec / frame. \n " ,
i , ( int ) frame_time_samples [ i ] ) ;
# endif
}
avg = accum / samples ;
/* Drop first measurement. It is likely to be bad. */
for ( i = 0 ; i < samples ; i + + )
{
retro_time_t diff = video_driver_frame_time_samples [ i ] - avg ;
accum_var + = diff * diff ;
}
* deviation = sqrt ( ( double ) accum_var / ( samples - 1 ) ) / avg ;
if ( refresh_rate )
* refresh_rate = 1000000.0 / avg ;
if ( sample_points )
* sample_points = samples ;
return true ;
}
float video_driver_get_aspect_ratio ( void )
{
return video_driver_aspect_ratio ;
}
void video_driver_set_aspect_ratio_value ( float value )
{
video_driver_aspect_ratio = value ;
}
rarch_softfilter_t * video_driver_frame_filter_get_ptr ( void )
{
return video_driver_state_filter ;
}
enum retro_pixel_format video_driver_get_pixel_format ( void )
{
return video_driver_pix_fmt ;
}
void video_driver_set_pixel_format ( enum retro_pixel_format fmt )
{
video_driver_pix_fmt = fmt ;
}
/**
* video_driver_cached_frame :
*
* Renders the current video frame .
* */
bool video_driver_cached_frame ( void )
{
2019-06-17 16:23:46 +02:00
void * recording = recording_data ;
2019-06-17 15:10:22 +02:00
/* Cannot allow recording when pushing duped frames. */
recording_data = NULL ;
retro_ctx . frame_cb (
( frame_cache_data ! = RETRO_HW_FRAME_BUFFER_VALID )
? frame_cache_data : NULL ,
frame_cache_width ,
frame_cache_height , frame_cache_pitch ) ;
recording_data = recording ;
return true ;
}
void video_driver_monitor_adjust_system_rates ( void )
{
float timing_skew = 0.0f ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
float video_refresh_rate = settings - > floats . video_refresh_rate ;
float timing_skew_hz = video_refresh_rate ;
const struct retro_system_timing * info = ( const struct retro_system_timing * ) & video_driver_av_info . timing ;
rarch_ctl ( RARCH_CTL_UNSET_NONBLOCK_FORCED , NULL ) ;
if ( ! info | | info - > fps < = 0.0 )
return ;
video_driver_core_hz = info - > fps ;
if ( video_driver_crt_switching_active )
timing_skew_hz = video_driver_core_hz ;
timing_skew = fabs (
1.0f - info - > fps / timing_skew_hz ) ;
if ( ! settings - > bools . vrr_runloop_enable )
{
/* We don't want to adjust pitch too much. If we have extreme cases,
* just don ' t readjust at all . */
if ( timing_skew < = settings - > floats . audio_max_timing_skew )
return ;
RARCH_LOG ( " [Video]: Timings deviate too much. Will not adjust. "
" (Display = %.2f Hz, Game = %.2f Hz) \n " ,
video_refresh_rate ,
( float ) info - > fps ) ;
}
if ( info - > fps < = timing_skew_hz )
return ;
/* We won't be able to do VSync reliably when game FPS > monitor FPS. */
rarch_ctl ( RARCH_CTL_SET_NONBLOCK_FORCED , NULL ) ;
RARCH_LOG ( " [Video]: Game FPS > Monitor FPS. Cannot rely on VSync. \n " ) ;
}
static void video_driver_lock_new ( void )
{
video_driver_lock_free ( ) ;
# ifdef HAVE_THREADS
if ( ! display_lock )
display_lock = slock_new ( ) ;
retro_assert ( display_lock ) ;
if ( ! context_lock )
context_lock = slock_new ( ) ;
retro_assert ( context_lock ) ;
# endif
}
void video_driver_destroy ( void )
{
video_display_server_destroy ( ) ;
crt_video_restore ( ) ;
video_driver_cb_has_focus = null_driver_has_focus ;
video_driver_use_rgba = false ;
video_driver_active = false ;
video_driver_cache_context = false ;
video_driver_cache_context_ack = false ;
video_driver_record_gpu_buffer = NULL ;
current_video = NULL ;
video_driver_set_cached_frame_ptr ( NULL ) ;
}
void video_driver_set_cached_frame_ptr ( const void * data )
{
if ( data )
frame_cache_data = data ;
}
void video_driver_set_stub_frame ( void )
{
frame_bak = current_video - > frame ;
current_video - > frame = video_null . frame ;
}
void video_driver_unset_stub_frame ( void )
{
if ( frame_bak ! = NULL )
current_video - > frame = frame_bak ;
frame_bak = NULL ;
}
bool video_driver_is_stub_frame ( void )
{
return current_video - > frame = = video_null . frame ;
}
bool video_driver_supports_recording ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
return settings - > bools . video_gpu_record
& & current_video - > read_viewport ;
}
bool video_driver_supports_viewport_read ( void )
{
return current_video - > read_viewport & & current_video - > viewport_info ;
}
bool video_driver_prefer_viewport_read ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
return settings - > bools . video_gpu_screenshot | |
( video_driver_is_hw_context ( ) & & ! current_video - > read_frame_raw ) ;
}
bool video_driver_supports_read_frame_raw ( void )
{
if ( current_video - > read_frame_raw )
return true ;
return false ;
}
void video_driver_set_viewport_config ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
if ( settings - > floats . video_aspect_ratio < 0.0f )
{
struct retro_game_geometry * geom = & video_driver_av_info . geometry ;
if ( geom - > aspect_ratio > 0.0f & &
settings - > bools . video_aspect_ratio_auto )
aspectratio_lut [ ASPECT_RATIO_CONFIG ] . value = geom - > aspect_ratio ;
else
{
unsigned base_width = geom - > base_width ;
unsigned base_height = geom - > base_height ;
/* Get around division by zero errors */
if ( base_width = = 0 )
base_width = 1 ;
if ( base_height = = 0 )
base_height = 1 ;
aspectratio_lut [ ASPECT_RATIO_CONFIG ] . value =
( float ) base_width / base_height ; /* 1:1 PAR. */
}
}
else
{
aspectratio_lut [ ASPECT_RATIO_CONFIG ] . value =
settings - > floats . video_aspect_ratio ;
}
}
void video_driver_set_viewport_square_pixel ( void )
{
unsigned len , highest , i , aspect_x , aspect_y ;
struct retro_game_geometry * geom = & video_driver_av_info . geometry ;
unsigned width = geom - > base_width ;
unsigned height = geom - > base_height ;
if ( width = = 0 | | height = = 0 )
return ;
len = MIN ( width , height ) ;
highest = 1 ;
for ( i = 1 ; i < len ; i + + )
{
if ( ( width % i ) = = 0 & & ( height % i ) = = 0 )
highest = i ;
}
aspect_x = width / highest ;
aspect_y = height / highest ;
snprintf ( aspectratio_lut [ ASPECT_RATIO_SQUARE ] . name ,
sizeof ( aspectratio_lut [ ASPECT_RATIO_SQUARE ] . name ) ,
" 1:1 PAR (%u:%u DAR) " , aspect_x , aspect_y ) ;
aspectratio_lut [ ASPECT_RATIO_SQUARE ] . value = ( float ) aspect_x / aspect_y ;
}
void video_driver_set_viewport_core ( void )
{
struct retro_game_geometry * geom = & video_driver_av_info . geometry ;
if ( ! geom | | geom - > base_width < = 0.0f | | geom - > base_height < = 0.0f )
return ;
/* Fallback to 1:1 pixel ratio if none provided */
if ( geom - > aspect_ratio > 0.0f )
aspectratio_lut [ ASPECT_RATIO_CORE ] . value = geom - > aspect_ratio ;
else
aspectratio_lut [ ASPECT_RATIO_CORE ] . value =
( float ) geom - > base_width / geom - > base_height ;
}
void video_driver_reset_custom_viewport ( void )
{
struct video_viewport * custom_vp = video_viewport_get_custom ( ) ;
custom_vp - > width = 0 ;
custom_vp - > height = 0 ;
custom_vp - > x = 0 ;
custom_vp - > y = 0 ;
}
void video_driver_set_rgba ( void )
{
video_driver_lock ( ) ;
video_driver_use_rgba = true ;
video_driver_unlock ( ) ;
}
void video_driver_unset_rgba ( void )
{
video_driver_lock ( ) ;
video_driver_use_rgba = false ;
video_driver_unlock ( ) ;
}
bool video_driver_supports_rgba ( void )
{
bool tmp ;
video_driver_lock ( ) ;
tmp = video_driver_use_rgba ;
video_driver_unlock ( ) ;
return tmp ;
}
bool video_driver_get_next_video_out ( void )
{
if ( ! video_driver_poke )
return false ;
if ( ! video_driver_poke - > get_video_output_next )
return video_context_driver_get_video_output_next ( ) ;
video_driver_poke - > get_video_output_next ( video_driver_data ) ;
return true ;
}
bool video_driver_get_prev_video_out ( void )
{
if ( ! video_driver_poke )
return false ;
if ( ! video_driver_poke - > get_video_output_prev )
return video_context_driver_get_video_output_prev ( ) ;
video_driver_poke - > get_video_output_prev ( video_driver_data ) ;
return true ;
}
bool video_driver_init ( bool * video_is_threaded )
{
video_driver_lock_new ( ) ;
video_driver_filter_free ( ) ;
video_driver_set_cached_frame_ptr ( NULL ) ;
return video_driver_init_internal ( video_is_threaded ) ;
}
void video_driver_destroy_data ( void )
{
video_driver_data = NULL ;
}
void video_driver_free ( void )
{
video_driver_free_internal ( ) ;
video_driver_lock_free ( ) ;
video_driver_data = NULL ;
video_driver_set_cached_frame_ptr ( NULL ) ;
}
void video_driver_monitor_reset ( void )
{
video_driver_frame_time_count = 0 ;
}
void video_driver_set_aspect_ratio ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
switch ( settings - > uints . video_aspect_ratio_idx )
{
case ASPECT_RATIO_SQUARE :
video_driver_set_viewport_square_pixel ( ) ;
break ;
case ASPECT_RATIO_CORE :
video_driver_set_viewport_core ( ) ;
break ;
case ASPECT_RATIO_CONFIG :
video_driver_set_viewport_config ( ) ;
break ;
default :
break ;
}
video_driver_set_aspect_ratio_value (
aspectratio_lut [ settings - > uints . video_aspect_ratio_idx ] . value ) ;
if ( ! video_driver_poke | | ! video_driver_poke - > set_aspect_ratio )
return ;
video_driver_poke - > set_aspect_ratio (
video_driver_data , settings - > uints . video_aspect_ratio_idx ) ;
}
void video_driver_update_viewport ( struct video_viewport * vp , bool force_full , bool keep_aspect )
{
gfx_ctx_aspect_t aspect_data ;
float device_aspect = ( float ) vp - > full_width / vp - > full_height ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
aspect_data . aspect = & device_aspect ;
aspect_data . width = vp - > full_width ;
aspect_data . height = vp - > full_height ;
video_context_driver_translate_aspect ( & aspect_data ) ;
vp - > x = 0 ;
vp - > y = 0 ;
vp - > width = vp - > full_width ;
vp - > height = vp - > full_height ;
if ( settings - > bools . video_scale_integer & & ! force_full )
{
video_viewport_get_scaled_integer (
vp , vp - > full_width , vp - > full_height , video_driver_get_aspect_ratio ( ) , keep_aspect ) ;
}
else if ( keep_aspect & & ! force_full )
{
float desired_aspect = video_driver_get_aspect_ratio ( ) ;
# if defined(HAVE_MENU)
if ( settings - > uints . video_aspect_ratio_idx = = ASPECT_RATIO_CUSTOM )
{
const struct video_viewport * custom = video_viewport_get_custom ( ) ;
vp - > x = custom - > x ;
vp - > y = custom - > y ;
vp - > width = custom - > width ;
vp - > height = custom - > height ;
}
else
# endif
{
float delta ;
if ( fabsf ( device_aspect - desired_aspect ) < 0.0001f )
{
/* If the aspect ratios of screen and desired aspect
* ratio are sufficiently equal ( floating point stuff ) ,
* assume they are actually equal .
*/
}
else if ( device_aspect > desired_aspect )
{
delta = ( desired_aspect / device_aspect - 1.0f )
/ 2.0f + 0.5f ;
vp - > x = ( int ) roundf ( vp - > full_width * ( 0.5f - delta ) ) ;
vp - > width = ( unsigned ) roundf ( 2.0f * vp - > full_width * delta ) ;
vp - > y = 0 ;
vp - > height = vp - > full_height ;
}
else
{
vp - > x = 0 ;
vp - > width = vp - > full_width ;
delta = ( device_aspect / desired_aspect - 1.0f )
/ 2.0f + 0.5f ;
vp - > y = ( int ) roundf ( vp - > full_height * ( 0.5f - delta ) ) ;
vp - > height = ( unsigned ) roundf ( 2.0f * vp - > full_height * delta ) ;
}
}
}
# if defined(RARCH_MOBILE)
/* In portrait mode, we want viewport to gravitate to top of screen. */
if ( device_aspect < 1.0f )
vp - > y = 0 ;
# endif
}
void video_driver_show_mouse ( void )
{
if ( video_driver_poke & & video_driver_poke - > show_mouse )
video_driver_poke - > show_mouse ( video_driver_data , true ) ;
}
void video_driver_hide_mouse ( void )
{
if ( video_driver_poke & & video_driver_poke - > show_mouse )
video_driver_poke - > show_mouse ( video_driver_data , false ) ;
}
void video_driver_set_nonblock_state ( bool toggle )
{
if ( current_video - > set_nonblock_state )
current_video - > set_nonblock_state ( video_driver_data , toggle ) ;
}
bool video_driver_find_driver ( void )
{
int i ;
driver_ctx_info_t drv ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
if ( video_driver_is_hw_context ( ) )
{
2019-06-17 16:58:43 +02:00
struct retro_hw_render_callback * hwr = video_driver_get_hw_context_internal ( ) ;
2019-06-17 15:10:22 +02:00
current_video = NULL ;
( void ) hwr ;
# if defined(HAVE_VULKAN)
if ( hwr & & hw_render_context_is_vulkan ( hwr - > context_type ) )
{
RARCH_LOG ( " [Video]: Using HW render, Vulkan driver forced. \n " ) ;
current_video = & video_vulkan ;
}
# endif
# if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
if ( hwr & & hw_render_context_is_gl ( hwr - > context_type ) )
{
RARCH_LOG ( " [Video]: Using HW render, OpenGL driver forced. \n " ) ;
/* If we have configured one of the HW render capable GL drivers, go with that. */
if ( ! string_is_equal ( settings - > arrays . video_driver , " gl " ) & &
! string_is_equal ( settings - > arrays . video_driver , " glcore " ) )
{
# if defined(HAVE_OPENGL_CORE)
current_video = & video_gl_core ;
RARCH_LOG ( " [Video]: Forcing \" glcore \" driver. \n " ) ;
# else
current_video = & video_gl2 ;
RARCH_LOG ( " [Video]: Forcing \" gl \" driver. \n " ) ;
# endif
}
else
{
RARCH_LOG ( " [Video]: Using configured \" %s \" driver for GL HW render. \n " ,
settings - > arrays . video_driver ) ;
}
}
# endif
if ( current_video )
return true ;
}
if ( frontend_driver_has_get_video_driver_func ( ) )
{
current_video = ( video_driver_t * ) frontend_driver_get_video_driver ( ) ;
if ( current_video )
return true ;
RARCH_WARN ( " Frontend supports get_video_driver() but did not specify one. \n " ) ;
}
drv . label = " video_driver " ;
drv . s = settings - > arrays . video_driver ;
driver_ctl ( RARCH_DRIVER_CTL_FIND_INDEX , & drv ) ;
i = ( int ) drv . len ;
if ( i > = 0 )
current_video = ( video_driver_t * ) video_driver_find_handle ( i ) ;
else
{
if ( verbosity_is_enabled ( ) )
{
unsigned d ;
RARCH_ERR ( " Couldn't find any video driver named \" %s \" \n " ,
settings - > arrays . video_driver ) ;
RARCH_LOG_OUTPUT ( " Available video drivers are: \n " ) ;
for ( d = 0 ; video_driver_find_handle ( d ) ; d + + )
RARCH_LOG_OUTPUT ( " \t %s \n " , video_driver_find_ident ( d ) ) ;
RARCH_WARN ( " Going to default to first video driver... \n " ) ;
}
current_video = ( video_driver_t * ) video_driver_find_handle ( 0 ) ;
if ( ! current_video )
retroarch_fail ( 1 , " find_video_driver() " ) ;
}
return true ;
}
void video_driver_apply_state_changes ( void )
{
if ( video_driver_poke & &
video_driver_poke - > apply_state_changes )
video_driver_poke - > apply_state_changes ( video_driver_data ) ;
}
bool video_driver_read_viewport ( uint8_t * buffer , bool is_idle )
{
if ( current_video - > read_viewport
& & current_video - > read_viewport (
video_driver_data , buffer , is_idle ) )
return true ;
return false ;
}
bool video_driver_frame_filter_alive ( void )
{
return ! ! video_driver_state_filter ;
}
bool video_driver_frame_filter_is_32bit ( void )
{
return video_driver_state_out_rgb32 ;
}
void video_driver_default_settings ( void )
{
2019-06-17 15:37:34 +02:00
global_t * global = & g_extern ;
2019-06-17 15:10:22 +02:00
if ( ! global )
return ;
global - > console . screen . gamma_correction = DEFAULT_GAMMA ;
global - > console . flickerfilter_enable = false ;
global - > console . softfilter_enable = false ;
global - > console . screen . resolutions . current . id = 0 ;
}
void video_driver_load_settings ( config_file_t * conf )
{
bool tmp_bool = false ;
2019-06-17 15:37:34 +02:00
global_t * global = & g_extern ;
2019-06-17 15:10:22 +02:00
if ( ! conf )
return ;
# ifdef _XBOX
CONFIG_GET_BOOL_BASE ( conf , global ,
console . screen . gamma_correction , " gamma_correction " ) ;
# else
CONFIG_GET_INT_BASE ( conf , global ,
console . screen . gamma_correction , " gamma_correction " ) ;
# endif
if ( config_get_bool ( conf , " flicker_filter_enable " ,
& tmp_bool ) )
global - > console . flickerfilter_enable = tmp_bool ;
if ( config_get_bool ( conf , " soft_filter_enable " ,
& tmp_bool ) )
global - > console . softfilter_enable = tmp_bool ;
CONFIG_GET_INT_BASE ( conf , global ,
console . screen . soft_filter_index ,
" soft_filter_index " ) ;
CONFIG_GET_INT_BASE ( conf , global ,
console . screen . resolutions . current . id ,
" current_resolution_id " ) ;
CONFIG_GET_INT_BASE ( conf , global ,
console . screen . flicker_filter_index ,
" flicker_filter_index " ) ;
}
void video_driver_save_settings ( config_file_t * conf )
{
2019-06-17 15:37:34 +02:00
global_t * global = & g_extern ;
2019-06-17 15:10:22 +02:00
if ( ! conf )
return ;
# ifdef _XBOX
config_set_bool ( conf , " gamma_correction " ,
global - > console . screen . gamma_correction ) ;
# else
config_set_int ( conf , " gamma_correction " ,
global - > console . screen . gamma_correction ) ;
# endif
config_set_bool ( conf , " flicker_filter_enable " ,
global - > console . flickerfilter_enable ) ;
config_set_bool ( conf , " soft_filter_enable " ,
global - > console . softfilter_enable ) ;
config_set_int ( conf , " soft_filter_index " ,
global - > console . screen . soft_filter_index ) ;
config_set_int ( conf , " current_resolution_id " ,
global - > console . screen . resolutions . current . id ) ;
config_set_int ( conf , " flicker_filter_index " ,
global - > console . screen . flicker_filter_index ) ;
}
void video_driver_reinit ( void )
{
struct retro_hw_render_callback * hwr =
2019-06-17 16:58:43 +02:00
video_driver_get_hw_context_internal ( ) ;
2019-06-17 15:10:22 +02:00
if ( hwr - > cache_context )
video_driver_cache_context = true ;
else
video_driver_cache_context = false ;
video_driver_cache_context_ack = false ;
command_event ( CMD_EVENT_RESET_CONTEXT , NULL ) ;
video_driver_cache_context = false ;
}
bool video_driver_is_hw_context ( void )
{
bool is_hw_context = false ;
video_driver_context_lock ( ) ;
is_hw_context = ( hw_render . context_type ! = RETRO_HW_CONTEXT_NONE ) ;
video_driver_context_unlock ( ) ;
return is_hw_context ;
}
void video_driver_free_hw_context ( void )
{
video_driver_context_lock ( ) ;
if ( hw_render . context_destroy )
hw_render . context_destroy ( ) ;
memset ( & hw_render , 0 , sizeof ( hw_render ) ) ;
video_driver_context_unlock ( ) ;
hw_render_context_negotiation = NULL ;
}
const struct retro_hw_render_context_negotiation_interface *
video_driver_get_context_negotiation_interface ( void )
{
return hw_render_context_negotiation ;
}
void video_driver_set_context_negotiation_interface (
const struct retro_hw_render_context_negotiation_interface * iface )
{
hw_render_context_negotiation = iface ;
}
bool video_driver_is_video_cache_context ( void )
{
return video_driver_cache_context ;
}
void video_driver_set_video_cache_context_ack ( void )
{
video_driver_cache_context_ack = true ;
}
void video_driver_unset_video_cache_context_ack ( void )
{
video_driver_cache_context_ack = false ;
}
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 )
{
if (
video_driver_poke
& & video_driver_poke - > get_current_software_framebuffer
& & video_driver_poke - > get_current_software_framebuffer (
video_driver_data , fb ) )
return true ;
return false ;
}
bool video_driver_get_hw_render_interface (
const struct retro_hw_render_interface * * iface )
{
if (
video_driver_poke
& & video_driver_poke - > get_hw_render_interface
& & video_driver_poke - > get_hw_render_interface (
video_driver_data , iface ) )
return true ;
return false ;
}
bool video_driver_get_viewport_info ( struct video_viewport * viewport )
{
if ( ! current_video | | ! current_video - > viewport_info )
return false ;
current_video - > viewport_info ( video_driver_data , viewport ) ;
return true ;
}
void video_driver_set_title_buf ( void )
{
struct retro_system_info info ;
core_get_system_info ( & info ) ;
fill_pathname_join_concat_noext (
video_driver_title_buf ,
msg_hash_to_str ( MSG_PROGRAM ) ,
" " ,
info . library_name ,
sizeof ( video_driver_title_buf ) ) ;
strlcat ( video_driver_title_buf , " " ,
sizeof ( video_driver_title_buf ) ) ;
strlcat ( video_driver_title_buf , info . library_version ,
sizeof ( video_driver_title_buf ) ) ;
}
/**
* video_viewport_get_scaled_integer :
* @ vp : Viewport handle
* @ width : Width .
* @ height : Height .
* @ aspect_ratio : Aspect ratio ( in float ) .
* @ keep_aspect : Preserve aspect ratio ?
*
* Gets viewport scaling dimensions based on
* scaled integer aspect ratio .
* */
void video_viewport_get_scaled_integer ( struct video_viewport * vp ,
unsigned width , unsigned height ,
float aspect_ratio , bool keep_aspect )
{
int padding_x = 0 ;
int padding_y = 0 ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
if ( settings - > uints . video_aspect_ratio_idx = = ASPECT_RATIO_CUSTOM )
{
struct video_viewport * custom = video_viewport_get_custom ( ) ;
if ( custom )
{
padding_x = width - custom - > width ;
padding_y = height - custom - > height ;
width = custom - > width ;
height = custom - > height ;
}
}
else
{
unsigned base_width ;
/* Use system reported sizes as these define the
* geometry for the " normal " case . */
unsigned base_height =
video_driver_av_info . geometry . base_height ;
if ( base_height = = 0 )
base_height = 1 ;
/* Account for non-square pixels.
* This is sort of contradictory with the goal of integer scale ,
* but it is desirable in some cases .
*
* If square pixels are used , base_height will be equal to
* system - > av_info . base_height . */
base_width = ( unsigned ) roundf ( base_height * aspect_ratio ) ;
/* Make sure that we don't get 0x scale ... */
if ( width > = base_width & & height > = base_height )
{
if ( keep_aspect )
{
/* X/Y scale must be same. */
unsigned max_scale = MIN ( width / base_width ,
height / base_height ) ;
padding_x = width - base_width * max_scale ;
padding_y = height - base_height * max_scale ;
}
else
{
/* X/Y can be independent, each scaled as much as possible. */
padding_x = width % base_width ;
padding_y = height % base_height ;
}
}
width - = padding_x ;
height - = padding_y ;
}
vp - > width = width ;
vp - > height = height ;
vp - > x = padding_x / 2 ;
vp - > y = padding_y / 2 ;
}
struct retro_system_av_info * video_viewport_get_system_av_info ( void )
{
return & video_driver_av_info ;
}
struct video_viewport * video_viewport_get_custom ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
return & settings - > video_viewport_custom ;
}
unsigned video_pixel_get_alignment ( unsigned pitch )
{
if ( pitch & 1 )
return 1 ;
if ( pitch & 2 )
return 2 ;
if ( pitch & 4 )
return 4 ;
return 8 ;
}
/**
* video_driver_frame :
* @ data : pointer to data of the video frame .
* @ width : width of the video frame .
* @ height : height of the video frame .
* @ pitch : pitch of the video frame .
*
* Video frame render callback function .
* */
void video_driver_frame ( const void * data , unsigned width ,
unsigned height , size_t pitch )
{
static char video_driver_msg [ 256 ] ;
video_frame_info_t video_info ;
static retro_time_t curr_time ;
static retro_time_t fps_time ;
static float last_fps , frame_time ;
retro_time_t new_time =
cpu_features_get_time_usec ( ) ;
if ( ! video_driver_active )
return ;
if ( video_driver_scaler_ptr & & data & &
( video_driver_pix_fmt = = RETRO_PIXEL_FORMAT_0RGB1555 ) & &
( data ! = RETRO_HW_FRAME_BUFFER_VALID ) )
{
if ( video_pixel_frame_scale (
video_driver_scaler_ptr - > scaler ,
video_driver_scaler_ptr - > scaler_out ,
data , width , height , pitch ) )
{
data = video_driver_scaler_ptr - > scaler_out ;
pitch = video_driver_scaler_ptr - > scaler - > out_stride ;
}
}
if ( data )
frame_cache_data = data ;
frame_cache_width = width ;
frame_cache_height = height ;
frame_cache_pitch = pitch ;
video_driver_build_info ( & video_info ) ;
/* Get the amount of frames per seconds. */
if ( video_driver_frame_count )
{
static char title [ 256 ] ;
unsigned write_index =
video_driver_frame_time_count + + &
( MEASURE_FRAME_TIME_SAMPLES_COUNT - 1 ) ;
frame_time = new_time - fps_time ;
video_driver_frame_time_samples [ write_index ] = frame_time ;
fps_time = new_time ;
if ( video_driver_frame_count = = 1 )
strlcpy ( title , video_driver_window_title , sizeof ( title ) ) ;
if ( video_info . fps_show )
{
snprintf ( video_info . fps_text , sizeof ( video_info . fps_text ) ,
" FPS: %6.1f " , last_fps ) ;
if ( video_info . framecount_show )
strlcat ( video_info . fps_text , " || " , sizeof ( video_info . fps_text ) ) ;
}
if ( video_info . framecount_show )
{
char frames_text [ 64 ] ;
snprintf ( frames_text ,
sizeof ( frames_text ) ,
" %s: % " PRIu64 , msg_hash_to_str ( MSG_FRAMES ) ,
( uint64_t ) video_driver_frame_count ) ;
strlcat ( video_info . fps_text , frames_text , sizeof ( video_info . fps_text ) ) ;
}
if ( ( video_driver_frame_count % FPS_UPDATE_INTERVAL ) = = 0 )
{
last_fps = TIME_TO_FPS ( curr_time , new_time , FPS_UPDATE_INTERVAL ) ;
strlcpy ( video_driver_window_title , title , sizeof ( video_driver_window_title ) ) ;
if ( ! string_is_empty ( video_info . fps_text ) )
{
strlcat ( video_driver_window_title , " || " , sizeof ( video_driver_window_title ) ) ;
strlcat ( video_driver_window_title ,
video_info . fps_text , sizeof ( video_driver_window_title ) ) ;
}
curr_time = new_time ;
video_driver_window_title_update = true ;
}
}
else
{
curr_time = fps_time = new_time ;
strlcpy ( video_driver_window_title ,
video_driver_title_buf ,
sizeof ( video_driver_window_title ) ) ;
if ( video_info . fps_show )
strlcpy ( video_info . fps_text ,
msg_hash_to_str ( MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE ) ,
sizeof ( video_info . fps_text ) ) ;
video_driver_window_title_update = true ;
}
video_info . frame_rate = last_fps ;
video_info . frame_time = frame_time / 1000.0f ;
video_info . frame_count = ( uint64_t ) video_driver_frame_count ;
/* Slightly messy code,
* but we really need to do processing before blocking on VSync
* for best possible scheduling .
*/
if (
(
! video_driver_state_filter
| | ! video_info . post_filter_record
| | ! data
| | video_driver_record_gpu_buffer
) & & recording_data
2019-06-17 16:23:46 +02:00
& & recording_driver & & recording_driver - > push_video
2019-06-17 15:10:22 +02:00
)
recording_dump_frame ( data , width , height ,
pitch , video_info . runloop_is_idle ) ;
if ( data & & video_driver_state_filter )
{
unsigned output_width = 0 ;
unsigned output_height = 0 ;
unsigned output_pitch = 0 ;
rarch_softfilter_get_output_size ( video_driver_state_filter ,
& output_width , & output_height , width , height ) ;
output_pitch = ( output_width ) * video_driver_state_out_bpp ;
rarch_softfilter_process ( video_driver_state_filter ,
video_driver_state_buffer , output_pitch ,
data , width , height , pitch ) ;
2019-06-17 16:23:46 +02:00
if ( video_info . post_filter_record & & recording_data
& & recording_driver & & recording_driver - > push_video )
2019-06-17 15:10:22 +02:00
recording_dump_frame ( video_driver_state_buffer ,
output_width , output_height , output_pitch ,
video_info . runloop_is_idle ) ;
data = video_driver_state_buffer ;
width = output_width ;
height = output_height ;
pitch = output_pitch ;
}
video_driver_msg [ 0 ] = ' \0 ' ;
if ( video_info . font_enable )
{
const char * msg = NULL ;
# ifdef HAVE_THREADS
runloop_msg_queue_lock_internal ( ) ;
# endif
msg = msg_queue_pull ( runloop_msg_queue ) ;
if ( msg )
strlcpy ( video_driver_msg , msg , sizeof ( video_driver_msg ) ) ;
# ifdef HAVE_THREADS
runloop_msg_queue_unlock_internal ( ) ;
# endif
}
if ( video_info . statistics_show )
{
audio_statistics_t audio_stats = { 0.0f } ;
double stddev = 0.0 ;
struct retro_system_av_info * av_info = & video_driver_av_info ;
unsigned red = 255 ;
unsigned green = 255 ;
unsigned blue = 255 ;
unsigned alpha = 255 ;
video_monitor_fps_statistics ( NULL , & stddev , NULL ) ;
video_info . osd_stat_params . x = 0.010f ;
video_info . osd_stat_params . y = 0.950f ;
video_info . osd_stat_params . scale = 1.0f ;
video_info . osd_stat_params . full_screen = true ;
video_info . osd_stat_params . drop_x = - 2 ;
video_info . osd_stat_params . drop_y = - 2 ;
video_info . osd_stat_params . drop_mod = 0.3f ;
video_info . osd_stat_params . drop_alpha = 1.0f ;
video_info . osd_stat_params . color = COLOR_ABGR (
red , green , blue , alpha ) ;
compute_audio_buffer_statistics ( & audio_stats ) ;
snprintf ( video_info . stat_text ,
sizeof ( video_info . stat_text ) ,
" Video Statistics: \n -Frame rate: %6.2f fps \n -Frame time: %6.2f ms \n -Frame time deviation: %.3f %% \n "
" -Frame count: % " PRIu64 " \n -Viewport: %d x %d x %3.2f \n "
" Audio Statistics: \n -Average buffer saturation: %.2f %% \n -Standard deviation: %.2f %% \n -Time spent close to underrun: %.2f %% \n -Time spent close to blocking: %.2f %% \n -Sample count: %d \n "
" Core Geometry: \n -Size: %u x %u \n -Max Size: %u x %u \n -Aspect: %3.2f \n Core Timing: \n -FPS: %3.2f \n -Sample Rate: %6.2f \n " ,
video_info . frame_rate ,
video_info . frame_time ,
100.0 * stddev ,
video_info . frame_count ,
video_info . width ,
video_info . height ,
video_info . refresh_rate ,
audio_stats . average_buffer_saturation ,
audio_stats . std_deviation_percentage ,
audio_stats . close_to_underrun ,
audio_stats . close_to_blocking ,
audio_stats . samples ,
av_info - > geometry . base_width ,
av_info - > geometry . base_height ,
av_info - > geometry . max_width ,
av_info - > geometry . max_height ,
av_info - > geometry . aspect_ratio ,
av_info - > timing . fps ,
av_info - > timing . sample_rate ) ;
/* TODO/FIXME - add OSD chat text here */
#if 0
snprintf ( video_info . chat_text , sizeof ( video_info . chat_text ) ,
" anon: does retroarch netplay have in-game chat? \n radius: I don't know \u2605 " ) ;
# endif
}
video_driver_active = current_video - > frame (
video_driver_data , data , width , height ,
video_driver_frame_count ,
( unsigned ) pitch , video_driver_msg , & video_info ) ;
video_driver_frame_count + + ;
/* Display the FPS, with a higher priority. */
if ( video_info . fps_show | | video_info . framecount_show )
{
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
if ( ! menu_widgets_set_fps_text ( video_info . fps_text ) )
# endif
runloop_msg_queue_push ( video_info . fps_text , 2 , 1 , true , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
/* trigger set resolution*/
if ( video_info . crt_switch_resolution )
{
video_driver_crt_switching_active = true ;
if ( video_info . crt_switch_resolution_super = = 2560 )
width = 2560 ;
if ( video_info . crt_switch_resolution_super = = 3840 )
width = 3840 ;
if ( video_info . crt_switch_resolution_super = = 1920 )
width = 1920 ;
if ( video_info . crt_switch_resolution_super = = 1 )
video_driver_crt_dynamic_super_width = true ;
else
video_driver_crt_dynamic_super_width = false ;
crt_switch_res_core ( width , height , video_driver_core_hz , video_info . crt_switch_resolution , video_info . crt_switch_center_adjust , video_info . monitor_index , video_driver_crt_dynamic_super_width ) ;
}
else if ( ! video_info . crt_switch_resolution )
video_driver_crt_switching_active = false ;
/* trigger set resolution*/
}
void crt_switch_driver_reinit ( void )
{
video_driver_reinit ( ) ;
}
void video_driver_display_type_set ( enum rarch_display_type type )
{
video_driver_display_type = type ;
}
uintptr_t video_driver_display_get ( void )
{
return video_driver_display ;
}
void video_driver_display_set ( uintptr_t idx )
{
video_driver_display = idx ;
}
enum rarch_display_type video_driver_display_type_get ( void )
{
return video_driver_display_type ;
}
void video_driver_window_set ( uintptr_t idx )
{
video_driver_window = idx ;
}
uintptr_t video_driver_window_get ( void )
{
return video_driver_window ;
}
bool video_driver_texture_load ( void * data ,
enum texture_filter_type filter_type ,
uintptr_t * id )
{
# ifdef HAVE_THREADS
bool is_threaded = video_driver_is_threaded_internal ( ) ;
# endif
if ( ! id | | ! video_driver_poke | | ! video_driver_poke - > load_texture )
return false ;
# ifdef HAVE_THREADS
if ( is_threaded )
video_context_driver_make_current ( false ) ;
# endif
* id = video_driver_poke - > load_texture ( video_driver_data , data ,
video_driver_is_threaded_internal ( ) ,
filter_type ) ;
return true ;
}
bool video_driver_texture_unload ( uintptr_t * id )
{
# ifdef HAVE_THREADS
bool is_threaded = video_driver_is_threaded_internal ( ) ;
# endif
if ( ! video_driver_poke | | ! video_driver_poke - > unload_texture )
return false ;
# ifdef HAVE_THREADS
if ( is_threaded )
video_context_driver_make_current ( false ) ;
# endif
video_driver_poke - > unload_texture ( video_driver_data , * id ) ;
* id = 0 ;
return true ;
}
void video_driver_build_info ( video_frame_info_t * video_info )
{
bool is_perfcnt_enable = false ;
bool is_paused = false ;
bool is_idle = false ;
bool is_slowmotion = false ;
video_viewport_t * custom_vp = NULL ;
struct retro_hw_render_callback * hwr =
2019-06-17 16:58:43 +02:00
video_driver_get_hw_context_internal ( ) ;
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
# ifdef HAVE_THREADS
bool is_threaded = video_driver_is_threaded_internal ( ) ;
video_driver_threaded_lock ( is_threaded ) ;
# endif
custom_vp = & settings - > video_viewport_custom ;
video_info - > refresh_rate = settings - > floats . video_refresh_rate ;
video_info - > crt_switch_resolution = settings - > uints . crt_switch_resolution ;
video_info - > crt_switch_resolution_super = settings - > uints . crt_switch_resolution_super ;
video_info - > crt_switch_center_adjust = settings - > ints . crt_switch_center_adjust ;
video_info - > black_frame_insertion = settings - > bools . video_black_frame_insertion ;
video_info - > hard_sync = settings - > bools . video_hard_sync ;
video_info - > hard_sync_frames = settings - > uints . video_hard_sync_frames ;
video_info - > fps_show = settings - > bools . video_fps_show ;
video_info - > statistics_show = settings - > bools . video_statistics_show ;
video_info - > framecount_show = settings - > bools . video_framecount_show ;
video_info - > scale_integer = settings - > bools . video_scale_integer ;
video_info - > aspect_ratio_idx = settings - > uints . video_aspect_ratio_idx ;
video_info - > post_filter_record = settings - > bools . video_post_filter_record ;
video_info - > input_menu_swap_ok_cancel_buttons = settings - > bools . input_menu_swap_ok_cancel_buttons ;
video_info - > max_swapchain_images = settings - > uints . video_max_swapchain_images ;
video_info - > windowed_fullscreen = settings - > bools . video_windowed_fullscreen ;
video_info - > fullscreen = settings - > bools . video_fullscreen | | retroarch_is_forced_fullscreen ( ) ;
video_info - > monitor_index = settings - > uints . video_monitor_index ;
video_info - > shared_context = settings - > bools . video_shared_context ;
if ( libretro_get_shared_context ( ) & & hwr & & hwr - > context_type ! = RETRO_HW_CONTEXT_NONE )
video_info - > shared_context = true ;
video_info - > font_enable = settings - > bools . video_font_enable ;
video_info - > font_msg_pos_x = settings - > floats . video_msg_pos_x ;
video_info - > font_msg_pos_y = settings - > floats . video_msg_pos_y ;
video_info - > font_msg_color_r = settings - > floats . video_msg_color_r ;
video_info - > font_msg_color_g = settings - > floats . video_msg_color_g ;
video_info - > font_msg_color_b = settings - > floats . video_msg_color_b ;
video_info - > custom_vp_x = custom_vp - > x ;
video_info - > custom_vp_y = custom_vp - > y ;
video_info - > custom_vp_width = custom_vp - > width ;
video_info - > custom_vp_height = custom_vp - > height ;
video_info - > custom_vp_full_width = custom_vp - > full_width ;
video_info - > custom_vp_full_height = custom_vp - > full_height ;
video_info - > fps_text [ 0 ] = ' \0 ' ;
video_info - > width = video_driver_width ;
video_info - > height = video_driver_height ;
video_info - > use_rgba = video_driver_use_rgba ;
video_info - > libretro_running = false ;
video_info - > msg_bgcolor_enable = settings - > bools . video_msg_bgcolor_enable ;
# ifdef HAVE_MENU
video_info - > menu_is_alive = menu_driver_is_alive ( ) ;
video_info - > menu_footer_opacity = settings - > floats . menu_footer_opacity ;
video_info - > menu_header_opacity = settings - > floats . menu_header_opacity ;
video_info - > materialui_color_theme = settings - > uints . menu_materialui_color_theme ;
video_info - > ozone_color_theme = settings - > uints . menu_ozone_color_theme ;
video_info - > menu_shader_pipeline = settings - > uints . menu_xmb_shader_pipeline ;
video_info - > xmb_theme = settings - > uints . menu_xmb_theme ;
video_info - > xmb_color_theme = settings - > uints . menu_xmb_color_theme ;
video_info - > timedate_enable = settings - > bools . menu_timedate_enable ;
video_info - > battery_level_enable = settings - > bools . menu_battery_level_enable ;
video_info - > xmb_shadows_enable = settings - > bools . menu_xmb_shadows_enable ;
video_info - > xmb_alpha_factor = settings - > uints . menu_xmb_alpha_factor ;
video_info - > menu_wallpaper_opacity = settings - > floats . menu_wallpaper_opacity ;
video_info - > menu_framebuffer_opacity = settings - > floats . menu_framebuffer_opacity ;
video_info - > libretro_running = core_is_game_loaded ( ) ;
# else
video_info - > menu_is_alive = false ;
video_info - > menu_footer_opacity = 0.0f ;
video_info - > menu_header_opacity = 0.0f ;
video_info - > materialui_color_theme = 0 ;
video_info - > menu_shader_pipeline = 0 ;
video_info - > xmb_color_theme = 0 ;
video_info - > xmb_theme = 0 ;
video_info - > timedate_enable = false ;
video_info - > battery_level_enable = false ;
video_info - > xmb_shadows_enable = false ;
video_info - > xmb_alpha_factor = 0.0f ;
video_info - > menu_framebuffer_opacity = 0.0f ;
video_info - > menu_wallpaper_opacity = 0.0f ;
# endif
runloop_get_status ( & is_paused , & is_idle , & is_slowmotion , & is_perfcnt_enable ) ;
video_info - > is_perfcnt_enable = is_perfcnt_enable ;
video_info - > runloop_is_paused = is_paused ;
video_info - > runloop_is_idle = is_idle ;
video_info - > runloop_is_slowmotion = is_slowmotion ;
video_info - > input_driver_nonblock_state = input_driver_is_nonblock_state ( ) ;
video_info - > context_data = video_context_data ;
video_info - > cb_update_window_title = current_video_context . update_window_title ;
video_info - > cb_swap_buffers = current_video_context . swap_buffers ;
video_info - > cb_get_metrics = current_video_context . get_metrics ;
video_info - > cb_set_resize = current_video_context . set_resize ;
video_info - > userdata = video_driver_get_ptr ( false ) ;
# ifdef HAVE_THREADS
video_driver_threaded_unlock ( is_threaded ) ;
# endif
}
/**
* video_driver_translate_coord_viewport :
* @ mouse_x : Pointer X coordinate .
* @ mouse_y : Pointer Y coordinate .
* @ res_x : Scaled X coordinate .
* @ res_y : Scaled Y coordinate .
* @ res_screen_x : Scaled screen X coordinate .
* @ res_screen_y : Scaled screen Y coordinate .
*
* Translates pointer [ X , Y ] coordinates into scaled screen
* coordinates based on viewport info .
*
* Returns : true ( 1 ) if successful , false if video driver doesn ' t support
* viewport info .
* */
bool video_driver_translate_coord_viewport (
struct video_viewport * vp ,
int mouse_x , int mouse_y ,
int16_t * res_x , int16_t * res_y ,
int16_t * res_screen_x , int16_t * res_screen_y )
{
int scaled_screen_x , scaled_screen_y , scaled_x , scaled_y ;
int norm_vp_width = ( int ) vp - > width ;
int norm_vp_height = ( int ) vp - > height ;
int norm_full_vp_width = ( int ) vp - > full_width ;
int norm_full_vp_height = ( int ) vp - > full_height ;
if ( norm_full_vp_width < = 0 | | norm_full_vp_height < = 0 )
return false ;
if ( mouse_x > = 0 & & mouse_x < = norm_full_vp_width )
scaled_screen_x = ( ( 2 * mouse_x * 0x7fff )
/ norm_full_vp_width ) - 0x7fff ;
else
scaled_screen_x = - 0x8000 ; /* OOB */
if ( mouse_y > = 0 & & mouse_y < = norm_full_vp_height )
scaled_screen_y = ( ( 2 * mouse_y * 0x7fff )
/ norm_full_vp_height ) - 0x7fff ;
else
scaled_screen_y = - 0x8000 ; /* OOB */
mouse_x - = vp - > x ;
mouse_y - = vp - > y ;
if ( mouse_x > = 0 & & mouse_x < = norm_vp_width )
scaled_x = ( ( 2 * mouse_x * 0x7fff )
/ norm_vp_width ) - 0x7fff ;
else
scaled_x = - 0x8000 ; /* OOB */
if ( mouse_y > = 0 & & mouse_y < = norm_vp_height )
scaled_y = ( ( 2 * mouse_y * 0x7fff )
/ norm_vp_height ) - 0x7fff ;
else
scaled_y = - 0x8000 ; /* OOB */
* res_x = scaled_x ;
* res_y = scaled_y ;
* res_screen_x = scaled_screen_x ;
* res_screen_y = scaled_screen_y ;
return true ;
}
void video_driver_get_window_title ( char * buf , unsigned len )
{
if ( buf & & video_driver_window_title_update )
{
strlcpy ( buf , video_driver_window_title , len ) ;
video_driver_window_title_update = false ;
}
}
void video_driver_get_status ( uint64_t * frame_count , bool * is_alive ,
bool * is_focused )
{
* frame_count = video_driver_frame_count ;
* is_alive = current_video ?
current_video - > alive ( video_driver_data ) : true ;
* is_focused = video_driver_cb_has_focus ( ) ;
}
/**
* find_video_context_driver_driver_index :
* @ ident : Identifier of resampler driver to find .
*
* Finds graphics context driver index by @ ident name .
*
* Returns : graphics context driver index if driver was found , otherwise
* - 1.
* */
static int find_video_context_driver_index ( const char * ident )
{
unsigned i ;
for ( i = 0 ; gfx_ctx_drivers [ i ] ; i + + )
if ( string_is_equal_noncase ( ident , gfx_ctx_drivers [ i ] - > ident ) )
return i ;
return - 1 ;
}
/**
* find_prev_context_driver :
*
* Finds previous driver in graphics context driver array .
* */
bool video_context_driver_find_prev_driver ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
int i = find_video_context_driver_index (
settings - > arrays . video_context_driver ) ;
if ( i > 0 )
{
strlcpy ( settings - > arrays . video_context_driver ,
gfx_ctx_drivers [ i - 1 ] - > ident ,
sizeof ( settings - > arrays . video_context_driver ) ) ;
return true ;
}
RARCH_WARN ( " Couldn't find any previous video context driver. \n " ) ;
return false ;
}
/**
* find_next_context_driver :
*
* Finds next driver in graphics context driver array .
* */
bool video_context_driver_find_next_driver ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
int i = find_video_context_driver_index (
settings - > arrays . video_context_driver ) ;
if ( i > = 0 & & gfx_ctx_drivers [ i + 1 ] )
{
strlcpy ( settings - > arrays . video_context_driver ,
gfx_ctx_drivers [ i + 1 ] - > ident ,
sizeof ( settings - > arrays . video_context_driver ) ) ;
return true ;
}
RARCH_WARN ( " Couldn't find any next video context driver. \n " ) ;
return false ;
}
/**
* video_context_driver_init :
* @ data : Input data .
* @ ctx : Graphics context driver to initialize .
* @ ident : Identifier of graphics context driver to find .
* @ api : API of higher - level graphics API .
* @ major : Major version number of higher - level graphics API .
* @ minor : Minor version number of higher - level graphics API .
* @ hw_render_ctx : Request a graphics context driver capable of
* hardware rendering ?
*
* Initialize graphics context driver .
*
* Returns : graphics context driver if successfully initialized ,
* otherwise NULL .
* */
static const gfx_ctx_driver_t * video_context_driver_init (
void * data ,
const gfx_ctx_driver_t * ctx ,
const char * ident ,
enum gfx_ctx_api api , unsigned major ,
unsigned minor , bool hw_render_ctx ,
void * * ctx_data )
{
video_frame_info_t video_info ;
if ( ! ctx - > bind_api ( data , api , major , minor ) )
{
RARCH_WARN ( " Failed to bind API (#%u, version %u.%u) "
" on context driver \" %s \" . \n " ,
( unsigned ) api , major , minor , ctx - > ident ) ;
return NULL ;
}
video_driver_build_info ( & video_info ) ;
if ( ! ( * ctx_data = ctx - > init ( & video_info , data ) ) )
return NULL ;
if ( ctx - > bind_hw_render )
ctx - > bind_hw_render ( * ctx_data ,
video_info . shared_context & & hw_render_ctx ) ;
return ctx ;
}
/**
* video_context_driver_init_first :
* @ data : Input data .
* @ ident : Identifier of graphics context driver to find .
* @ api : API of higher - level graphics API .
* @ major : Major version number of higher - level graphics API .
* @ minor : Minor version number of higher - level graphics API .
* @ hw_render_ctx : Request a graphics context driver capable of
* hardware rendering ?
*
* Finds first suitable graphics context driver and initializes .
*
* Returns : graphics context driver if found , otherwise NULL .
* */
const gfx_ctx_driver_t * video_context_driver_init_first ( void * data ,
const char * ident , enum gfx_ctx_api api , unsigned major ,
unsigned minor , bool hw_render_ctx , void * * ctx_data )
{
int i = find_video_context_driver_index ( ident ) ;
if ( i > = 0 )
{
const gfx_ctx_driver_t * ctx = video_context_driver_init ( data , gfx_ctx_drivers [ i ] , ident ,
api , major , minor , hw_render_ctx , ctx_data ) ;
if ( ctx )
{
video_context_data = * ctx_data ;
return ctx ;
}
}
for ( i = 0 ; gfx_ctx_drivers [ i ] ; i + + )
{
const gfx_ctx_driver_t * ctx =
video_context_driver_init ( data , gfx_ctx_drivers [ i ] , ident ,
api , major , minor , hw_render_ctx , ctx_data ) ;
if ( ctx )
{
video_context_data = * ctx_data ;
return ctx ;
}
}
return NULL ;
}
bool video_context_driver_init_image_buffer ( const video_info_t * data )
{
if (
current_video_context . image_buffer_init
& & current_video_context . image_buffer_init (
video_context_data , data ) )
return true ;
return false ;
}
bool video_context_driver_write_to_image_buffer ( gfx_ctx_image_t * img )
{
if (
current_video_context . image_buffer_write
& & current_video_context . image_buffer_write ( video_context_data ,
img - > frame , img - > width , img - > height , img - > pitch ,
img - > rgb32 , img - > index , img - > handle ) )
return true ;
return false ;
}
bool video_context_driver_get_video_output_prev ( void )
{
if ( ! current_video_context . get_video_output_prev )
return false ;
current_video_context . get_video_output_prev ( video_context_data ) ;
return true ;
}
bool video_context_driver_get_video_output_next ( void )
{
if ( ! current_video_context . get_video_output_next )
return false ;
current_video_context . get_video_output_next ( video_context_data ) ;
return true ;
}
void video_context_driver_make_current ( bool release )
{
if ( current_video_context . make_current )
current_video_context . make_current ( release ) ;
}
bool video_context_driver_translate_aspect ( gfx_ctx_aspect_t * aspect )
{
if ( ! video_context_data | | ! aspect )
return false ;
if ( ! current_video_context . translate_aspect )
return false ;
* aspect - > aspect = current_video_context . translate_aspect (
video_context_data , aspect - > width , aspect - > height ) ;
return true ;
}
void video_context_driver_free ( void )
{
if ( current_video_context . destroy )
current_video_context . destroy ( video_context_data ) ;
video_context_driver_destroy ( ) ;
video_context_data = NULL ;
}
bool video_context_driver_get_video_output_size ( gfx_ctx_size_t * size_data )
{
if ( ! size_data )
return false ;
if ( ! current_video_context . get_video_output_size )
return false ;
current_video_context . get_video_output_size ( video_context_data ,
size_data - > width , size_data - > height ) ;
return true ;
}
bool video_context_driver_swap_interval ( int * interval )
{
gfx_ctx_flags_t flags ;
int current_interval = * interval ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 15:10:22 +02:00
bool adaptive_vsync_enabled = video_driver_get_all_flags ( & flags , GFX_CTX_FLAGS_ADAPTIVE_VSYNC ) & & settings - > bools . video_adaptive_vsync ;
if ( ! current_video_context . swap_interval )
return false ;
if ( adaptive_vsync_enabled & & current_interval = = 1 )
current_interval = - 1 ;
current_video_context . swap_interval ( video_context_data , current_interval ) ;
return true ;
2019-06-17 12:49:21 +02:00
}
2019-03-07 19:17:54 -05:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_get_proc_address ( gfx_ctx_proc_address_t * proc )
2015-11-30 04:10:15 +01:00
{
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . get_proc_address )
return false ;
2015-06-12 12:42:44 -03:00
2019-06-17 15:10:22 +02:00
proc - > addr = current_video_context . get_proc_address ( proc - > sym ) ;
2019-06-17 12:49:21 +02:00
return true ;
}
2019-06-17 15:10:22 +02:00
bool video_context_driver_get_metrics ( gfx_ctx_metrics_t * metrics )
2017-05-11 09:11:46 +02:00
{
2019-06-17 15:10:22 +02:00
if (
current_video_context . get_metrics ( video_context_data ,
metrics - > type ,
metrics - > value ) )
return true ;
return false ;
}
bool video_context_driver_get_refresh_rate ( float * refresh_rate )
{
float refresh_holder = 0 ;
if ( ! current_video_context . get_refresh_rate | | ! refresh_rate )
2019-06-17 12:49:21 +02:00
return false ;
2019-06-17 15:10:22 +02:00
if ( ! video_context_data )
return false ;
if ( ! video_driver_crt_switching_active )
if ( refresh_rate )
* refresh_rate =
current_video_context . get_refresh_rate ( video_context_data ) ;
if ( video_driver_crt_switching_active )
{
if ( refresh_rate )
refresh_holder =
current_video_context . get_refresh_rate ( video_context_data ) ;
if ( refresh_holder ! = video_driver_core_hz ) /* Fix for incorrect interlace detsction -- HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/
* refresh_rate = video_driver_core_hz ;
}
2019-06-17 12:49:21 +02:00
return true ;
}
2017-05-11 09:11:46 +02:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_input_driver ( gfx_ctx_input_t * inp )
2017-05-11 09:11:46 +02:00
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
const char * joypad_name = settings - > arrays . input_joypad_driver ;
2017-05-11 09:11:46 +02:00
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . input_driver )
return false ;
current_video_context . input_driver (
video_context_data , joypad_name ,
inp - > input , inp - > input_data ) ;
2019-06-17 12:49:21 +02:00
return true ;
}
2015-11-30 19:30:05 +01:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_suppress_screensaver ( bool * bool_data )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( video_context_data
& & current_video_context . suppress_screensaver (
video_context_data , * bool_data ) )
return true ;
return false ;
}
2017-05-12 03:39:37 +02:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_get_ident ( gfx_ctx_ident_t * ident )
{
if ( ! ident )
return false ;
ident - > ident = current_video_context . ident ;
return true ;
2019-06-17 12:49:21 +02:00
}
2017-05-12 03:39:37 +02:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_set_video_mode ( gfx_ctx_mode_t * mode_info )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
video_frame_info_t video_info ;
if ( ! current_video_context . set_video_mode )
2019-06-17 12:49:21 +02:00
return false ;
2018-08-18 23:09:40 -04:00
2019-06-17 15:10:22 +02:00
video_driver_build_info ( & video_info ) ;
2018-08-18 23:09:40 -04:00
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . set_video_mode (
video_context_data , & video_info , mode_info - > width ,
mode_info - > height , mode_info - > fullscreen ) )
return false ;
2019-06-17 12:49:21 +02:00
return true ;
}
2017-09-08 06:08:05 +02:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_get_video_size ( gfx_ctx_mode_t * mode_info )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . get_video_size )
return false ;
current_video_context . get_video_size ( video_context_data ,
& mode_info - > width , & mode_info - > height ) ;
return true ;
2019-06-17 12:49:21 +02:00
}
2017-09-08 06:08:05 +02:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_show_mouse ( bool * bool_data )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . show_mouse )
return false ;
current_video_context . show_mouse ( video_context_data , * bool_data ) ;
2019-06-17 12:49:21 +02:00
return true ;
}
2017-05-11 09:11:46 +02:00
2019-06-17 15:10:22 +02:00
bool video_context_driver_get_flags ( gfx_ctx_flags_t * flags )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . get_flags )
return false ;
if ( deferred_video_context_driver_set_flags )
{
flags - > flags = deferred_flag_data . flags ;
deferred_video_context_driver_set_flags = false ;
return true ;
}
flags - > flags = current_video_context . get_flags ( video_context_data ) ;
2019-06-17 12:49:21 +02:00
return true ;
}
2019-03-06 12:24:35 +00:00
2019-06-17 15:10:22 +02:00
static bool video_driver_get_flags ( gfx_ctx_flags_t * flags )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( ! video_driver_poke | | ! video_driver_poke - > get_flags )
return false ;
flags - > flags = video_driver_poke - > get_flags ( video_driver_data ) ;
return true ;
2019-06-17 12:49:21 +02:00
}
2019-03-21 16:56:24 +00:00
2019-06-17 15:10:22 +02:00
bool video_driver_get_all_flags ( gfx_ctx_flags_t * flags , enum display_flags flag )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( ! flags )
return false ;
2019-05-17 17:19:13 +01:00
2019-06-17 15:10:22 +02:00
if ( video_driver_get_flags ( flags ) )
if ( BIT32_GET ( flags - > flags , flag ) )
return true ;
flags - > flags = 0 ;
if ( video_context_driver_get_flags ( flags ) )
if ( BIT32_GET ( flags - > flags , flag ) )
return true ;
2017-05-21 21:42:13 +02:00
2019-06-17 12:49:21 +02:00
return false ;
}
2019-06-17 15:10:22 +02:00
bool video_context_driver_set_flags ( gfx_ctx_flags_t * flags )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( ! flags )
2019-06-17 12:49:21 +02:00
return false ;
2019-06-17 15:10:22 +02:00
if ( ! current_video_context . set_flags )
{
deferred_flag_data . flags = flags - > flags ;
deferred_video_context_driver_set_flags = true ;
2019-06-17 12:49:21 +02:00
return false ;
2019-06-17 15:10:22 +02:00
}
current_video_context . set_flags ( video_context_data , flags - > flags ) ;
return true ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
enum gfx_ctx_api video_context_driver_get_api ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
enum gfx_ctx_api ctx_api = video_context_data ?
current_video_context . get_api ( video_context_data ) : GFX_CTX_NONE ;
if ( ctx_api = = GFX_CTX_NONE )
{
const char * video_driver = video_driver_get_ident ( ) ;
if ( string_is_equal ( video_driver , " d3d9 " ) )
return GFX_CTX_DIRECT3D9_API ;
else if ( string_is_equal ( video_driver , " d3d10 " ) )
return GFX_CTX_DIRECT3D10_API ;
else if ( string_is_equal ( video_driver , " d3d11 " ) )
return GFX_CTX_DIRECT3D11_API ;
else if ( string_is_equal ( video_driver , " d3d12 " ) )
return GFX_CTX_DIRECT3D12_API ;
else if ( string_is_equal ( video_driver , " gx2 " ) )
return GFX_CTX_GX2_API ;
else if ( string_is_equal ( video_driver , " gx " ) )
return GFX_CTX_GX_API ;
else if ( string_is_equal ( video_driver , " gl " ) )
return GFX_CTX_OPENGL_API ;
else if ( string_is_equal ( video_driver , " gl1 " ) )
return GFX_CTX_OPENGL_API ;
else if ( string_is_equal ( video_driver , " glcore " ) )
return GFX_CTX_OPENGL_API ;
else if ( string_is_equal ( video_driver , " vulkan " ) )
return GFX_CTX_VULKAN_API ;
else if ( string_is_equal ( video_driver , " metal " ) )
return GFX_CTX_METAL_API ;
return GFX_CTX_NONE ;
}
return ctx_api ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
bool video_driver_has_windowed ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
# if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE))
if ( video_driver_data & & current_video - > has_windowed )
return current_video - > has_windowed ( video_driver_data ) ;
else if ( video_context_data & & current_video_context . has_windowed )
return current_video_context . has_windowed ( video_context_data ) ;
# endif
return false ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
bool video_driver_cached_frame_has_valid_framebuffer ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( frame_cache_data )
return ( frame_cache_data = = RETRO_HW_FRAME_BUFFER_VALID ) ;
return false ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
bool video_shader_driver_get_current_shader ( video_shader_ctx_t * shader )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
void * video_driver = video_driver_get_ptr ( true ) ;
const video_poke_interface_t * video_poke = video_driver_get_poke ( ) ;
shader - > data = NULL ;
if ( ! video_poke | | ! video_driver | | ! video_poke - > get_current_shader )
return false ;
shader - > data = video_poke - > get_current_shader ( video_driver ) ;
return true ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
float video_driver_get_refresh_rate ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( video_driver_poke & & video_driver_poke - > get_refresh_rate )
return video_driver_poke - > get_refresh_rate ( video_driver_data ) ;
return 0.0f ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
bool video_driver_has_widgets ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
return current_video & & current_video - > menu_widgets_enabled
& & current_video - > menu_widgets_enabled ( video_driver_data ) ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
# endif
2019-06-17 12:49:21 +02:00
2019-06-17 15:10:22 +02:00
void video_driver_set_gpu_device_string ( const char * str )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
strlcpy ( video_driver_gpu_device_string , str , sizeof ( video_driver_gpu_device_string ) ) ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
const char * video_driver_get_gpu_device_string ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
return video_driver_gpu_device_string ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
void video_driver_set_gpu_api_version_string ( const char * str )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
strlcpy ( video_driver_gpu_api_version_string , str , sizeof ( video_driver_gpu_api_version_string ) ) ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
const char * video_driver_get_gpu_api_version_string ( void )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
return video_driver_gpu_api_version_string ;
2019-06-17 12:49:21 +02:00
}
2019-06-17 15:10:22 +02:00
/* string list stays owned by the caller and must be available at all times after the video driver is inited */
void video_driver_set_gpu_api_devices ( enum gfx_ctx_api api , struct string_list * list )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( gpu_map ) ; i + + )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( api = = gpu_map [ i ] . api )
{
gpu_map [ i ] . list = list ;
2019-06-17 12:49:21 +02:00
break ;
2019-06-17 15:10:22 +02:00
}
2019-06-17 12:49:21 +02:00
}
}
2019-06-17 15:10:22 +02:00
struct string_list * video_driver_get_gpu_api_devices ( enum gfx_ctx_api api )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( gpu_map ) ; i + + )
2019-06-17 12:49:21 +02:00
{
2019-06-17 15:10:22 +02:00
if ( api = = gpu_map [ i ] . api )
return gpu_map [ i ] . list ;
2019-06-17 12:49:21 +02:00
}
return NULL ;
}
2019-01-05 15:11:58 -05:00
2019-06-17 11:18:27 +02:00
/* BSV Movie */
2019-06-16 16:52:48 +02:00
struct bsv_state
{
bool movie_start_recording ;
bool movie_start_playback ;
bool movie_playback ;
bool eof_exit ;
bool movie_end ;
/* Movie playback/recording support. */
char movie_path [ PATH_MAX_LENGTH ] ;
/* Immediate playback/recording. */
char movie_start_path [ PATH_MAX_LENGTH ] ;
} ;
struct bsv_movie
{
intfstream_t * file ;
/* A ring buffer keeping track of positions
* in the file for each frame . */
size_t * frame_pos ;
size_t frame_mask ;
size_t frame_ptr ;
size_t min_file_pos ;
size_t state_size ;
uint8_t * state ;
bool playback ;
bool first_rewind ;
bool did_rewind ;
} ;
# define BSV_MAGIC 0x42535631
# define MAGIC_INDEX 0
# define SERIALIZER_INDEX 1
# define CRC_INDEX 2
# define STATE_SIZE_INDEX 3
typedef struct bsv_movie bsv_movie_t ;
static bsv_movie_t * bsv_movie_state_handle = NULL ;
static struct bsv_state bsv_movie_state ;
static bool bsv_movie_init_playback ( bsv_movie_t * handle , const char * path )
{
uint32_t state_size = 0 ;
uint32_t content_crc = 0 ;
uint32_t header [ 4 ] = { 0 } ;
intfstream_t * file = intfstream_open_file ( path ,
RETRO_VFS_FILE_ACCESS_READ ,
RETRO_VFS_FILE_ACCESS_HINT_NONE ) ;
if ( ! file )
{
RARCH_ERR ( " Could not open BSV file for playback, path : \" %s \" . \n " , path ) ;
return false ;
}
handle - > file = file ;
handle - > playback = true ;
intfstream_read ( handle - > file , header , sizeof ( uint32_t ) * 4 ) ;
/* Compatibility with old implementation that
* used incorrect documentation . */
if ( swap_if_little32 ( header [ MAGIC_INDEX ] ) ! = BSV_MAGIC
& & swap_if_big32 ( header [ MAGIC_INDEX ] ) ! = BSV_MAGIC )
{
RARCH_ERR ( " %s \n " , msg_hash_to_str ( MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE ) ) ;
return false ;
}
content_crc = content_get_crc ( ) ;
if ( content_crc ! = 0 )
if ( swap_if_big32 ( header [ CRC_INDEX ] ) ! = content_crc )
RARCH_WARN ( " %s. \n " , msg_hash_to_str ( MSG_CRC32_CHECKSUM_MISMATCH ) ) ;
state_size = swap_if_big32 ( header [ STATE_SIZE_INDEX ] ) ;
#if 0
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 0 ] ) ;
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 1 ] ) ;
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 2 ] ) ;
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 3 ] ) ;
# endif
if ( state_size )
{
retro_ctx_size_info_t info ;
retro_ctx_serialize_info_t serial_info ;
uint8_t * buf = ( uint8_t * ) malloc ( state_size ) ;
if ( ! buf )
return false ;
handle - > state = buf ;
handle - > state_size = state_size ;
if ( intfstream_read ( handle - > file ,
handle - > state , state_size ) ! = state_size )
{
RARCH_ERR ( " %s \n " , msg_hash_to_str ( MSG_COULD_NOT_READ_STATE_FROM_MOVIE ) ) ;
return false ;
}
core_serialize_size ( & info ) ;
if ( info . size = = state_size )
{
serial_info . data_const = handle - > state ;
serial_info . size = state_size ;
core_unserialize ( & serial_info ) ;
}
else
RARCH_WARN ( " %s \n " ,
msg_hash_to_str ( MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION ) ) ;
}
handle - > min_file_pos = sizeof ( header ) + state_size ;
return true ;
}
static bool bsv_movie_init_record ( bsv_movie_t * handle , const char * path )
{
retro_ctx_size_info_t info ;
uint32_t state_size = 0 ;
uint32_t content_crc = 0 ;
uint32_t header [ 4 ] = { 0 } ;
intfstream_t * file = intfstream_open_file ( path ,
RETRO_VFS_FILE_ACCESS_WRITE ,
RETRO_VFS_FILE_ACCESS_HINT_NONE ) ;
if ( ! file )
{
RARCH_ERR ( " Could not open BSV file for recording, path : \" %s \" . \n " , path ) ;
return false ;
}
handle - > file = file ;
content_crc = content_get_crc ( ) ;
/* This value is supposed to show up as
* BSV1 in a HEX editor , big - endian . */
header [ MAGIC_INDEX ] = swap_if_little32 ( BSV_MAGIC ) ;
header [ CRC_INDEX ] = swap_if_big32 ( content_crc ) ;
core_serialize_size ( & info ) ;
state_size = ( unsigned ) info . size ;
header [ STATE_SIZE_INDEX ] = swap_if_big32 ( state_size ) ;
#if 0
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 0 ] ) ;
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 1 ] ) ;
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 2 ] ) ;
RARCH_ERR ( " ----- debug %u ----- \n " , header [ 3 ] ) ;
# endif
intfstream_write ( handle - > file , header , 4 * sizeof ( uint32_t ) ) ;
handle - > min_file_pos = sizeof ( header ) + state_size ;
handle - > state_size = state_size ;
if ( state_size )
{
retro_ctx_serialize_info_t serial_info ;
handle - > state = ( uint8_t * ) malloc ( state_size ) ;
if ( ! handle - > state )
return false ;
serial_info . data = handle - > state ;
serial_info . size = state_size ;
core_serialize ( & serial_info ) ;
intfstream_write ( handle - > file ,
handle - > state , state_size ) ;
}
return true ;
}
static void bsv_movie_free ( bsv_movie_t * handle )
{
if ( ! handle )
return ;
intfstream_close ( handle - > file ) ;
free ( handle - > file ) ;
free ( handle - > state ) ;
free ( handle - > frame_pos ) ;
free ( handle ) ;
}
static bsv_movie_t * bsv_movie_init_internal ( const char * path ,
enum rarch_movie_type type )
{
size_t * frame_pos = NULL ;
bsv_movie_t * handle = ( bsv_movie_t * ) calloc ( 1 , sizeof ( * handle ) ) ;
if ( ! handle )
return NULL ;
if ( type = = RARCH_MOVIE_PLAYBACK )
{
if ( ! bsv_movie_init_playback ( handle , path ) )
goto error ;
}
else if ( ! bsv_movie_init_record ( handle , path ) )
goto error ;
/* Just pick something really large
* ~ 1 million frames rewind should do the trick . */
if ( ! ( frame_pos = ( size_t * ) calloc ( ( 1 < < 20 ) , sizeof ( size_t ) ) ) )
goto error ;
handle - > frame_pos = frame_pos ;
handle - > frame_pos [ 0 ] = handle - > min_file_pos ;
handle - > frame_mask = ( 1 < < 20 ) - 1 ;
return handle ;
error :
bsv_movie_free ( handle ) ;
return NULL ;
}
2019-06-17 02:22:49 +02:00
void bsv_movie_frame_rewind ( void )
2019-06-16 16:52:48 +02:00
{
2019-06-17 02:22:49 +02:00
bsv_movie_t * handle = bsv_movie_state_handle ;
if ( ! handle )
return ;
2019-06-16 16:52:48 +02:00
handle - > did_rewind = true ;
if ( ( handle - > frame_ptr < = 1 )
& & ( handle - > frame_pos [ 0 ] = = handle - > min_file_pos ) )
{
/* If we're at the beginning... */
handle - > frame_ptr = 0 ;
intfstream_seek ( handle - > file , ( int ) handle - > min_file_pos , SEEK_SET ) ;
}
else
{
/* First time rewind is performed, the old frame is simply replayed.
* However , playing back that frame caused us to read data , and push
* data to the ring buffer .
*
* Sucessively rewinding frames , we need to rewind past the read data ,
* plus another . */
handle - > frame_ptr = ( handle - > frame_ptr -
( handle - > first_rewind ? 1 : 2 ) ) & handle - > frame_mask ;
intfstream_seek ( handle - > file ,
( int ) handle - > frame_pos [ handle - > frame_ptr ] , SEEK_SET ) ;
}
if ( intfstream_tell ( handle - > file ) < = ( long ) handle - > min_file_pos )
{
/* We rewound past the beginning. */
if ( ! handle - > playback )
{
retro_ctx_serialize_info_t serial_info ;
/* If recording, we simply reset
* the starting point . Nice and easy . */
intfstream_seek ( handle - > file , 4 * sizeof ( uint32_t ) , SEEK_SET ) ;
serial_info . data = handle - > state ;
serial_info . size = handle - > state_size ;
core_serialize ( & serial_info ) ;
intfstream_write ( handle - > file , handle - > state , handle - > state_size ) ;
}
else
intfstream_seek ( handle - > file , ( int ) handle - > min_file_pos , SEEK_SET ) ;
}
}
static bool bsv_movie_init_handle ( const char * path ,
enum rarch_movie_type type )
{
bsv_movie_t * state = bsv_movie_init_internal ( path , type ) ;
if ( ! state )
return false ;
bsv_movie_state_handle = state ;
return true ;
}
bool bsv_movie_init ( void )
{
bool set_granularity = false ;
if ( bsv_movie_state . movie_start_playback )
{
2019-06-16 17:05:06 +02:00
if ( ! bsv_movie_init_handle ( bsv_movie_state . movie_start_path ,
RARCH_MOVIE_PLAYBACK ) )
2019-06-16 16:52:48 +02:00
{
RARCH_ERR ( " %s: \" %s \" . \n " ,
msg_hash_to_str ( MSG_FAILED_TO_LOAD_MOVIE_FILE ) ,
bsv_movie_state . movie_start_path ) ;
2019-06-16 17:05:06 +02:00
return false ;
2019-06-16 16:52:48 +02:00
}
bsv_movie_state . movie_playback = true ;
runloop_msg_queue_push ( msg_hash_to_str ( MSG_STARTING_MOVIE_PLAYBACK ) ,
2 , 180 , false ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_LOG ( " %s. \n " , msg_hash_to_str ( MSG_STARTING_MOVIE_PLAYBACK ) ) ;
set_granularity = true ;
}
else if ( bsv_movie_state . movie_start_recording )
{
2019-06-16 17:05:06 +02:00
if ( ! bsv_movie_init_handle ( bsv_movie_state . movie_start_path ,
RARCH_MOVIE_RECORD ) )
2019-06-16 16:52:48 +02:00
{
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAILED_TO_START_MOVIE_RECORD ) ,
1 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_ERR ( " %s. \n " ,
msg_hash_to_str ( MSG_FAILED_TO_START_MOVIE_RECORD ) ) ;
2019-06-16 17:05:06 +02:00
return false ;
2019-06-16 16:52:48 +02:00
}
2019-06-16 17:05:06 +02:00
{
char msg [ 8192 ] ;
snprintf ( msg , sizeof ( msg ) ,
" %s \" %s \" . " ,
msg_hash_to_str ( MSG_STARTING_MOVIE_RECORD_TO ) ,
bsv_movie_state . movie_start_path ) ;
runloop_msg_queue_push ( msg , 1 , 180 , true , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_LOG ( " %s \" %s \" . \n " ,
msg_hash_to_str ( MSG_STARTING_MOVIE_RECORD_TO ) ,
bsv_movie_state . movie_start_path ) ;
}
2019-06-16 16:52:48 +02:00
set_granularity = true ;
}
if ( set_granularity )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-16 16:52:48 +02:00
configuration_set_uint ( settings ,
settings - > uints . rewind_granularity , 1 ) ;
}
2019-06-16 17:05:06 +02:00
return true ;
2019-06-16 16:52:48 +02:00
}
2019-06-17 02:22:49 +02:00
# define bsv_movie_is_playback_on() (bsv_movie_state_handle && bsv_movie_state.movie_playback)
# define bsv_movie_is_playback_off() (bsv_movie_state_handle && !bsv_movie_state.movie_playback)
2019-06-16 16:52:48 +02:00
bool bsv_movie_get_input ( int16_t * bsv_data )
{
2019-06-17 02:22:49 +02:00
if ( ! bsv_movie_is_playback_on ( ) )
return false ;
2019-06-16 16:52:48 +02:00
if ( intfstream_read ( bsv_movie_state_handle - > file , bsv_data , 1 ) ! = 1 )
2019-06-17 02:22:49 +02:00
{
bsv_movie_state . movie_end = true ;
2019-06-16 16:52:48 +02:00
return false ;
2019-06-17 02:22:49 +02:00
}
2019-06-16 16:52:48 +02:00
* bsv_data = swap_if_big16 ( * bsv_data ) ;
return true ;
}
2019-06-17 02:22:49 +02:00
void bsv_movie_set_input ( int16_t * bsv_data )
2019-06-16 16:52:48 +02:00
{
2019-06-17 02:22:49 +02:00
if ( bsv_data & & bsv_movie_is_playback_off ( ) )
{
* bsv_data = swap_if_big16 ( * bsv_data ) ;
intfstream_write ( bsv_movie_state_handle - > file , bsv_data , 1 ) ;
}
2019-06-16 16:52:48 +02:00
}
void bsv_movie_set_path ( const char * path )
{
strlcpy ( bsv_movie_state . movie_path ,
path , sizeof ( bsv_movie_state . movie_path ) ) ;
}
void bsv_movie_deinit ( void )
{
if ( ! bsv_movie_state_handle )
return ;
bsv_movie_free ( bsv_movie_state_handle ) ;
bsv_movie_state_handle = NULL ;
}
static bool runloop_check_movie_init ( void )
{
char msg [ 16384 ] , path [ 8192 ] ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-16 16:52:48 +02:00
msg [ 0 ] = path [ 0 ] = ' \0 ' ;
configuration_set_uint ( settings , settings - > uints . rewind_granularity , 1 ) ;
if ( settings - > ints . state_slot > 0 )
snprintf ( path , sizeof ( path ) , " %s%d " ,
bsv_movie_state . movie_path ,
settings - > ints . state_slot ) ;
else
strlcpy ( path , bsv_movie_state . movie_path , sizeof ( path ) ) ;
strlcat ( path ,
file_path_str ( FILE_PATH_BSV_EXTENSION ) ,
sizeof ( path ) ) ;
snprintf ( msg , sizeof ( msg ) , " %s \" %s \" . " ,
msg_hash_to_str ( MSG_STARTING_MOVIE_RECORD_TO ) ,
path ) ;
bsv_movie_init_handle ( path , RARCH_MOVIE_RECORD ) ;
if ( ! bsv_movie_state_handle )
{
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAILED_TO_START_MOVIE_RECORD ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_ERR ( " %s \n " ,
msg_hash_to_str ( MSG_FAILED_TO_START_MOVIE_RECORD ) ) ;
return false ;
}
runloop_msg_queue_push ( msg , 2 , 180 , true , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_LOG ( " %s \" %s \" . \n " ,
msg_hash_to_str ( MSG_STARTING_MOVIE_RECORD_TO ) ,
path ) ;
return true ;
}
bool bsv_movie_check ( void )
{
if ( ! bsv_movie_state_handle )
return runloop_check_movie_init ( ) ;
if ( bsv_movie_state . movie_playback )
{
2019-06-16 17:05:06 +02:00
/* Checks if movie is being played back. */
2019-06-16 16:52:48 +02:00
if ( ! bsv_movie_state . movie_end )
return false ;
2019-06-16 17:05:06 +02:00
runloop_msg_queue_push (
msg_hash_to_str ( MSG_MOVIE_PLAYBACK_ENDED ) , 2 , 180 , false ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_LOG ( " %s \n " , msg_hash_to_str ( MSG_MOVIE_PLAYBACK_ENDED ) ) ;
command_event ( CMD_EVENT_BSV_MOVIE_DEINIT , NULL ) ;
bsv_movie_state . movie_end = false ;
bsv_movie_state . movie_playback = false ;
return true ;
2019-06-16 16:52:48 +02:00
}
2019-06-16 17:05:06 +02:00
/* Checks if movie is being recorded. */
if ( ! bsv_movie_state_handle )
return false ;
runloop_msg_queue_push (
msg_hash_to_str ( MSG_MOVIE_RECORD_STOPPED ) , 2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
RARCH_LOG ( " %s \n " , msg_hash_to_str ( MSG_MOVIE_RECORD_STOPPED ) ) ;
command_event ( CMD_EVENT_BSV_MOVIE_DEINIT , NULL ) ;
return true ;
2019-06-16 16:52:48 +02:00
}
2019-06-17 11:57:46 +02:00
/* Location */
static const location_driver_t * location_drivers [ ] = {
# ifdef ANDROID
& location_android ,
# endif
& location_null ,
NULL ,
} ;
static const location_driver_t * location_driver ;
static void * location_data ;
static bool location_driver_active = false ;
/**
* location_driver_find_handle :
* @ idx : index of driver to get handle to .
*
* Returns : handle to location driver at index . Can be NULL
* if nothing found .
* */
const void * location_driver_find_handle ( int idx )
{
const void * drv = location_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv ;
}
/**
* location_driver_find_ident :
* @ idx : index of driver to get handle to .
*
* Returns : Human - readable identifier of location driver at index . Can be NULL
* if nothing found .
* */
const char * location_driver_find_ident ( int idx )
{
const location_driver_t * drv = location_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv - > ident ;
}
/**
* config_get_location_driver_options :
*
* Get an enumerated list of all location driver names ,
* separated by ' | ' .
*
* Returns : string listing of all location driver names ,
* separated by ' | ' .
* */
const char * config_get_location_driver_options ( void )
{
return char_list_new_special ( STRING_LIST_LOCATION_DRIVERS , NULL ) ;
}
static void find_location_driver ( void )
{
int i ;
driver_ctx_info_t drv ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 11:57:46 +02:00
drv . label = " location_driver " ;
drv . s = settings - > arrays . location_driver ;
driver_ctl ( RARCH_DRIVER_CTL_FIND_INDEX , & drv ) ;
i = ( int ) drv . len ;
if ( i > = 0 )
location_driver = ( const location_driver_t * ) location_driver_find_handle ( i ) ;
else
{
if ( verbosity_is_enabled ( ) )
{
unsigned d ;
RARCH_ERR ( " Couldn't find any location driver named \" %s \" \n " ,
settings - > arrays . location_driver ) ;
RARCH_LOG_OUTPUT ( " Available location drivers are: \n " ) ;
for ( d = 0 ; location_driver_find_handle ( d ) ; d + + )
RARCH_LOG_OUTPUT ( " \t %s \n " , location_driver_find_ident ( d ) ) ;
RARCH_WARN ( " Going to default to first location driver... \n " ) ;
}
location_driver = ( const location_driver_t * ) location_driver_find_handle ( 0 ) ;
if ( ! location_driver )
retroarch_fail ( 1 , " find_location_driver() " ) ;
}
}
/**
* driver_location_start :
*
* Starts location driver interface . .
* Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE .
*
* Returns : true ( 1 ) if successful , otherwise false ( 0 ) .
* */
bool driver_location_start ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 11:57:46 +02:00
if ( location_driver & & location_data & & location_driver - > start )
{
if ( settings - > bools . location_allow )
return location_driver - > start ( location_data ) ;
runloop_msg_queue_push ( " Location is explicitly disabled. \n " , 1 , 180 , true , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
return false ;
}
/**
* driver_location_stop :
*
* Stops location driver interface . .
* Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE .
*
* Returns : true ( 1 ) if successful , otherwise false ( 0 ) .
* */
void driver_location_stop ( void )
{
if ( location_driver & & location_driver - > stop & & location_data )
location_driver - > stop ( location_data ) ;
}
/**
* driver_location_set_interval :
* @ interval_msecs : Interval time in milliseconds .
* @ interval_distance : Distance at which to update .
*
* Sets interval update time for location driver interface .
* Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE .
* */
void driver_location_set_interval ( unsigned interval_msecs ,
unsigned interval_distance )
{
if ( location_driver & & location_driver - > set_interval
& & location_data )
location_driver - > set_interval ( location_data ,
interval_msecs , interval_distance ) ;
}
/**
* driver_location_get_position :
* @ lat : Latitude of current position .
* @ lon : Longitude of current position .
* @ horiz_accuracy : Horizontal accuracy .
* @ vert_accuracy : Vertical accuracy .
*
* Gets current positioning information from
* location driver interface .
* Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE .
*
* Returns : bool ( 1 ) if successful , otherwise false ( 0 ) .
* */
bool driver_location_get_position ( double * lat , double * lon ,
double * horiz_accuracy , double * vert_accuracy )
{
if ( location_driver & & location_driver - > get_position
& & location_data )
return location_driver - > get_position ( location_data ,
lat , lon , horiz_accuracy , vert_accuracy ) ;
* lat = 0.0 ;
* lon = 0.0 ;
* horiz_accuracy = 0.0 ;
* vert_accuracy = 0.0 ;
return false ;
}
static void init_location ( void )
{
rarch_system_info_t * system = & runloop_system ;
/* Resource leaks will follow if location interface is initialized twice. */
if ( location_data )
return ;
find_location_driver ( ) ;
location_data = location_driver - > init ( ) ;
if ( ! location_data )
{
RARCH_ERR ( " Failed to initialize location driver. Will continue without location. \n " ) ;
rarch_ctl ( RARCH_CTL_LOCATION_UNSET_ACTIVE , NULL ) ;
}
if ( system - > location_cb . initialized )
system - > location_cb . initialized ( ) ;
}
static void uninit_location ( void )
{
rarch_system_info_t * system = & runloop_system ;
if ( location_data & & location_driver )
{
if ( system - > location_cb . deinitialized )
system - > location_cb . deinitialized ( ) ;
if ( location_driver - > free )
location_driver - > free ( location_data ) ;
}
location_data = NULL ;
}
2019-06-17 11:18:27 +02:00
/* Camera */
static const camera_driver_t * camera_drivers [ ] = {
# ifdef HAVE_V4L2
& camera_v4l2 ,
# endif
# ifdef EMSCRIPTEN
& camera_rwebcam ,
# endif
# ifdef ANDROID
& camera_android ,
# endif
& camera_null ,
NULL ,
} ;
static struct retro_camera_callback camera_cb ;
static const camera_driver_t * camera_driver = NULL ;
static void * camera_data = NULL ;
static bool camera_driver_active = false ;
/**
* camera_driver_find_handle :
* @ idx : index of driver to get handle to .
*
* Returns : handle to camera driver at index . Can be NULL
* if nothing found .
* */
const void * camera_driver_find_handle ( int idx )
{
const void * drv = camera_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv ;
}
/**
* camera_driver_find_ident :
* @ idx : index of driver to get handle to .
*
* Returns : Human - readable identifier of camera driver at index . Can be NULL
* if nothing found .
* */
const char * camera_driver_find_ident ( int idx )
{
const camera_driver_t * drv = camera_drivers [ idx ] ;
if ( ! drv )
return NULL ;
return drv - > ident ;
}
/**
* config_get_camera_driver_options :
*
* Get an enumerated list of all camera driver names ,
* separated by ' | ' .
*
* Returns : string listing of all camera driver names ,
* separated by ' | ' .
* */
const char * config_get_camera_driver_options ( void )
{
return char_list_new_special ( STRING_LIST_CAMERA_DRIVERS , NULL ) ;
}
2019-06-17 11:29:05 +02:00
bool driver_camera_start ( void )
2019-06-17 11:18:27 +02:00
{
2019-06-17 11:29:05 +02:00
if ( camera_driver & & camera_data & & camera_driver - > start )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 11:29:05 +02:00
if ( settings - > bools . camera_allow )
return camera_driver - > start ( camera_data ) ;
runloop_msg_queue_push (
" Camera is explicitly disabled. \n " , 1 , 180 , false ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
return true ;
2019-06-17 11:18:27 +02:00
}
2019-06-17 11:29:05 +02:00
void driver_camera_stop ( void )
2019-06-17 11:18:27 +02:00
{
2019-06-17 11:29:05 +02:00
if ( camera_driver
& & camera_driver - > stop
& & camera_data )
camera_driver - > stop ( camera_data ) ;
2019-06-17 11:18:27 +02:00
}
2019-06-17 11:29:05 +02:00
static void camera_driver_find_driver ( void )
2019-06-17 11:18:27 +02:00
{
2019-06-17 11:29:05 +02:00
int i ;
driver_ctx_info_t drv ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-17 11:18:27 +02:00
2019-06-17 11:29:05 +02:00
drv . label = " camera_driver " ;
drv . s = settings - > arrays . camera_driver ;
2019-06-17 11:18:27 +02:00
2019-06-17 11:29:05 +02:00
driver_ctl ( RARCH_DRIVER_CTL_FIND_INDEX , & drv ) ;
2019-06-17 11:18:27 +02:00
2019-06-17 11:29:05 +02:00
i = ( int ) drv . len ;
2019-06-17 11:18:27 +02:00
2019-06-17 11:29:05 +02:00
if ( i > = 0 )
camera_driver = ( const camera_driver_t * ) camera_driver_find_handle ( i ) ;
else
{
if ( verbosity_is_enabled ( ) )
{
unsigned d ;
RARCH_ERR ( " Couldn't find any camera driver named \" %s \" \n " ,
settings - > arrays . camera_driver ) ;
RARCH_LOG_OUTPUT ( " Available camera drivers are: \n " ) ;
for ( d = 0 ; camera_driver_find_handle ( d ) ; d + + )
RARCH_LOG_OUTPUT ( " \t %s \n " , camera_driver_find_ident ( d ) ) ;
RARCH_WARN ( " Going to default to first camera driver... \n " ) ;
}
2019-06-17 11:18:27 +02:00
2019-06-17 11:29:05 +02:00
camera_driver = ( const camera_driver_t * ) camera_driver_find_handle ( 0 ) ;
2019-06-17 11:18:27 +02:00
2019-06-17 11:29:05 +02:00
if ( ! camera_driver )
retroarch_fail ( 1 , " find_camera_driver() " ) ;
}
}
2019-06-17 11:18:27 +02:00
/* Drivers */
2019-02-27 16:47:39 +01:00
/**
* find_driver_nonempty :
* @ label : string of driver type to be found .
* @ i : index of driver .
* @ str : identifier name of the found driver
* gets written to this string .
* @ len : size of @ str .
*
* Find driver based on @ label .
*
* Returns : NULL if no driver based on @ label found , otherwise
* pointer to driver .
* */
static const void * find_driver_nonempty ( const char * label , int i ,
char * s , size_t len )
{
2019-04-29 04:04:33 +02:00
const void * drv = NULL ;
2019-02-27 16:47:39 +01:00
2019-04-29 04:04:33 +02:00
if ( string_is_equal ( label , " camera_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = camera_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , camera_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " location_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = location_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , location_driver_find_ident ( i ) , len ) ;
}
# ifdef HAVE_MENU
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " menu_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = menu_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , menu_driver_find_ident ( i ) , len ) ;
}
# endif
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " input_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = input_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , input_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " input_joypad_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = joypad_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , joypad_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " video_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = video_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , video_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " audio_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = audio_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , audio_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " record_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = record_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , record_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " midi_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = midi_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , midi_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " audio_resampler_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = audio_resampler_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , audio_resampler_driver_find_ident ( i ) , len ) ;
}
2019-04-29 04:04:33 +02:00
else if ( string_is_equal ( label , " wifi_driver " ) )
2019-02-27 16:47:39 +01:00
{
drv = wifi_driver_find_handle ( i ) ;
if ( drv )
strlcpy ( s , wifi_driver_find_ident ( i ) , len ) ;
}
return drv ;
}
/**
* driver_find_index :
* @ label : string of driver type to be found .
* @ drv : identifier of driver to be found .
*
* Find index of the driver , based on @ label .
*
* Returns : - 1 if no driver based on @ label and @ drv found , otherwise
* index number of the driver found in the array .
* */
static int driver_find_index ( const char * label , const char * drv )
{
unsigned i ;
char str [ 256 ] ;
str [ 0 ] = ' \0 ' ;
for ( i = 0 ;
find_driver_nonempty ( label , i , str , sizeof ( str ) ) ! = NULL ; i + + )
{
if ( string_is_empty ( str ) )
break ;
if ( string_is_equal_noncase ( drv , str ) )
return i ;
}
return - 1 ;
}
static bool driver_find_first ( const char * label , char * s , size_t len )
{
find_driver_nonempty ( label , 0 , s , len ) ;
return true ;
}
/**
* driver_find_last :
* @ label : string of driver type to be found .
* @ s : identifier of driver to be found .
* @ len : size of @ s .
*
* Find last driver in driver array .
* */
static bool driver_find_last ( const char * label , char * s , size_t len )
{
unsigned i ;
for ( i = 0 ;
find_driver_nonempty ( label , i , s , len ) ! = NULL ; i + + )
{ }
if ( i )
find_driver_nonempty ( label , i - 1 , s , len ) ;
else
driver_find_first ( label , s , len ) ;
return true ;
}
/**
* driver_find_prev :
* @ label : string of driver type to be found .
* @ s : identifier of driver to be found .
* @ len : size of @ s .
*
* Find previous driver in driver array .
* */
static bool driver_find_prev ( const char * label , char * s , size_t len )
{
int i = driver_find_index ( label , s ) ;
if ( i > 0 )
{
find_driver_nonempty ( label , i - 1 , s , len ) ;
return true ;
}
RARCH_WARN (
" Couldn't find any previous driver (current one: \" %s \" ). \n " , s ) ;
return false ;
}
/**
* driver_find_next :
* @ label : string of driver type to be found .
* @ s : identifier of driver to be found .
* @ len : size of @ s .
*
* Find next driver in driver array .
* */
bool driver_find_next ( const char * label , char * s , size_t len )
{
int i = driver_find_index ( label , s ) ;
if ( i > = 0 & & string_is_not_equal ( s , " null " ) )
{
find_driver_nonempty ( label , i + 1 , s , len ) ;
return true ;
}
RARCH_WARN ( " %s (current one: \" %s \" ). \n " ,
msg_hash_to_str ( MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER ) ,
s ) ;
return false ;
}
static void driver_adjust_system_rates ( void )
{
audio_driver_monitor_adjust_system_rates ( ) ;
video_driver_monitor_adjust_system_rates ( ) ;
if ( ! video_driver_get_ptr ( false ) )
return ;
if ( runloop_force_nonblock )
command_event ( CMD_EVENT_VIDEO_SET_NONBLOCKING_STATE , NULL ) ;
else
driver_set_nonblock_state ( ) ;
}
/**
* driver_set_nonblock_state :
*
* Sets audio and video drivers to nonblock state ( if enabled ) .
*
* If nonblock state is false , sets
* blocking state for both audio and video drivers instead .
* */
void driver_set_nonblock_state ( void )
{
bool enable = input_driver_is_nonblock_state ( ) ;
/* Only apply non-block-state for video if we're using vsync. */
if ( video_driver_is_active ( ) & & video_driver_get_ptr ( false ) )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-02-27 16:47:39 +01:00
bool video_nonblock = enable ;
if ( ! settings - > bools . video_vsync | | runloop_force_nonblock )
video_nonblock = true ;
video_driver_set_nonblock_state ( video_nonblock ) ;
}
audio_driver_set_nonblocking_state ( enable ) ;
}
/**
* driver_update_system_av_info :
* @ data : pointer to new A / V info
*
* Update the system Audio / Video information .
* Will reinitialize audio / video drivers .
* Used by RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO .
*
* Returns : true ( 1 ) if successful , otherwise false ( 0 ) .
* */
2019-06-17 16:58:43 +02:00
static bool driver_update_system_av_info (
const struct retro_system_av_info * info )
2019-02-27 16:47:39 +01:00
{
2019-06-17 16:58:43 +02:00
struct retro_system_av_info
* av_info = video_viewport_get_system_av_info ( ) ;
settings_t * settings = configuration_settings ;
2019-02-27 16:47:39 +01:00
memcpy ( av_info , info , sizeof ( * av_info ) ) ;
command_event ( CMD_EVENT_REINIT , NULL ) ;
/* Cannot continue recording with different parameters.
* Take the easiest route out and just restart the recording . */
2019-06-17 16:23:46 +02:00
if ( recording_data )
2019-02-27 16:47:39 +01:00
{
runloop_msg_queue_push (
msg_hash_to_str ( MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT ) ,
2 , 180 , false ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
command_event ( CMD_EVENT_RECORD_DEINIT , NULL ) ;
command_event ( CMD_EVENT_RECORD_INIT , NULL ) ;
}
/* Hide mouse cursor in fullscreen after
* a RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO call . */
if ( settings - > bools . video_fullscreen )
video_driver_hide_mouse ( ) ;
return true ;
}
2019-06-17 12:49:21 +02:00
bool audio_driver_new_devices_list ( void )
{
if ( ! current_audio | | ! current_audio - > device_list_new
| | ! audio_driver_context_audio_data )
return false ;
audio_driver_devices_list = ( struct string_list * )
current_audio - > device_list_new ( audio_driver_context_audio_data ) ;
if ( ! audio_driver_devices_list )
return false ;
return true ;
}
2019-02-27 16:47:39 +01:00
/**
* drivers_init :
* @ flags : Bitmask of drivers to initialize .
*
* Initializes drivers .
* @ flags determines which drivers get initialized .
* */
void drivers_init ( int flags )
{
bool video_is_threaded = false ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-02-27 16:47:39 +01:00
# ifdef HAVE_MENU
/* By default, we want the menu to persist through driver reinits. */
menu_driver_ctl ( RARCH_MENU_CTL_SET_OWN_DRIVER , NULL ) ;
# endif
if ( flags & ( DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK ) )
driver_adjust_system_rates ( ) ;
2019-02-27 17:02:33 +01:00
/* Initialize video driver */
2019-02-27 16:47:39 +01:00
if ( flags & DRIVER_VIDEO_MASK )
{
struct retro_hw_render_callback * hwr =
2019-06-17 16:58:43 +02:00
video_driver_get_hw_context_internal ( ) ;
2019-02-27 16:47:39 +01:00
video_driver_monitor_reset ( ) ;
video_driver_init ( & video_is_threaded ) ;
if ( ! video_driver_is_video_cache_context_ack ( )
& & hwr - > context_reset )
hwr - > context_reset ( ) ;
video_driver_unset_video_cache_context_ack ( ) ;
runloop_frame_time_last = 0 ;
}
2019-02-27 17:02:33 +01:00
/* Initialize audio driver */
2019-02-27 16:47:39 +01:00
if ( flags & DRIVER_AUDIO_MASK )
{
2019-06-17 12:49:21 +02:00
audio_driver_init_internal ( audio_callback . callback ! = NULL ) ;
2019-02-27 16:47:39 +01:00
audio_driver_new_devices_list ( ) ;
}
2019-02-27 17:02:33 +01:00
if ( flags & DRIVER_CAMERA_MASK )
{
/* Only initialize camera driver if we're ever going to use it. */
2019-06-17 11:29:05 +02:00
if ( camera_driver_active )
{
/* Resource leaks will follow if camera is initialized twice. */
if ( ! camera_data )
{
camera_driver_find_driver ( ) ;
if ( camera_driver )
{
camera_data = camera_driver - > init (
* settings - > arrays . camera_device ?
settings - > arrays . camera_device : NULL ,
camera_cb . caps ,
settings - > uints . camera_width ?
settings - > uints . camera_width : camera_cb . width ,
settings - > uints . camera_height ?
settings - > uints . camera_height : camera_cb . height ) ;
if ( ! camera_data )
{
RARCH_ERR ( " Failed to initialize camera driver. Will continue without camera. \n " ) ;
2019-06-17 11:38:28 +02:00
rarch_ctl ( RARCH_CTL_CAMERA_UNSET_ACTIVE , NULL ) ;
2019-06-17 11:29:05 +02:00
}
if ( camera_cb . initialized )
camera_cb . initialized ( ) ;
}
}
}
2019-02-27 17:02:33 +01:00
}
2019-02-27 16:47:39 +01:00
2019-02-27 17:02:33 +01:00
if ( flags & DRIVER_LOCATION_MASK )
{
/* Only initialize location driver if we're ever going to use it. */
2019-06-17 11:57:46 +02:00
if ( location_driver_active )
2019-02-27 17:02:33 +01:00
init_location ( ) ;
}
2019-02-27 16:47:39 +01:00
core_info_init_current_core ( ) ;
# ifdef HAVE_MENU
# ifdef HAVE_MENU_WIDGETS
2019-05-03 21:25:20 +02:00
if ( settings - > bools . menu_enable_widgets
& & video_driver_has_widgets ( ) )
2019-02-27 16:47:39 +01:00
{
menu_widgets_init ( video_is_threaded ) ;
menu_widgets_context_reset ( video_is_threaded ) ;
}
# endif
if ( flags & DRIVER_VIDEO_MASK )
{
2019-02-27 17:02:33 +01:00
/* Initialize menu driver */
2019-02-27 16:47:39 +01:00
if ( flags & DRIVER_MENU_MASK )
menu_driver_init ( video_is_threaded ) ;
}
# else
/* Qt uses core info, even if the menu is disabled */
command_event ( CMD_EVENT_CORE_INFO_INIT , NULL ) ;
command_event ( CMD_EVENT_LOAD_CORE_PERSIST , NULL ) ;
# endif
if ( flags & ( DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK ) )
{
/* Keep non-throttled state as good as possible. */
if ( input_driver_is_nonblock_state ( ) )
driver_set_nonblock_state ( ) ;
}
2019-02-27 17:02:33 +01:00
/* Initialize LED driver */
2019-02-27 16:47:39 +01:00
if ( flags & DRIVER_LED_MASK )
led_driver_init ( ) ;
2019-02-27 17:02:33 +01:00
/* Initialize MIDI driver */
2019-02-27 16:47:39 +01:00
if ( flags & DRIVER_MIDI_MASK )
midi_driver_init ( ) ;
}
/**
* uninit_drivers :
* @ flags : Bitmask of drivers to deinitialize .
*
* Deinitializes drivers .
*
*
* @ flags determines which drivers get deinitialized .
* */
/**
* Driver ownership - set this to true if the platform in question needs to ' own '
* the respective handle and therefore skip regular RetroArch
* driver teardown / reiniting procedure .
*
* If to true , the ' free ' function will get skipped . It is
* then up to the driver implementation to properly handle
* ' reiniting ' inside the ' init ' function and make sure it
* returns the existing handle instead of allocating and
* returning a pointer to a new handle .
*
* Typically , if a driver intends to make use of this , it should
* set this to true at the end of its ' init ' function .
* */
void driver_uninit ( int flags )
{
core_info_deinit_list ( ) ;
core_info_free_current_core ( ) ;
# ifdef HAVE_MENU
if ( flags & DRIVER_MENU_MASK )
{
2019-04-08 13:35:35 +01:00
# if defined(HAVE_MENU_WIDGETS)
/* This absolutely has to be done before video_driver_free()
* is called / completes , otherwise certain menu drivers
* ( e . g . Vulkan ) will segfault */
menu_widgets_context_destroy ( ) ;
menu_widgets_free ( ) ;
# endif
2019-02-27 16:47:39 +01:00
menu_driver_ctl ( RARCH_MENU_CTL_DEINIT , NULL ) ;
menu_driver_free ( ) ;
}
# endif
2019-02-27 17:02:33 +01:00
if ( ( flags & DRIVER_LOCATION_MASK ) )
2019-06-17 11:57:46 +02:00
uninit_location ( ) ;
2019-02-27 16:47:39 +01:00
2019-02-27 17:02:33 +01:00
if ( ( flags & DRIVER_CAMERA_MASK ) )
2019-06-17 11:29:05 +02:00
{
if ( camera_data & & camera_driver )
{
if ( camera_cb . deinitialized )
camera_cb . deinitialized ( ) ;
if ( camera_driver - > free )
camera_driver - > free ( camera_data ) ;
}
camera_data = NULL ;
}
2019-02-27 16:47:39 +01:00
2019-02-27 17:02:33 +01:00
if ( ( flags & DRIVER_WIFI_MASK ) )
2019-02-27 16:47:39 +01:00
wifi_driver_ctl ( RARCH_WIFI_CTL_DEINIT , NULL ) ;
if ( flags & DRIVER_LED )
led_driver_free ( ) ;
if ( flags & DRIVERS_VIDEO_INPUT )
video_driver_free ( ) ;
if ( flags & DRIVER_AUDIO_MASK )
audio_driver_deinit ( ) ;
2019-02-27 17:09:15 +01:00
if ( ( flags & DRIVER_VIDEO_MASK ) )
2019-02-27 16:47:39 +01:00
video_driver_destroy_data ( ) ;
2019-02-27 17:17:34 +01:00
if ( ( flags & DRIVER_INPUT_MASK ) )
2019-02-27 16:47:39 +01:00
input_driver_destroy_data ( ) ;
2019-02-27 17:09:15 +01:00
if ( ( flags & DRIVER_AUDIO_MASK ) )
2019-06-17 13:06:56 +02:00
audio_driver_context_audio_data = NULL ;
2019-02-27 16:47:39 +01:00
if ( flags & DRIVER_MIDI_MASK )
midi_driver_free ( ) ;
}
bool driver_ctl ( enum driver_ctl_state state , void * data )
{
switch ( state )
{
case RARCH_DRIVER_CTL_DEINIT :
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
/* Tear down menu widgets no matter what
* in case the handle is lost in the threaded
* video driver in the meantime
* ( breaking video_driver_has_widgets ) */
menu_widgets_context_destroy ( ) ;
menu_widgets_free ( ) ;
# endif
video_driver_destroy ( ) ;
audio_driver_destroy ( ) ;
input_driver_destroy ( ) ;
# ifdef HAVE_MENU
menu_driver_destroy ( ) ;
# endif
2019-06-17 11:57:46 +02:00
location_driver_active = false ;
location_driver = NULL ;
2019-06-17 11:29:05 +02:00
/* Camera */
camera_driver_active = false ;
camera_driver = NULL ;
camera_data = NULL ;
2019-02-27 16:47:39 +01:00
wifi_driver_ctl ( RARCH_WIFI_CTL_DESTROY , NULL ) ;
core_uninit_libretro_callbacks ( ) ;
break ;
case RARCH_DRIVER_CTL_SET_REFRESH_RATE :
{
float * hz = ( float * ) data ;
video_monitor_set_refresh_rate ( * hz ) ;
audio_driver_monitor_set_rate ( ) ;
driver_adjust_system_rates ( ) ;
}
break ;
case RARCH_DRIVER_CTL_UPDATE_SYSTEM_AV_INFO :
{
const struct retro_system_av_info * * info = ( const struct retro_system_av_info * * ) data ;
if ( info )
return driver_update_system_av_info ( * info ) ;
}
return false ;
case RARCH_DRIVER_CTL_FIND_FIRST :
{
driver_ctx_info_t * drv = ( driver_ctx_info_t * ) data ;
if ( ! drv )
return false ;
return driver_find_first ( drv - > label , drv - > s , drv - > len ) ;
}
case RARCH_DRIVER_CTL_FIND_LAST :
{
driver_ctx_info_t * drv = ( driver_ctx_info_t * ) data ;
if ( ! drv )
return false ;
return driver_find_last ( drv - > label , drv - > s , drv - > len ) ;
}
case RARCH_DRIVER_CTL_FIND_PREV :
{
driver_ctx_info_t * drv = ( driver_ctx_info_t * ) data ;
if ( ! drv )
return false ;
return driver_find_prev ( drv - > label , drv - > s , drv - > len ) ;
}
case RARCH_DRIVER_CTL_FIND_NEXT :
{
driver_ctx_info_t * drv = ( driver_ctx_info_t * ) data ;
if ( ! drv )
return false ;
return driver_find_next ( drv - > label , drv - > s , drv - > len ) ;
}
case RARCH_DRIVER_CTL_FIND_INDEX :
{
driver_ctx_info_t * drv = ( driver_ctx_info_t * ) data ;
if ( ! drv )
return false ;
drv - > len = driver_find_index ( drv - > label , drv - > s ) ;
}
break ;
case RARCH_DRIVER_CTL_NONE :
default :
break ;
}
return true ;
}
2019-02-12 00:32:01 -05:00
void rarch_core_runtime_tick ( void )
{
struct retro_system_av_info * av_info = video_viewport_get_system_av_info ( ) ;
if ( av_info & & av_info - > timing . fps )
2019-03-04 15:30:12 +00:00
{
2019-05-31 16:38:17 +02:00
retro_time_t frame_time = ( 1.0 / av_info - > timing . fps ) * 1000000 ;
2019-03-04 15:30:12 +00:00
/* Account for slow motion */
if ( runloop_slowmotion )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
frame_time = ( retro_time_t ) ( ( double )
frame_time * settings - > floats . slowmotion_ratio ) ;
2019-03-04 15:30:12 +00:00
}
/* Account for fast forward */
else 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 = cpu_features_get_time_usec ( ) ;
if ( current_usec - libretro_core_runtime_last < frame_time )
frame_time = current_usec - libretro_core_runtime_last ;
libretro_core_runtime_last = current_usec ;
}
libretro_core_runtime_usec + = frame_time ;
}
2019-02-12 00:32:01 -05:00
}
2019-03-07 12:28:21 +00:00
static void update_runtime_log ( bool log_per_core )
{
/* Initialise runtime log file */
2019-04-21 23:42:21 +02:00
runtime_log_t * runtime_log = runtime_log_init ( runtime_content_path , runtime_core_path , log_per_core ) ;
2019-03-07 12:28:21 +00:00
2019-04-21 23:42:21 +02:00
if ( ! runtime_log )
return ;
2019-03-07 12:28:21 +00:00
2019-04-21 23:42:21 +02:00
/* Add additional runtime */
runtime_log_add_runtime_usec ( runtime_log , libretro_core_runtime_usec ) ;
2019-03-07 12:28:21 +00:00
2019-04-21 23:42:21 +02:00
/* Update 'last played' entry */
runtime_log_set_last_played_now ( runtime_log ) ;
/* Save runtime log file */
runtime_log_save ( runtime_log ) ;
/* Clean up */
free ( runtime_log ) ;
2019-02-12 00:32:01 -05:00
}
2017-05-11 09:20:35 +02:00
2017-05-20 11:34:51 +02:00
static void retroarch_override_setting_free_state ( void )
{
2017-09-09 00:20:39 +02:00
unsigned i ;
2017-05-20 11:34:51 +02:00
for ( i = 0 ; i < RARCH_OVERRIDE_SETTING_LAST ; i + + )
{
if ( i = = RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE )
{
2017-09-09 00:20:39 +02:00
unsigned j ;
2017-05-20 11:34:51 +02:00
for ( j = 0 ; j < MAX_USERS ; j + + )
retroarch_override_setting_unset ( ( enum rarch_override_setting ) ( i ) , & j ) ;
}
else
retroarch_override_setting_unset ( ( enum rarch_override_setting ) ( i ) , NULL ) ;
}
}
2017-05-11 09:20:35 +02:00
static void global_free ( void )
{
global_t * global = NULL ;
2017-05-27 03:43:53 +02:00
content_deinit ( ) ;
2017-05-11 09:20:35 +02:00
path_deinit_subsystem ( ) ;
command_event ( CMD_EVENT_RECORD_DEINIT , NULL ) ;
command_event ( CMD_EVENT_LOG_FILE_DEINIT , NULL ) ;
2019-01-12 17:58:35 +01:00
rarch_ctl ( RARCH_CTL_UNSET_BLOCK_CONFIG_READ , NULL ) ;
2017-05-12 03:39:37 +02:00
rarch_is_sram_load_disabled = false ;
rarch_is_sram_save_disabled = false ;
rarch_use_sram = false ;
2019-01-12 17:58:35 +01:00
rarch_ctl ( RARCH_CTL_UNSET_BPS_PREF , NULL ) ;
rarch_ctl ( RARCH_CTL_UNSET_IPS_PREF , NULL ) ;
rarch_ctl ( RARCH_CTL_UNSET_UPS_PREF , NULL ) ;
rarch_ctl ( RARCH_CTL_UNSET_PATCH_BLOCKED , NULL ) ;
2017-05-12 03:39:37 +02:00
runloop_overrides_active = false ;
2017-08-05 00:37:26 -05:00
runloop_remaps_core_active = false ;
runloop_remaps_game_active = false ;
2018-05-13 23:17:44 -05:00
runloop_remaps_content_dir_active = false ;
2017-05-11 09:20:35 +02:00
core_unset_input_descriptors ( ) ;
2019-06-17 15:37:34 +02:00
global = & g_extern ;
2017-05-11 09:20:35 +02:00
path_clear_all ( ) ;
dir_clear_all ( ) ;
2017-09-29 20:47:54 +02:00
if ( global )
{
2017-10-04 06:53:47 +02:00
if ( ! string_is_empty ( global - > name . remapfile ) )
2017-09-29 20:47:54 +02:00
free ( global - > name . remapfile ) ;
2019-01-10 22:24:43 +01:00
memset ( global , 0 , sizeof ( struct global ) ) ;
2017-09-29 20:47:54 +02:00
}
2017-05-11 09:20:35 +02:00
retroarch_override_setting_free_state ( ) ;
}
2016-05-09 07:24:28 +02:00
static void retroarch_print_features ( void )
2011-01-25 13:03:53 +01:00
{
2018-08-18 12:43:49 -05:00
frontend_driver_attach_console ( ) ;
2011-01-25 13:03:53 +01:00
puts ( " " ) ;
puts ( " Features: " ) ;
2016-06-20 04:51:36 +02:00
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_LIBRETRODB , " LibretroDB " , " LibretroDB support " ) ;
_PSUPP ( SUPPORTS_COMMAND , " Command " , " Command interface support " ) ;
_PSUPP ( SUPPORTS_NETWORK_COMMAND , " Network Command " , " Network Command interface "
2016-01-26 05:38:40 +01:00
" support " ) ;
2016-06-20 04:51:36 +02:00
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_SDL , " SDL " , " SDL input/audio/video drivers " ) ;
_PSUPP ( SUPPORTS_SDL2 , " SDL2 " , " SDL2 input/audio/video drivers " ) ;
_PSUPP ( SUPPORTS_X11 , " X11 " , " X11 input/video drivers " ) ;
_PSUPP ( SUPPORTS_WAYLAND , " wayland " , " Wayland input/video drivers " ) ;
_PSUPP ( SUPPORTS_THREAD , " Threads " , " Threading support " ) ;
_PSUPP ( SUPPORTS_VULKAN , " Vulkan " , " Vulkan video driver " ) ;
_PSUPP ( SUPPORTS_METAL , " Metal " , " Metal video driver " ) ;
_PSUPP ( SUPPORTS_OPENGL , " OpenGL " , " OpenGL video driver support " ) ;
_PSUPP ( SUPPORTS_OPENGLES , " OpenGL ES " , " OpenGLES video driver support " ) ;
_PSUPP ( SUPPORTS_XVIDEO , " XVideo " , " Video driver " ) ;
_PSUPP ( SUPPORTS_UDEV , " UDEV " , " UDEV/EVDEV input driver support " ) ;
_PSUPP ( SUPPORTS_EGL , " EGL " , " Video context driver " ) ;
_PSUPP ( SUPPORTS_KMS , " KMS " , " Video context driver " ) ;
_PSUPP ( SUPPORTS_VG , " OpenVG " , " Video context driver " ) ;
_PSUPP ( SUPPORTS_COREAUDIO , " CoreAudio " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_COREAUDIO3 , " CoreAudioV3 " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_ALSA , " ALSA " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_OSS , " OSS " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_JACK , " Jack " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_RSOUND , " RSound " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_ROAR , " RoarAudio " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_PULSE , " PulseAudio " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_DSOUND , " DirectSound " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_WASAPI , " WASAPI " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_XAUDIO , " XAudio2 " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_AL , " OpenAL " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_SL , " OpenSL " , " Audio driver " ) ;
_PSUPP ( SUPPORTS_7ZIP , " 7zip " , " 7zip extraction support " ) ;
_PSUPP ( SUPPORTS_ZLIB , " zlib " , " .zip extraction support " ) ;
_PSUPP ( SUPPORTS_DYLIB , " External " , " External filter and plugin support " ) ;
_PSUPP ( SUPPORTS_CG , " Cg " , " Fragment/vertex shader driver " ) ;
_PSUPP ( SUPPORTS_GLSL , " GLSL " , " Fragment/vertex shader driver " ) ;
_PSUPP ( SUPPORTS_HLSL , " HLSL " , " Fragment/vertex shader driver " ) ;
_PSUPP ( SUPPORTS_SDL_IMAGE , " SDL_image " , " SDL_image image loading " ) ;
_PSUPP ( SUPPORTS_RPNG , " rpng " , " PNG image loading/encoding " ) ;
_PSUPP ( SUPPORTS_RJPEG , " rjpeg " , " JPEG image loading " ) ;
_PSUPP ( SUPPORTS_DYNAMIC , " Dynamic " , " Dynamic run-time loading of "
2016-06-20 04:51:36 +02:00
" libretro library " ) ;
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_FFMPEG , " FFmpeg " , " On-the-fly recording of gameplay "
2016-06-20 04:51:36 +02:00
" with libavcodec " ) ;
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_FREETYPE , " FreeType " , " TTF font rendering driver " ) ;
_PSUPP ( SUPPORTS_CORETEXT , " CoreText " , " TTF font rendering driver "
2016-06-20 04:51:36 +02:00
" (for OSX and/or iOS) " ) ;
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_NETPLAY , " Netplay " , " Peer-to-peer netplay " ) ;
_PSUPP ( SUPPORTS_PYTHON , " Python " , " Script support in shaders " ) ;
2016-06-20 04:51:36 +02:00
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_LIBUSB , " Libusb " , " Libusb support " ) ;
2016-06-20 04:51:36 +02:00
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_COCOA , " Cocoa " , " Cocoa UI companion support "
2016-06-20 04:51:36 +02:00
" (for OSX and/or iOS) " ) ;
2019-06-13 22:34:00 +02:00
_PSUPP ( SUPPORTS_QT , " Qt " , " Qt UI companion support " ) ;
_PSUPP ( SUPPORTS_V4L2 , " Video4Linux2 " , " Camera driver " ) ;
2011-01-25 13:03:53 +01:00
}
2016-05-09 07:09:26 +02:00
static void retroarch_print_version ( void )
2010-10-01 21:39:15 +02:00
{
2016-10-27 09:44:20 +02:00
char str [ 255 ] ;
2018-08-18 12:43:49 -05:00
frontend_driver_attach_console ( ) ;
2016-10-21 05:57:40 +02:00
str [ 0 ] = ' \0 ' ;
2015-04-16 20:17:05 +02:00
2016-06-20 03:54:42 +02:00
fprintf ( stderr , " %s: %s -- v%s " ,
msg_hash_to_str ( MSG_PROGRAM ) ,
msg_hash_to_str ( MSG_LIBRETRO_FRONTEND ) ,
PACKAGE_VERSION ) ;
2014-01-11 18:51:42 +01:00
# ifdef HAVE_GIT_VERSION
2016-05-11 20:44:24 +02:00
printf ( " -- %s -- \n " , retroarch_git_version ) ;
2014-01-11 18:51:42 +01:00
# endif
2016-05-09 07:09:26 +02:00
retroarch_get_capabilities ( RARCH_CAPABILITIES_COMPILER , str , sizeof ( str ) ) ;
2015-04-16 20:19:53 +02:00
fprintf ( stdout , " %s " , str ) ;
2015-04-16 20:17:05 +02:00
fprintf ( stdout , " Built: %s \n " , __DATE__ ) ;
2015-06-12 11:42:29 -03:00
}
/**
2016-05-09 07:09:26 +02:00
* retroarch_print_help :
2015-06-12 11:42:29 -03:00
*
2015-06-30 15:26:14 +02:00
* Prints help message explaining the program ' s commandline switches .
2015-06-12 11:42:29 -03:00
* */
2016-05-09 07:09:26 +02:00
static void retroarch_print_help ( const char * arg0 )
2015-06-12 11:42:29 -03:00
{
2018-08-18 12:43:49 -05:00
frontend_driver_attach_console ( ) ;
2015-06-12 12:43:38 -03:00
puts ( " =================================================================== " ) ;
2016-05-09 07:09:26 +02:00
retroarch_print_version ( ) ;
2015-06-12 12:43:38 -03:00
puts ( " =================================================================== " ) ;
2015-06-12 10:15:27 -03:00
printf ( " Usage: %s [OPTIONS]... [FILE] \n " , arg0 ) ;
2015-06-12 11:18:36 -03:00
puts ( " -h, --help Show this help message. " ) ;
2015-06-12 11:42:29 -03:00
puts ( " -v, --verbose Verbose logging. " ) ;
2019-05-17 17:19:13 +01:00
puts ( " --log-file FILE Log messages to FILE. " ) ;
2015-07-03 00:16:46 +02:00
puts ( " --version Show version. " ) ;
2016-01-26 05:38:40 +01:00
puts ( " --features Prints available features compiled into "
" program. " ) ;
2015-10-28 08:02:39 +01:00
# ifdef HAVE_MENU
2016-01-26 05:38:40 +01:00
puts ( " --menu Do not require content or libretro core to "
" be loaded, \n "
" starts directly in menu. If no arguments "
" are passed to \n "
" the program, it is equivalent to using "
" --menu as only argument. " ) ;
2015-10-28 08:02:39 +01:00
# endif
2015-06-12 13:09:00 -03:00
puts ( " -s, --save=PATH Path for save files (*.srm). " ) ;
puts ( " -S, --savestate=PATH Path for the save state files (*.state). " ) ;
2016-01-26 05:38:40 +01:00
puts ( " -f, --fullscreen Start the program in fullscreen regardless "
" of config settings. " ) ;
2015-07-03 00:16:46 +02:00
puts ( " -c, --config=FILE Path for config file. "
# ifdef _WIN32
2016-01-26 05:38:40 +01:00
" \n \t \t Defaults to retroarch.cfg in same directory as retroarch.exe. "
" \n \t \t If a default config is not found, the program will attempt to "
" create one. "
2015-07-03 00:16:46 +02:00
# else
2016-01-26 05:38:40 +01:00
" \n \t \t By default looks for config in $XDG_CONFIG_HOME/retroarch/ "
" retroarch.cfg, \n \t \t $HOME/.config/retroarch/retroarch.cfg, \n \t \t "
" and $HOME/.retroarch.cfg. \n \t \t If a default config is not found, "
2016-08-01 18:35:56 +02:00
" the program will attempt to create one based on the \n \t \t "
" skeleton config ( " GLOBAL_CONFIG_DIR " /retroarch.cfg). \n "
2015-07-03 00:16:46 +02:00
# endif
) ;
2015-06-12 11:18:36 -03:00
puts ( " --appendconfig=FILE \n "
2016-01-26 05:38:40 +01:00
" Extra config files are loaded in, "
" and take priority over \n "
" config selected in -c (or default). "
" Multiple configs are \n "
2015-06-12 11:18:36 -03:00
" delimited by '|'. " ) ;
2011-11-15 21:15:12 +01:00
# ifdef HAVE_DYNAMIC
2016-01-26 05:38:40 +01:00
puts ( " -L, --libretro=FILE Path to libretro implementation. "
" Overrides any config setting. " ) ;
2011-01-19 12:54:19 +01:00
# endif
2016-01-26 05:38:40 +01:00
puts ( " --subsystem=NAME Use a subsystem of the libretro core. "
" Multiple content \n "
" files are loaded as multiple arguments. "
" If a content \n "
" file is skipped, use a blank ( \" \" ) "
" command line argument. \n "
" Content must be loaded in an order "
" which depends on the \n "
" particular subsystem used. See verbose "
" log output to learn \n "
" how a particular subsystem wants content "
" to be loaded. \n " ) ;
2012-08-16 21:20:38 +02:00
2015-06-12 11:18:36 -03:00
printf ( " -N, --nodevice=PORT \n "
2016-01-26 05:38:40 +01:00
" Disconnects controller device connected "
" to PORT (1 to %d). \n " , MAX_USERS ) ;
2015-06-12 11:18:36 -03:00
printf ( " -A, --dualanalog=PORT \n "
2016-01-26 05:38:40 +01:00
" Connect a DualAnalog controller to PORT "
" (1 to %d). \n " , MAX_USERS ) ;
2015-06-12 11:18:36 -03:00
printf ( " -d, --device=PORT:ID \n "
2016-01-26 05:38:40 +01:00
" Connect a generic device into PORT of "
" the device (1 to %d). \n " , MAX_USERS ) ;
puts ( " Format is PORT:ID, where ID is a number "
" corresponding to the particular device. " ) ;
2012-08-16 21:20:38 +02:00
2015-06-12 11:18:36 -03:00
puts ( " -P, --bsvplay=FILE Playback a BSV movie file. " ) ;
2016-01-26 05:38:40 +01:00
puts ( " -R, --bsvrecord=FILE Start recording a BSV movie file from "
" the beginning. " ) ;
puts ( " --eof-exit Exit upon reaching the end of the "
" BSV movie file. " ) ;
puts ( " -M, --sram-mode=MODE SRAM handling mode. MODE can be "
" 'noload-nosave', \n "
" 'noload-save', 'load-nosave' or "
" 'load-save'. \n "
" Note: 'noload-save' implies that "
" save files *WILL BE OVERWRITTEN*. " ) ;
2011-11-20 20:19:05 +01:00
2016-09-29 21:07:10 +02:00
# ifdef HAVE_NETWORKING
2015-06-12 11:18:36 -03:00
puts ( " -H, --host Host netplay as user 1. " ) ;
puts ( " -C, --connect=HOST Connect to netplay server as user 2. " ) ;
puts ( " --port=PORT Port used to netplay. Default is 55435. " ) ;
2016-12-15 23:09:55 -05:00
puts ( " --stateless Use \" stateless \" mode for netplay " ) ;
puts ( " (requires a very fast network). " ) ;
2016-09-14 23:54:18 -04:00
puts ( " --check-frames=NUMBER \n "
" Check frames when using netplay. " ) ;
2016-09-29 21:10:35 +02:00
# if defined(HAVE_NETWORK_CMD)
2016-01-26 05:38:40 +01:00
puts ( " --command Sends a command over UDP to an already "
" running program process. " ) ;
2015-06-12 11:18:36 -03:00
puts ( " Available commands are listed if command is invalid. " ) ;
2012-06-01 15:15:06 +02:00
# endif
2011-01-07 17:59:53 +01:00
2016-09-29 21:10:35 +02:00
# endif
puts ( " --nick=NICK Picks a username (for use with netplay). "
" Not mandatory. " ) ;
2016-01-26 05:38:40 +01:00
puts ( " -r, --record=FILE Path to record video file. \n "
" Using .mkv extension is recommended. " ) ;
2015-06-12 11:18:36 -03:00
puts ( " --recordconfig Path to settings used during recording. " ) ;
puts ( " --size=WIDTHxHEIGHT \n "
" Overrides output video size when recording. " ) ;
2016-01-26 05:38:40 +01:00
puts ( " -U, --ups=FILE Specifies path for UPS patch that will be "
" applied to content. " ) ;
puts ( " --bps=FILE Specifies path for BPS patch that will be "
" applied to content. " ) ;
puts ( " --ips=FILE Specifies path for IPS patch that will be "
" applied to content. " ) ;
2015-06-12 11:18:36 -03:00
puts ( " --no-patch Disables all forms of content patching. " ) ;
2016-01-26 05:38:40 +01:00
puts ( " -D, --detach Detach program from the running console. "
" Not relevant for all platforms. " ) ;
2015-06-12 11:18:36 -03:00
puts ( " --max-frames=NUMBER \n "
2016-01-26 05:38:40 +01:00
" Runs for the specified number of frames, "
2018-08-18 23:09:40 -04:00
" then exits. " ) ;
puts ( " --max-frames-ss \n "
" Takes a screenshot at the end of max-frames. " ) ;
puts ( " --max-frames-ss-path=FILE \n "
" Path to save the screenshot to at the end of max-frames. \n " ) ;
2010-10-01 21:39:15 +02:00
}
2015-06-26 19:19:36 +02:00
# define FFMPEG_RECORD_ARG "r:"
# ifdef HAVE_DYNAMIC
# define DYNAMIC_ARG "L:"
# else
# define DYNAMIC_ARG
# endif
2016-09-29 21:07:10 +02:00
# ifdef HAVE_NETWORKING
2015-06-26 19:19:36 +02:00
# define NETPLAY_ARG "HC:F:"
# else
# define NETPLAY_ARG
# endif
# define BSV_MOVIE_ARG "P:R:M:"
2015-01-11 02:21:18 +01:00
/**
2018-03-09 17:23:34 -05:00
* retroarch_parse_input_and_config :
2015-01-11 02:21:18 +01:00
* @ argc : Count of ( commandline ) arguments .
2015-05-07 18:06:14 -05:00
* @ argv : ( Commandline ) arguments .
2015-01-11 02:21:18 +01:00
*
2018-03-09 17:23:34 -05:00
* Parses ( commandline ) arguments passed to program and loads the config file ,
* with command line options overriding the config file .
2015-01-11 02:21:18 +01:00
*
* */
2018-03-09 17:23:34 -05:00
static void retroarch_parse_input_and_config ( int argc , char * argv [ ] )
2010-05-26 21:27:37 +02:00
{
2019-05-21 05:37:21 +02:00
static bool first_run = true ;
2015-06-26 19:19:36 +02:00
const char * optstring = NULL ;
2016-03-23 00:29:52 +01:00
bool explicit_menu = false ;
2019-01-05 19:16:28 -05:00
unsigned i ;
2019-06-17 15:37:34 +02:00
global_t * global = & g_extern ;
2011-02-18 14:49:15 +01:00
2012-01-05 21:43:55 +01:00
const struct option opts [ ] = {
2011-11-15 21:15:12 +01:00
# ifdef HAVE_DYNAMIC
2018-08-18 23:09:40 -04:00
{ " libretro " , 1 , NULL , ' L ' } ,
# endif
{ " menu " , 0 , NULL , RA_OPT_MENU } ,
{ " help " , 0 , NULL , ' h ' } ,
{ " save " , 1 , NULL , ' s ' } ,
{ " fullscreen " , 0 , NULL , ' f ' } ,
{ " record " , 1 , NULL , ' r ' } ,
{ " recordconfig " , 1 , NULL , RA_OPT_RECORDCONFIG } ,
{ " size " , 1 , NULL , RA_OPT_SIZE } ,
{ " verbose " , 0 , NULL , ' v ' } ,
{ " config " , 1 , NULL , ' c ' } ,
{ " appendconfig " , 1 , NULL , RA_OPT_APPENDCONFIG } ,
{ " nodevice " , 1 , NULL , ' N ' } ,
{ " dualanalog " , 1 , NULL , ' A ' } ,
{ " device " , 1 , NULL , ' d ' } ,
{ " savestate " , 1 , NULL , ' S ' } ,
{ " bsvplay " , 1 , NULL , ' P ' } ,
{ " bsvrecord " , 1 , NULL , ' R ' } ,
{ " sram-mode " , 1 , NULL , ' M ' } ,
2016-09-29 21:07:10 +02:00
# ifdef HAVE_NETWORKING
2018-08-18 23:09:40 -04:00
{ " host " , 0 , NULL , ' H ' } ,
{ " connect " , 1 , NULL , ' C ' } ,
{ " stateless " , 0 , NULL , RA_OPT_STATELESS } ,
{ " check-frames " , 1 , NULL , RA_OPT_CHECK_FRAMES } ,
{ " port " , 1 , NULL , RA_OPT_PORT } ,
2016-09-29 21:07:10 +02:00
# if defined(HAVE_NETWORK_CMD)
2018-08-18 23:09:40 -04:00
{ " command " , 1 , NULL , RA_OPT_COMMAND } ,
# endif
# endif
{ " nick " , 1 , NULL , RA_OPT_NICK } ,
{ " ups " , 1 , NULL , ' U ' } ,
{ " bps " , 1 , NULL , RA_OPT_BPS } ,
{ " ips " , 1 , NULL , RA_OPT_IPS } ,
{ " no-patch " , 0 , NULL , RA_OPT_NO_PATCH } ,
{ " detach " , 0 , NULL , ' D ' } ,
{ " features " , 0 , NULL , RA_OPT_FEATURES } ,
{ " subsystem " , 1 , NULL , RA_OPT_SUBSYSTEM } ,
{ " max-frames " , 1 , NULL , RA_OPT_MAX_FRAMES } ,
{ " max-frames-ss " , 0 , NULL , RA_OPT_MAX_FRAMES_SCREENSHOT } ,
{ " max-frames-ss-path " , 1 , NULL , RA_OPT_MAX_FRAMES_SCREENSHOT_PATH } ,
{ " eof-exit " , 0 , NULL , RA_OPT_EOF_EXIT } ,
{ " version " , 0 , NULL , RA_OPT_VERSION } ,
2019-05-17 17:19:13 +01:00
{ " log-file " , 1 , NULL , RA_OPT_LOG_FILE } ,
2010-10-01 21:39:15 +02:00
{ NULL , 0 , NULL , 0 }
} ;
2019-05-21 05:43:49 +02:00
if ( first_run )
2019-01-05 19:16:28 -05:00
{
2019-05-21 05:36:04 +02:00
/* Copy the args into a buffer so launch arguments can be reused */
for ( i = 0 ; i < ( unsigned ) argc ; i + + )
{
strlcat ( launch_arguments , argv [ i ] , sizeof ( launch_arguments ) ) ;
strlcat ( launch_arguments , " " , sizeof ( launch_arguments ) ) ;
}
string_trim_whitespace_left ( launch_arguments ) ;
string_trim_whitespace_right ( launch_arguments ) ;
2019-05-21 05:37:21 +02:00
first_run = false ;
2019-01-05 19:16:28 -05:00
}
2016-03-23 00:29:52 +01:00
/* Handling the core type is finicky. Based on the arguments we pass in,
* we handle it differently .
* Some current cases which track desired behavior and how it is supposed to work :
*
* Dynamically linked RA :
* . / retroarch - > CORE_TYPE_DUMMY
* . / retroarch - v - > CORE_TYPE_DUMMY + verbose
* . / retroarch - - menu - > CORE_TYPE_DUMMY
* . / retroarch - - menu - v - > CORE_TYPE_DUMMY + verbose
* . / retroarch - L contentless - core - > CORE_TYPE_PLAIN
* . / retroarch - L content - core - > CORE_TYPE_PLAIN + FAIL ( This currently crashes )
* . / retroarch [ - L content - core ] ROM - > CORE_TYPE_PLAIN
* . / retroarch < - L or ROM > - - menu - > FAIL
*
* The heuristic here seems to be that if we use the - L CLI option or
* optind < argc at the end we should set CORE_TYPE_PLAIN .
* To handle - - menu , we should ensure that CORE_TYPE_DUMMY is still set
* otherwise , fail early , since the CLI options are non - sensical .
* We could also simply ignore - - menu in this case to be more friendly with
* bogus arguments .
*/
2016-10-03 16:42:08 +02:00
if ( ! has_set_core )
2016-09-12 08:37:40 +02:00
retroarch_set_current_core_type ( CORE_TYPE_DUMMY , false ) ;
2016-05-27 21:16:25 +02:00
2016-09-30 04:31:19 +02:00
path_clear ( RARCH_PATH_SUBSYSTEM ) ;
2016-08-01 20:43:26 +02:00
2016-08-01 20:48:02 +02:00
retroarch_override_setting_free_state ( ) ;
2016-08-01 20:43:26 +02:00
2019-01-14 05:25:04 +01:00
rarch_ctl ( RARCH_CTL_USERNAME_UNSET , NULL ) ;
2019-01-12 17:58:35 +01:00
rarch_ctl ( RARCH_CTL_UNSET_UPS_PREF , NULL ) ;
rarch_ctl ( RARCH_CTL_UNSET_IPS_PREF , NULL ) ;
rarch_ctl ( RARCH_CTL_UNSET_BPS_PREF , NULL ) ;
2016-10-01 08:18:23 +02:00
* global - > name . ups = ' \0 ' ;
* global - > name . bps = ' \0 ' ;
* global - > name . ips = ' \0 ' ;
2011-11-30 16:43:09 +01:00
2017-05-15 05:06:23 +02:00
rarch_ctl ( RARCH_CTL_UNSET_OVERRIDES_ACTIVE , NULL ) ;
2014-09-02 17:05:15 +02:00
2016-05-09 07:24:28 +02:00
/* Make sure we can call retroarch_parse_input several times ... */
2015-06-26 19:19:36 +02:00
optind = 0 ;
2016-03-10 17:36:46 -05:00
optstring = " hs:fvS:A:c:U:DN:d: "
2016-01-26 05:38:40 +01:00
BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG ;
2013-01-13 04:12:10 +01:00
2019-01-03 21:46:29 +01:00
# ifdef ORBIS
argv = & ( argv [ 2 ] ) ;
argc = argc - 2 ;
# endif
2016-08-01 18:35:56 +02:00
# ifndef HAVE_MENU
if ( argc = = 1 )
{
2016-11-08 15:17:02 +01:00
printf ( " %s \n " , msg_hash_to_str ( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN ) ) ;
2016-08-01 18:35:56 +02:00
retroarch_print_help ( argv [ 0 ] ) ;
exit ( 0 ) ;
}
# endif
2018-03-09 17:23:34 -05:00
/* First pass: Read the config file path and any directory overrides, so
* they ' re in place when we load the config */
2019-01-06 22:03:16 -05:00
if ( argc )
2010-05-29 15:21:30 +02:00
{
2019-01-06 22:03:16 -05:00
for ( ; ; )
{
int c = getopt_long ( argc , argv , optstring , opts , NULL ) ;
2015-06-26 20:35:02 +02:00
2016-06-28 04:23:57 +02:00
#if 0
2019-01-06 22:03:16 -05:00
fprintf ( stderr , " c is: %c (%d), optarg is: [%s] \n " , c , c , string_is_empty ( optarg ) ? " " : optarg ) ;
2016-06-28 04:23:57 +02:00
# endif
2019-01-06 22:03:16 -05:00
if ( c = = - 1 )
break ;
2010-10-01 21:39:15 +02:00
2019-01-06 22:03:16 -05:00
switch ( c )
{
case ' h ' :
retroarch_print_help ( argv [ 0 ] ) ;
exit ( 0 ) ;
2010-10-01 21:39:15 +02:00
2019-01-06 22:03:16 -05:00
case ' c ' :
RARCH_LOG ( " Set config file to : %s \n " , optarg ) ;
path_set ( RARCH_PATH_CONFIG , optarg ) ;
break ;
2018-03-09 17:23:34 -05:00
2019-01-06 22:03:16 -05:00
case RA_OPT_APPENDCONFIG :
path_set ( RARCH_PATH_CONFIG_APPEND , optarg ) ;
break ;
2018-03-20 18:48:51 -04:00
2019-01-06 22:03:16 -05:00
case ' s ' :
strlcpy ( global - > name . savefile , optarg ,
sizeof ( global - > name . savefile ) ) ;
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_SAVE_PATH , NULL ) ;
break ;
2018-03-09 17:23:34 -05:00
2019-01-06 22:03:16 -05:00
case ' S ' :
strlcpy ( global - > name . savestate , optarg ,
sizeof ( global - > name . savestate ) ) ;
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_STATE_PATH , NULL ) ;
break ;
2018-03-09 17:23:34 -05:00
2019-01-06 22:03:16 -05:00
/* Must handle '?' otherwise you get an infinite loop */
case ' ? ' :
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
break ;
/* All other arguments are handled in the second pass */
}
2018-03-09 17:23:34 -05:00
}
}
/* Load the config file now that we know what it is */
config_load ( ) ;
/* Second pass: All other arguments override the config file */
optind = 1 ;
2019-01-06 22:03:16 -05:00
if ( argc )
2018-03-09 17:23:34 -05:00
{
2019-01-06 22:03:16 -05:00
for ( ; ; )
2018-03-09 17:23:34 -05:00
{
2019-01-06 22:03:16 -05:00
int c = getopt_long ( argc , argv , optstring , opts , NULL ) ;
2011-01-10 16:53:37 +01:00
2019-01-06 22:03:16 -05:00
if ( c = = - 1 )
break ;
2017-01-17 19:59:33 +01:00
2019-01-06 22:03:16 -05:00
switch ( c )
{
case ' d ' :
2017-05-29 14:58:30 +02:00
{
2019-01-06 22:03:16 -05:00
unsigned new_port ;
unsigned id = 0 ;
struct string_list * list = string_split ( optarg , " : " ) ;
int port = 0 ;
2016-10-01 06:22:57 +02:00
2019-01-06 22:03:16 -05:00
if ( list & & list - > size = = 2 )
{
port = ( int ) strtol ( list - > elems [ 0 ] . data , NULL , 0 ) ;
id = ( unsigned ) strtoul ( list - > elems [ 1 ] . data , NULL , 0 ) ;
}
string_list_free ( list ) ;
2017-05-29 14:58:30 +02:00
2019-01-06 22:03:16 -05:00
if ( port < 1 | | port > MAX_USERS )
{
RARCH_ERR ( " %s \n " , msg_hash_to_str ( MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT ) ) ;
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
}
new_port = port - 1 ;
2014-04-04 14:58:42 +02:00
2019-01-06 22:03:16 -05:00
input_config_set_device ( new_port , id ) ;
2016-10-01 06:22:57 +02:00
2019-01-06 22:03:16 -05:00
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE , & new_port ) ;
2017-05-29 14:58:30 +02:00
}
2019-01-06 22:03:16 -05:00
break ;
2017-05-29 14:58:30 +02:00
2019-01-06 22:03:16 -05:00
case ' A ' :
2017-05-29 14:58:30 +02:00
{
2019-01-06 22:03:16 -05:00
unsigned new_port ;
int port = ( int ) strtol ( optarg , NULL , 0 ) ;
2012-08-16 21:20:38 +02:00
2019-01-06 22:03:16 -05:00
if ( port < 1 | | port > MAX_USERS )
{
RARCH_ERR ( " Connect dualanalog to a valid port. \n " ) ;
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
}
new_port = port - 1 ;
2011-07-09 08:37:08 +02:00
2019-01-06 22:03:16 -05:00
input_config_set_device ( new_port , RETRO_DEVICE_ANALOG ) ;
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE , & new_port ) ;
2017-05-29 14:58:30 +02:00
}
2019-01-06 22:03:16 -05:00
break ;
2010-10-01 22:10:28 +02:00
2019-01-06 22:03:16 -05:00
case ' f ' :
rarch_force_fullscreen = true ;
break ;
2017-05-29 14:58:30 +02:00
2019-01-06 22:03:16 -05:00
case ' v ' :
verbosity_enable ( ) ;
2016-10-01 06:22:57 +02:00
retroarch_override_setting_set (
2019-01-06 22:03:16 -05:00
RARCH_OVERRIDE_SETTING_VERBOSITY , NULL ) ;
break ;
2011-01-05 20:07:55 +01:00
2019-01-06 22:03:16 -05:00
case ' N ' :
2017-05-29 14:58:30 +02:00
{
2019-01-06 22:03:16 -05:00
unsigned new_port ;
int port = ( int ) strtol ( optarg , NULL , 0 ) ;
2017-01-17 19:59:33 +01:00
2019-01-06 22:03:16 -05:00
if ( port < 1 | | port > MAX_USERS )
{
RARCH_ERR ( " %s \n " ,
msg_hash_to_str ( MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT ) ) ;
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
}
new_port = port - 1 ;
input_config_set_device ( port - 1 , RETRO_DEVICE_NONE ) ;
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE , & new_port ) ;
2017-05-29 14:58:30 +02:00
}
2019-01-06 22:03:16 -05:00
break ;
case ' r ' :
strlcpy ( global - > record . path , optarg ,
sizeof ( global - > record . path ) ) ;
2019-06-17 16:23:46 +02:00
if ( recording_enable )
2019-01-06 22:03:16 -05:00
recording_set_state ( true ) ;
break ;
# ifdef HAVE_DYNAMIC
case ' L ' :
{
2019-05-22 02:21:14 +02:00
int path_stats = path_stat ( optarg ) ;
2018-04-30 14:33:05 -04:00
2019-05-22 02:21:14 +02:00
if ( ( path_stats & RETRO_VFS_STAT_IS_DIRECTORY ) ! = 0 )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2018-04-30 14:33:05 -04:00
2019-05-22 02:21:14 +02:00
path_clear ( RARCH_PATH_CORE ) ;
strlcpy ( settings - > paths . directory_libretro , optarg ,
sizeof ( settings - > paths . directory_libretro ) ) ;
2016-03-23 00:29:52 +01:00
2019-05-22 02:21:14 +02:00
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO , NULL ) ;
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY , NULL ) ;
RARCH_WARN ( " Using old --libretro behavior. "
" Setting libretro_directory to \" %s \" instead. \n " ,
optarg ) ;
}
else if ( ( path_stats & RETRO_VFS_STAT_IS_VALID ) ! = 0 )
{
path_set ( RARCH_PATH_CORE , optarg ) ;
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO , NULL ) ;
2015-12-01 01:25:36 +01:00
2019-05-22 02:21:14 +02:00
/* We requested explicit core, so use PLAIN core type. */
retroarch_set_current_core_type ( CORE_TYPE_PLAIN , false ) ;
}
else
{
RARCH_WARN ( " --libretro argument \" %s \" is neither a file nor directory. Ignoring. \n " ,
optarg ) ;
}
}
2019-01-06 22:03:16 -05:00
break ;
# endif
case ' P ' :
case ' R ' :
2019-06-16 16:52:48 +02:00
strlcpy ( bsv_movie_state . movie_start_path , optarg ,
sizeof ( bsv_movie_state . movie_start_path ) ) ;
2015-12-01 01:25:36 +01:00
2019-01-06 22:03:16 -05:00
if ( c = = ' P ' )
2019-06-16 20:04:43 +02:00
bsv_movie_state . movie_start_playback = true ;
2019-01-06 22:03:16 -05:00
else
2019-06-16 20:04:43 +02:00
bsv_movie_state . movie_start_playback = false ;
2011-11-18 18:03:24 +01:00
2019-01-06 22:03:16 -05:00
if ( c = = ' R ' )
2019-06-16 20:04:43 +02:00
bsv_movie_state . movie_start_recording = true ;
2019-01-06 22:03:16 -05:00
else
2019-06-16 20:04:43 +02:00
bsv_movie_state . movie_start_recording = false ;
2019-01-06 22:03:16 -05:00
break ;
2011-02-02 12:10:27 +01:00
2019-01-06 22:03:16 -05:00
case ' M ' :
if ( string_is_equal ( optarg , " noload-nosave " ) )
{
rarch_is_sram_load_disabled = true ;
rarch_is_sram_save_disabled = true ;
}
else if ( string_is_equal ( optarg , " noload-save " ) )
rarch_is_sram_load_disabled = true ;
else if ( string_is_equal ( optarg , " load-nosave " ) )
rarch_is_sram_save_disabled = true ;
else if ( string_is_not_equal ( optarg , " load-save " ) )
2016-10-01 06:22:57 +02:00
{
2019-01-06 22:03:16 -05:00
RARCH_ERR ( " Invalid argument in --sram-mode. \n " ) ;
2016-10-01 06:22:57 +02:00
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
}
2019-01-06 22:03:16 -05:00
break ;
2011-02-13 16:40:24 +01:00
2019-01-06 22:03:16 -05:00
# ifdef HAVE_NETWORKING
case ' H ' :
2017-01-17 19:59:33 +01:00
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_NETPLAY_MODE , NULL ) ;
2019-01-06 22:03:16 -05:00
netplay_driver_ctl ( RARCH_NETPLAY_CTL_ENABLE_SERVER , NULL ) ;
break ;
2016-09-29 21:10:35 +02:00
2019-01-06 22:03:16 -05:00
case ' C ' :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-01-06 22:03:16 -05:00
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_NETPLAY_MODE , NULL ) ;
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS , NULL ) ;
netplay_driver_ctl ( RARCH_NETPLAY_CTL_ENABLE_CLIENT , NULL ) ;
strlcpy ( settings - > paths . netplay_server , optarg ,
sizeof ( settings - > paths . netplay_server ) ) ;
}
break ;
2011-02-15 15:32:26 +01:00
2019-01-06 22:03:16 -05:00
case RA_OPT_STATELESS :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2015-06-30 22:43:41 +02:00
2019-01-06 22:03:16 -05:00
configuration_set_bool ( settings ,
settings - > bools . netplay_stateless_mode , true ) ;
2011-04-23 14:47:50 +02:00
2019-01-06 22:03:16 -05:00
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE , NULL ) ;
}
break ;
2015-06-30 22:43:41 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_CHECK_FRAMES :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-01-06 22:03:16 -05:00
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES , NULL ) ;
2015-06-30 22:43:41 +02:00
2019-01-06 22:03:16 -05:00
configuration_set_int ( settings ,
settings - > ints . netplay_check_frames ,
( int ) strtoul ( optarg , NULL , 0 ) ) ;
}
break ;
2015-10-19 19:43:21 -05:00
2019-01-06 22:03:16 -05:00
case RA_OPT_PORT :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-01-06 22:03:16 -05:00
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT , NULL ) ;
configuration_set_uint ( settings ,
settings - > uints . netplay_port ,
( int ) strtoul ( optarg , NULL , 0 ) ) ;
}
break ;
2013-04-14 16:24:19 +02:00
2019-01-06 22:03:16 -05:00
# if defined(HAVE_NETWORK_CMD)
case RA_OPT_COMMAND :
# ifdef HAVE_COMMAND
if ( command_network_send ( ( const char * ) optarg ) )
exit ( 0 ) ;
else
retroarch_fail ( 1 , " network_cmd_send() " ) ;
# endif
break ;
# endif
# endif
case RA_OPT_BPS :
strlcpy ( global - > name . bps , optarg ,
sizeof ( global - > name . bps ) ) ;
rarch_bps_pref = true ;
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_BPS_PREF , NULL ) ;
break ;
case ' U ' :
strlcpy ( global - > name . ups , optarg ,
sizeof ( global - > name . ups ) ) ;
rarch_ups_pref = true ;
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_UPS_PREF , NULL ) ;
break ;
case RA_OPT_IPS :
strlcpy ( global - > name . ips , optarg ,
sizeof ( global - > name . ips ) ) ;
rarch_ips_pref = true ;
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_IPS_PREF , NULL ) ;
break ;
case RA_OPT_NO_PATCH :
rarch_ctl ( RARCH_CTL_SET_PATCH_BLOCKED , NULL ) ;
break ;
case ' D ' :
frontend_driver_detach_console ( ) ;
break ;
case RA_OPT_MENU :
explicit_menu = true ;
break ;
case RA_OPT_NICK :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2017-05-12 03:39:37 +02:00
2019-01-14 05:25:04 +01:00
rarch_ctl ( RARCH_CTL_USERNAME_SET , NULL ) ;
2017-05-12 03:39:37 +02:00
2019-01-06 22:03:16 -05:00
strlcpy ( settings - > paths . username , optarg ,
sizeof ( settings - > paths . username ) ) ;
}
break ;
2016-09-29 21:07:10 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_SIZE :
2019-06-17 16:23:46 +02:00
if ( sscanf ( optarg , " %ux%u " ,
& recording_width ,
& recording_height ) ! = 2 )
2019-01-06 22:03:16 -05:00
{
2019-06-17 16:23:46 +02:00
RARCH_ERR ( " Wrong format for --size. \n " ) ;
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
2019-01-06 22:03:16 -05:00
}
break ;
2011-02-18 14:49:15 +01:00
2019-01-06 22:03:16 -05:00
case RA_OPT_RECORDCONFIG :
strlcpy ( global - > record . config , optarg ,
sizeof ( global - > record . config ) ) ;
break ;
2015-06-30 22:36:17 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_MAX_FRAMES :
runloop_max_frames = ( unsigned ) strtoul ( optarg , NULL , 10 ) ;
break ;
2015-06-30 22:36:17 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_MAX_FRAMES_SCREENSHOT :
runloop_max_frames_screenshot = true ;
break ;
2018-08-18 23:09:40 -04:00
2019-01-06 22:03:16 -05:00
case RA_OPT_MAX_FRAMES_SCREENSHOT_PATH :
strlcpy ( runloop_max_frames_screenshot_path , optarg , sizeof ( runloop_max_frames_screenshot_path ) ) ;
break ;
2018-08-18 23:09:40 -04:00
2019-01-06 22:03:16 -05:00
case RA_OPT_SUBSYSTEM :
path_set ( RARCH_PATH_SUBSYSTEM , optarg ) ;
break ;
2015-06-30 22:36:17 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_FEATURES :
retroarch_print_features ( ) ;
exit ( 0 ) ;
2015-06-30 22:36:17 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_EOF_EXIT :
2019-06-16 20:04:43 +02:00
bsv_movie_state . eof_exit = true ;
2019-01-06 22:03:16 -05:00
break ;
2015-06-30 22:36:17 +02:00
2019-01-06 22:03:16 -05:00
case RA_OPT_VERSION :
retroarch_print_version ( ) ;
exit ( 0 ) ;
2010-10-01 21:39:15 +02:00
2019-05-17 17:19:13 +01:00
case RA_OPT_LOG_FILE :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-05-17 17:19:13 +01:00
/* Enable 'log to file' */
configuration_set_bool ( settings ,
settings - > bools . log_to_file , true ) ;
retroarch_override_setting_set (
RARCH_OVERRIDE_SETTING_LOG_TO_FILE , NULL ) ;
/* Cache log file path override */
log_file_override_active = true ;
strlcpy ( log_file_override_path , optarg , sizeof ( log_file_override_path ) ) ;
}
break ;
2019-01-06 22:03:16 -05:00
case ' c ' :
case ' h ' :
case RA_OPT_APPENDCONFIG :
case ' s ' :
case ' S ' :
break ; /* Handled in the first pass */
2018-03-09 17:23:34 -05:00
2019-01-06 22:03:16 -05:00
case ' ? ' :
retroarch_print_help ( argv [ 0 ] ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
2015-06-30 22:39:13 +02:00
2019-01-06 22:03:16 -05:00
default :
RARCH_ERR ( " %s \n " , msg_hash_to_str ( MSG_ERROR_PARSING_ARGUMENTS ) ) ;
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
}
2010-10-01 21:39:15 +02:00
}
2010-05-29 15:21:30 +02:00
}
2017-07-04 21:46:22 -04:00
2019-03-05 17:34:05 -05:00
if ( verbosity_is_enabled ( ) )
2019-03-21 16:56:24 +00:00
rarch_log_file_init ( ) ;
2019-03-05 17:34:05 -05:00
2017-01-29 05:06:14 +01:00
# ifdef HAVE_GIT_VERSION
2017-07-04 21:46:22 -04:00
RARCH_LOG ( " RetroArch %s (Git %s) \n " ,
2017-05-29 14:58:30 +02:00
PACKAGE_VERSION , retroarch_git_version ) ;
2017-01-29 05:06:14 +01:00
# endif
2010-05-29 15:21:30 +02:00
2016-04-05 23:21:55 +02:00
if ( explicit_menu )
2013-04-14 16:24:19 +02:00
{
2016-04-05 23:21:55 +02:00
if ( optind < argc )
{
RARCH_ERR ( " --menu was used, but content file was passed as well. \n " ) ;
2016-05-09 07:24:28 +02:00
retroarch_fail ( 1 , " retroarch_parse_input() " ) ;
2016-04-05 23:21:55 +02:00
}
2016-09-12 08:37:40 +02:00
# ifdef HAVE_DYNAMIC
2016-04-05 23:21:55 +02:00
else
{
2017-07-04 21:46:22 -04:00
/* Allow stray -L arguments to go through to workaround cases
2016-09-17 14:23:44 +02:00
* where it ' s used as " config file " .
*
2017-07-04 21:46:22 -04:00
* This seems to still be the case for Android , which
2016-09-17 14:23:44 +02:00
* should be properly fixed . */
2016-05-27 21:16:25 +02:00
retroarch_set_current_core_type ( CORE_TYPE_DUMMY , false ) ;
2016-04-05 23:21:55 +02:00
}
2016-09-12 08:37:40 +02:00
# endif
2013-04-14 16:24:19 +02:00
}
2016-03-23 00:29:52 +01:00
2019-04-21 05:24:06 +02:00
if ( optind < argc )
2016-03-23 00:29:52 +01:00
{
2019-04-21 05:24:06 +02:00
bool subsystem_path_is_empty = path_is_empty ( RARCH_PATH_SUBSYSTEM ) ;
2016-03-23 00:29:52 +01:00
/* We requested explicit ROM, so use PLAIN core type. */
2016-05-27 21:16:25 +02:00
retroarch_set_current_core_type ( CORE_TYPE_PLAIN , false ) ;
2019-04-21 05:24:06 +02:00
if ( subsystem_path_is_empty )
path_set ( RARCH_PATH_NAMES , ( const char * ) argv [ optind ] ) ;
else
path_set_special ( argv + optind , argc - optind ) ;
2016-03-23 00:29:52 +01:00
}
2015-06-23 06:44:29 +02:00
2014-08-20 17:18:43 +02:00
/* Copy SRM/state dirs used, so they can be reused on reentrancy. */
2016-10-01 06:05:08 +02:00
if ( retroarch_override_setting_is_set ( RARCH_OVERRIDE_SETTING_SAVE_PATH , NULL ) & &
2016-10-01 08:18:23 +02:00
path_is_directory ( global - > name . savefile ) )
2016-10-03 08:20:33 +02:00
dir_set ( RARCH_DIR_SAVEFILE , global - > name . savefile ) ;
2016-10-01 08:18:23 +02:00
2016-10-01 08:24:02 +02:00
if ( retroarch_override_setting_is_set ( RARCH_OVERRIDE_SETTING_STATE_PATH , NULL ) & &
2016-10-01 08:18:23 +02:00
path_is_directory ( global - > name . savestate ) )
2016-10-03 08:20:33 +02:00
dir_set ( RARCH_DIR_SAVESTATE , global - > name . savestate ) ;
2010-10-01 21:39:15 +02:00
}
2010-08-15 10:02:04 +02:00
2016-05-09 07:09:26 +02:00
bool retroarch_validate_game_options ( char * s , size_t len , bool mkdir )
2016-01-26 02:24:59 +01:00
{
2018-02-04 23:02:52 +01:00
char * config_directory = NULL ;
2017-09-09 06:21:27 +02:00
size_t str_size = PATH_MAX_LENGTH * sizeof ( char ) ;
2017-05-30 16:57:29 +02:00
const char * core_name = runloop_system . info . library_name ;
2017-05-20 19:24:21 +02:00
const char * game_name = path_basename ( path_get ( RARCH_PATH_BASENAME ) ) ;
2016-01-26 02:24:59 +01:00
if ( string_is_empty ( core_name ) | | string_is_empty ( game_name ) )
2018-02-04 23:02:52 +01:00
return false ;
2016-01-26 02:24:59 +01:00
2018-10-29 07:38:26 +01:00
config_directory = ( char * ) malloc ( str_size ) ;
2019-04-23 21:06:12 +02:00
config_directory [ 0 ] = ' \0 ' ;
2017-05-20 19:24:21 +02:00
2017-01-17 20:07:41 +01:00
fill_pathname_application_special ( config_directory ,
2017-09-09 06:21:27 +02:00
str_size , APPLICATION_SPECIAL_DIRECTORY_CONFIG ) ;
2016-01-26 02:24:59 +01:00
/* Concatenate strings into full paths for game_path */
2016-06-30 04:59:57 +02:00
fill_pathname_join_special_ext ( s ,
config_directory , core_name , game_name ,
file_path_str ( FILE_PATH_OPT_EXTENSION ) ,
len ) ;
2016-01-26 02:24:59 +01:00
2019-04-23 21:06:12 +02:00
if ( mkdir )
{
char * core_path = ( char * ) malloc ( str_size ) ;
core_path [ 0 ] = ' \0 ' ;
fill_pathname_join ( core_path ,
config_directory , core_name , str_size ) ;
2016-02-08 00:07:41 -05:00
2019-04-23 21:06:12 +02:00
if ( ! path_is_directory ( core_path ) )
path_mkdir ( core_path ) ;
free ( core_path ) ;
}
2016-01-26 02:24:59 +01:00
2017-09-09 06:21:27 +02:00
free ( config_directory ) ;
2016-01-26 02:24:59 +01:00
return true ;
}
2014-10-05 19:13:03 +02:00
2016-05-11 21:48:30 +02:00
/* Validates CPU features for given processor architecture.
* Make sure we haven ' t compiled for something we cannot run .
* Ideally , code would get swapped out depending on CPU support ,
* but this will do for now . */
static void retroarch_validate_cpu_features ( void )
{
uint64_t cpu = cpu_features_get ( ) ;
( void ) cpu ;
2019-02-23 16:50:36 -05:00
# ifdef __MMX__
if ( ! ( cpu & RETRO_SIMD_MMX ) )
FAIL_CPU ( " MMX " ) ;
# endif
2016-05-11 21:48:30 +02:00
# ifdef __SSE__
if ( ! ( cpu & RETRO_SIMD_SSE ) )
FAIL_CPU ( " SSE " ) ;
# endif
# ifdef __SSE2__
if ( ! ( cpu & RETRO_SIMD_SSE2 ) )
FAIL_CPU ( " SSE2 " ) ;
# endif
# ifdef __AVX__
if ( ! ( cpu & RETRO_SIMD_AVX ) )
FAIL_CPU ( " AVX " ) ;
# endif
}
2019-05-31 07:02:44 +02:00
static void retroarch_main_init_media ( enum rarch_content_type cont_type ,
bool builtin_mediaplayer , bool builtin_imageviewer )
2016-09-11 19:57:06 +02:00
{
2019-05-31 07:02:44 +02:00
switch ( cont_type )
2016-09-11 19:57:06 +02:00
{
case RARCH_CONTENT_MOVIE :
case RARCH_CONTENT_MUSIC :
2017-04-28 13:43:47 +02:00
if ( builtin_mediaplayer )
2016-09-11 19:57:06 +02:00
{
2019-05-31 07:02:44 +02:00
/* TODO/FIXME - it needs to become possible to
* switch between FFmpeg and MPV at runtime */
2018-06-20 04:29:31 +02:00
# if defined(HAVE_MPV)
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO , NULL ) ;
retroarch_set_current_core_type ( CORE_TYPE_MPV , false ) ;
# elif defined(HAVE_FFMPEG)
2016-10-01 05:51:03 +02:00
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO , NULL ) ;
2016-09-11 19:57:06 +02:00
retroarch_set_current_core_type ( CORE_TYPE_FFMPEG , false ) ;
# endif
}
break ;
# ifdef HAVE_IMAGEVIEWER
case RARCH_CONTENT_IMAGE :
2017-04-28 13:43:47 +02:00
if ( builtin_imageviewer )
2016-09-11 19:57:06 +02:00
{
2016-10-01 05:51:03 +02:00
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO , NULL ) ;
2016-09-11 19:57:06 +02:00
retroarch_set_current_core_type ( CORE_TYPE_IMAGEVIEWER , false ) ;
}
break ;
2019-01-05 18:33:29 -05:00
# endif
# ifdef HAVE_EASTEREGG
case RARCH_CONTENT_GONG :
retroarch_override_setting_set ( RARCH_OVERRIDE_SETTING_LIBRETRO , NULL ) ;
retroarch_set_current_core_type ( CORE_TYPE_GONG , false ) ;
break ;
2016-09-11 19:57:06 +02:00
# endif
default :
break ;
}
}
2015-01-11 02:21:18 +01:00
/**
2016-05-09 07:09:26 +02:00
* retroarch_main_init :
2015-01-11 02:21:18 +01:00
* @ argc : Count of ( commandline ) arguments .
2015-10-19 19:43:21 -05:00
* @ argv : ( Commandline ) arguments .
2015-01-11 02:21:18 +01:00
*
2015-06-30 15:26:14 +02:00
* Initializes the program .
2015-01-11 02:21:18 +01:00
*
2017-12-29 15:31:17 +01:00
* Returns : true on success , otherwise false if there was an error .
2015-01-11 02:21:18 +01:00
* */
2016-05-11 20:50:34 +02:00
bool retroarch_main_init ( int argc , char * argv [ ] )
2012-01-14 16:08:54 +01:00
{
2019-04-22 03:08:30 +02:00
bool init_failed = false ;
2019-06-17 15:37:34 +02:00
global_t * global = & g_extern ;
2018-12-10 20:03:03 -05:00
# if defined(DEBUG) && defined(HAVE_DRMINGW)
char log_file_name [ 128 ] ;
# endif
2019-06-17 13:06:56 +02:00
video_driver_set_active ( ) ;
audio_driver_active = true ;
2011-12-25 21:39:58 +01:00
2016-05-16 08:46:06 +02:00
if ( setjmp ( error_sjlj_context ) > 0 )
2012-01-14 16:08:54 +01:00
{
2016-06-20 03:54:42 +02:00
RARCH_ERR ( " %s: \" %s \" \n " ,
msg_hash_to_str ( MSG_FATAL_ERROR_RECEIVED_IN ) , error_string ) ;
2016-05-11 20:50:34 +02:00
return false ;
2012-01-14 16:08:54 +01:00
}
2015-11-30 19:30:05 +01:00
2017-05-08 03:59:02 +02:00
rarch_error_on_init = true ;
2019-03-21 16:56:24 +00:00
/* Have to initialise non-file logging once at the start... */
retro_main_log_file_init ( NULL , false ) ;
2018-03-09 17:23:34 -05:00
retroarch_parse_input_and_config ( argc , argv ) ;
2012-05-04 00:14:42 +02:00
2016-05-31 04:42:04 +02:00
if ( verbosity_is_enabled ( ) )
2011-12-25 21:39:58 +01:00
{
2017-09-09 06:21:27 +02:00
char str [ 128 ] ;
2019-02-23 16:50:36 -05:00
const char * cpu_model = NULL ;
2016-10-21 05:57:40 +02:00
str [ 0 ] = ' \0 ' ;
2015-04-16 20:17:05 +02:00
2019-02-23 16:50:36 -05:00
cpu_model = frontend_driver_get_cpu_model_name ( ) ;
2016-05-24 21:40:44 -05:00
RARCH_LOG_OUTPUT ( " === Build ======================================= \n " ) ;
2019-02-23 16:50:36 -05:00
if ( ! string_is_empty ( cpu_model ) )
RARCH_LOG_OUTPUT ( " CPU Model Name: %s \n " , cpu_model ) ;
2016-05-09 07:09:26 +02:00
retroarch_get_capabilities ( RARCH_CAPABILITIES_CPU , str , sizeof ( str ) ) ;
2019-03-21 16:56:24 +00:00
RARCH_LOG_OUTPUT ( " %s: %s \n " , msg_hash_to_str ( MSG_CAPABILITIES ) , str ) ;
RARCH_LOG_OUTPUT ( " Built: %s \n " , __DATE__ ) ;
2014-01-11 18:51:42 +01:00
RARCH_LOG_OUTPUT ( " Version: %s \n " , PACKAGE_VERSION ) ;
# ifdef HAVE_GIT_VERSION
2016-05-11 20:44:24 +02:00
RARCH_LOG_OUTPUT ( " Git: %s \n " , retroarch_git_version ) ;
2014-01-11 18:51:42 +01:00
# endif
2012-10-16 13:57:35 +02:00
RARCH_LOG_OUTPUT ( " ================================================= \n " ) ;
2011-12-25 21:39:58 +01:00
}
2018-12-10 20:03:03 -05:00
# if defined(DEBUG) && defined(HAVE_DRMINGW)
RARCH_LOG ( " Initializing Dr.MingW Exception handler \n " ) ;
fill_str_dated_filename ( log_file_name , " crash " ,
" log " , sizeof ( log_file_name ) ) ;
ExcHndlInit ( ) ;
ExcHndlSetLogFileNameA ( log_file_name ) ;
# endif
2016-05-11 21:48:30 +02:00
retroarch_validate_cpu_features ( ) ;
2016-02-09 17:41:19 +01:00
2017-05-15 05:06:23 +02:00
rarch_ctl ( RARCH_CTL_TASK_INIT , NULL ) ;
2010-12-30 13:54:49 +01:00
2019-05-31 07:02:44 +02:00
{
const char * fullpath = path_get ( RARCH_PATH_CONTENT ) ;
2019-05-31 09:06:48 +02:00
if ( ! string_is_empty ( fullpath ) )
2019-05-31 07:02:44 +02:00
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-05-31 07:02:44 +02:00
bool builtin_imageviewer = false ;
bool builtin_mediaplayer = false ;
enum rarch_content_type cont_type = path_is_media_type ( fullpath ) ;
if ( settings )
{
builtin_imageviewer = settings - > bools . multimedia_builtin_imageviewer_enable ;
builtin_mediaplayer = settings - > bools . multimedia_builtin_mediaplayer_enable ;
}
retroarch_main_init_media ( cont_type , builtin_mediaplayer ,
builtin_imageviewer ) ;
}
}
2016-07-19 06:20:19 +02:00
2019-02-27 16:47:39 +01:00
/* Pre-initialize all drivers
* Attempts to find a default driver for
* all driver types .
*/
audio_driver_find_driver ( ) ;
video_driver_find_driver ( ) ;
input_driver_find_driver ( ) ;
2019-06-17 11:29:05 +02:00
camera_driver_find_driver ( ) ;
2019-02-27 16:47:39 +01:00
wifi_driver_ctl ( RARCH_WIFI_CTL_FIND_DRIVER , NULL ) ;
find_location_driver ( ) ;
# ifdef HAVE_MENU
menu_driver_ctl ( RARCH_MENU_CTL_FIND_DRIVER , NULL ) ;
# endif
2016-07-19 06:20:19 +02:00
2016-07-19 14:27:46 +10:00
/* Attempt to initialize core */
2016-10-03 16:42:08 +02:00
if ( has_set_core )
2016-05-27 21:16:25 +02:00
{
2016-10-03 16:42:08 +02:00
has_set_core = false ;
2016-05-27 21:16:25 +02:00
if ( ! command_event ( CMD_EVENT_CORE_INIT , & explicit_current_core_type ) )
2016-07-19 14:27:46 +10:00
init_failed = true ;
2016-05-27 21:16:25 +02:00
}
else if ( ! command_event ( CMD_EVENT_CORE_INIT , & current_core_type ) )
2016-07-19 14:27:46 +10:00
init_failed = true ;
/* Handle core initialization failure */
2016-07-19 06:33:56 +02:00
if ( init_failed )
{
2016-07-19 14:27:46 +10:00
/* Check if menu was active prior to core initialization */
2019-01-09 08:39:31 -08:00
if ( ! content_launched_from_cli ( )
# ifdef HAVE_MENU
| | menu_driver_is_alive ( )
# endif
)
2016-07-19 06:33:56 +02:00
{
2016-09-11 19:53:34 +02:00
/* Attempt initializing dummy core */
2016-07-19 06:33:56 +02:00
current_core_type = CORE_TYPE_DUMMY ;
if ( ! command_event ( CMD_EVENT_CORE_INIT , & current_core_type ) )
2016-07-19 14:27:46 +10:00
goto error ;
2016-07-19 06:33:56 +02:00
}
else
{
2016-07-19 14:27:46 +10:00
/* Fall back to regular error handling */
goto error ;
}
2016-07-19 06:20:19 +02:00
}
2010-10-01 21:39:15 +02:00
2018-07-25 19:19:14 -04:00
command_event ( CMD_EVENT_CHEATS_INIT , NULL ) ;
2017-01-16 22:04:57 +01:00
drivers_init ( DRIVERS_CMD_ALL ) ;
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_COMMAND_INIT , NULL ) ;
command_event ( CMD_EVENT_REMOTE_INIT , NULL ) ;
2017-11-24 22:18:08 +01:00
command_event ( CMD_EVENT_MAPPER_INIT , NULL ) ;
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_REWIND_INIT , NULL ) ;
command_event ( CMD_EVENT_CONTROLLERS_INIT , NULL ) ;
2018-09-15 17:44:46 -05:00
if ( ! string_is_empty ( global - > record . path ) )
command_event ( CMD_EVENT_RECORD_INIT , NULL ) ;
2016-09-19 03:03:31 +02:00
path_init_savefile ( ) ;
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_SET_PER_GAME_RESOLUTION , NULL ) ;
2014-10-13 07:35:18 +02:00
2017-05-08 03:59:02 +02:00
rarch_error_on_init = false ;
rarch_is_inited = true ;
2016-05-11 20:50:34 +02:00
2018-05-28 23:43:30 -05:00
# ifdef HAVE_DISCORD
2018-05-29 12:41:13 +02:00
if ( command_event ( CMD_EVENT_DISCORD_INIT , NULL ) )
discord_is_inited = true ;
2018-05-29 11:06:43 +02:00
if ( discord_is_inited )
2018-05-29 12:41:13 +02:00
{
discord_userdata_t userdata ;
userdata . status = DISCORD_PRESENCE_MENU ;
command_event ( CMD_EVENT_DISCORD_UPDATE , & userdata ) ;
}
2018-05-28 23:43:30 -05:00
# endif
2019-01-27 11:22:16 -05:00
# ifdef HAVE_MENU
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-01-27 11:22:16 -05:00
if ( settings - > bools . audio_enable_menu )
audio_driver_load_menu_sounds ( ) ;
}
# endif
2016-05-11 20:50:34 +02:00
return true ;
2011-08-13 04:09:08 +02:00
2012-01-14 14:08:43 +01:00
error :
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_CORE_DEINIT , NULL ) ;
2017-05-08 03:59:02 +02:00
rarch_is_inited = false ;
2018-04-30 14:33:05 -04:00
2016-05-11 20:50:34 +02:00
return false ;
2012-01-14 14:08:43 +01:00
}
2017-05-12 03:39:37 +02:00
bool retroarch_is_on_main_thread ( void )
2014-09-03 18:16:49 +02:00
{
2016-10-17 21:21:51 -03:00
# ifdef HAVE_THREAD_STORAGE
2017-05-12 03:39:37 +02:00
if ( sthread_tls_get ( & rarch_tls ) ! = MAGIC_POINTER )
return false ;
2016-10-17 20:50:19 -03:00
# endif
2017-05-12 03:39:37 +02:00
return true ;
}
2015-03-18 06:47:22 +01:00
2017-05-15 04:31:40 +02:00
void rarch_menu_running ( void )
{
2019-06-14 05:08:04 +02:00
# if defined(HAVE_MENU) || defined(HAVE_OVERLAY)
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-14 05:08:04 +02:00
# endif
2017-05-15 04:31:40 +02:00
# ifdef HAVE_MENU
menu_driver_ctl ( RARCH_MENU_CTL_SET_TOGGLE , NULL ) ;
2019-01-27 11:22:16 -05:00
2017-05-17 05:06:52 +02:00
/* Prevent stray input */
input_driver_set_flushing_input ( ) ;
2019-01-27 11:22:16 -05:00
if ( settings & & settings - > bools . audio_enable_menu & & settings - > bools . audio_enable_menu_bgm )
audio_driver_mixer_play_menu_sound_looped ( AUDIO_MIXER_SYSTEM_SLOT_BGM ) ;
2017-05-15 04:31:40 +02:00
# endif
# ifdef HAVE_OVERLAY
2019-01-27 11:22:16 -05:00
if ( settings & & settings - > bools . input_overlay_hide_in_menu )
command_event ( CMD_EVENT_OVERLAY_DEINIT , NULL ) ;
2017-05-15 04:31:40 +02:00
# endif
}
void rarch_menu_running_finished ( void )
{
2019-06-14 05:08:04 +02:00
# if defined(HAVE_MENU) || defined(HAVE_OVERLAY)
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-06-14 05:08:04 +02:00
# endif
2017-05-15 04:31:40 +02:00
# ifdef HAVE_MENU
menu_driver_ctl ( RARCH_MENU_CTL_UNSET_TOGGLE , NULL ) ;
2019-01-27 11:22:16 -05:00
2017-05-17 05:06:52 +02:00
/* Prevent stray input */
input_driver_set_flushing_input ( ) ;
2019-01-27 11:22:16 -05:00
2019-02-28 21:54:46 +01:00
/* Stop menu background music before we exit the menu */
2019-01-27 11:22:16 -05:00
if ( settings & & settings - > bools . audio_enable_menu & & settings - > bools . audio_enable_menu_bgm )
audio_driver_mixer_stop_stream ( AUDIO_MIXER_SYSTEM_SLOT_BGM ) ;
2017-05-15 04:31:40 +02:00
# endif
video_driver_set_texture_enable ( false , false ) ;
# ifdef HAVE_OVERLAY
2019-01-27 11:22:16 -05:00
if ( settings & & settings - > bools . input_overlay_hide_in_menu )
command_event ( CMD_EVENT_OVERLAY_INIT , NULL ) ;
2017-05-15 04:31:40 +02:00
# endif
}
2017-05-15 05:06:23 +02:00
/**
* rarch_game_specific_options :
*
* Returns : true ( 1 ) if a game specific core
* options path has been found ,
* otherwise false ( 0 ) .
* */
static bool rarch_game_specific_options ( char * * output )
{
2017-09-09 06:31:51 +02:00
size_t game_path_size = 8192 * sizeof ( char ) ;
2018-10-29 07:38:26 +01:00
char * game_path = ( char * ) malloc ( game_path_size ) ;
2017-05-15 05:06:23 +02:00
game_path [ 0 ] = ' \0 ' ;
if ( ! retroarch_validate_game_options ( game_path ,
2017-09-09 06:31:51 +02:00
game_path_size , false ) )
2017-11-18 10:48:53 -05:00
goto error ;
2017-05-15 05:06:23 +02:00
if ( ! config_file_exists ( game_path ) )
2017-11-18 10:48:53 -05:00
goto error ;
2017-05-15 05:06:23 +02:00
RARCH_LOG ( " %s %s \n " ,
msg_hash_to_str ( MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT ) ,
game_path ) ;
* output = strdup ( game_path ) ;
2017-09-09 06:31:51 +02:00
free ( game_path ) ;
2017-05-15 05:06:23 +02:00
return true ;
2017-09-09 06:31:51 +02:00
error :
free ( game_path ) ;
return false ;
2017-05-15 05:06:23 +02:00
}
2017-05-12 03:39:37 +02:00
bool rarch_ctl ( enum rarch_ctl_state state , void * data )
{
2019-01-14 05:25:04 +01:00
static bool has_set_username = false ;
2019-01-12 17:58:35 +01:00
static bool rarch_block_config_read = false ;
static bool rarch_patch_blocked = false ;
2019-06-14 05:08:04 +02:00
static bool runloop_missing_bios = false ;
/* TODO/FIXME - not used right now? */
2019-01-12 17:58:35 +01:00
2015-09-27 01:58:24 +02:00
switch ( state )
2014-09-03 18:16:49 +02:00
{
2019-06-17 11:57:46 +02:00
case RARCH_CTL_LOCATION_SET_ACTIVE :
location_driver_active = true ;
break ;
case RARCH_CTL_LOCATION_UNSET_ACTIVE :
location_driver_active = false ;
break ;
2019-06-17 11:38:28 +02:00
case RARCH_CTL_BSV_MOVIE_IS_INITED :
return ( bsv_movie_state_handle ! = NULL ) ;
2016-09-29 05:36:21 +02:00
case RARCH_CTL_IS_PATCH_BLOCKED :
return rarch_patch_blocked ;
case RARCH_CTL_SET_PATCH_BLOCKED :
rarch_patch_blocked = true ;
break ;
case RARCH_CTL_UNSET_PATCH_BLOCKED :
rarch_patch_blocked = false ;
break ;
case RARCH_CTL_IS_BPS_PREF :
return rarch_bps_pref ;
case RARCH_CTL_UNSET_BPS_PREF :
rarch_bps_pref = false ;
break ;
case RARCH_CTL_IS_UPS_PREF :
return rarch_ups_pref ;
case RARCH_CTL_UNSET_UPS_PREF :
rarch_ups_pref = false ;
break ;
case RARCH_CTL_IS_IPS_PREF :
return rarch_ips_pref ;
case RARCH_CTL_UNSET_IPS_PREF :
rarch_ips_pref = false ;
break ;
2016-01-19 23:44:32 +01:00
case RARCH_CTL_IS_DUMMY_CORE :
2016-01-20 03:15:50 +01:00
return ( current_core_type = = CORE_TYPE_DUMMY ) ;
2016-04-06 00:30:21 +02:00
case RARCH_CTL_USERNAME_SET :
has_set_username = true ;
break ;
case RARCH_CTL_USERNAME_UNSET :
has_set_username = false ;
break ;
case RARCH_CTL_HAS_SET_USERNAME :
return has_set_username ;
2016-01-19 23:26:47 +01:00
case RARCH_CTL_IS_INITED :
return rarch_is_inited ;
2015-12-07 15:03:54 +01:00
case RARCH_CTL_DESTROY :
2016-04-10 16:40:36 +02:00
has_set_username = false ;
rarch_is_inited = false ;
rarch_error_on_init = false ;
2019-01-12 17:58:35 +01:00
rarch_ctl ( RARCH_CTL_UNSET_BLOCK_CONFIG_READ , NULL ) ;
2016-04-10 16:40:36 +02:00
2017-05-11 09:20:35 +02:00
retroarch_msg_queue_deinit ( ) ;
2017-05-28 15:03:03 +02:00
driver_uninit ( DRIVERS_CMD_ALL ) ;
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_LOG_FILE_DEINIT , NULL ) ;
2016-04-10 16:40:36 +02:00
2017-05-15 05:06:23 +02:00
rarch_ctl ( RARCH_CTL_STATE_FREE , NULL ) ;
2017-05-11 09:20:35 +02:00
global_free ( ) ;
2017-05-15 05:06:23 +02:00
rarch_ctl ( RARCH_CTL_DATA_DEINIT , NULL ) ;
2019-06-17 16:58:43 +02:00
free ( configuration_settings ) ;
configuration_settings = NULL ;
2016-01-30 05:03:15 +01:00
break ;
2015-12-07 15:01:53 +01:00
case RARCH_CTL_PREINIT :
2017-05-30 01:44:49 +02:00
libretro_free_system_info ( & runloop_system . info ) ;
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_HISTORY_DEINIT , NULL ) ;
2016-05-27 05:05:27 +02:00
2019-06-17 16:58:43 +02:00
configuration_settings = ( settings_t * ) calloc ( 1 , sizeof ( settings_t ) ) ;
2015-12-07 15:01:53 +01:00
2017-05-11 09:20:35 +02:00
driver_ctl ( RARCH_DRIVER_CTL_DEINIT , NULL ) ;
2017-05-15 05:06:23 +02:00
rarch_ctl ( RARCH_CTL_STATE_FREE , NULL ) ;
2017-05-11 09:20:35 +02:00
global_free ( ) ;
2016-01-30 05:03:15 +01:00
break ;
case RARCH_CTL_MAIN_DEINIT :
2019-02-27 16:47:39 +01:00
if ( ! rarch_is_inited )
2016-01-30 05:03:15 +01:00
return false ;
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_NETPLAY_DEINIT , NULL ) ;
command_event ( CMD_EVENT_COMMAND_DEINIT , NULL ) ;
command_event ( CMD_EVENT_REMOTE_DEINIT , NULL ) ;
2017-09-07 22:30:42 -05:00
command_event ( CMD_EVENT_MAPPER_DEINIT , NULL ) ;
2016-04-10 15:52:06 +02:00
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_AUTOSAVE_DEINIT , NULL ) ;
2016-04-10 15:52:06 +02:00
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_RECORD_DEINIT , NULL ) ;
2016-09-19 04:09:27 +02:00
event_save_files ( ) ;
2016-04-10 15:52:06 +02:00
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_REWIND_DEINIT , NULL ) ;
command_event ( CMD_EVENT_CHEATS_DEINIT , NULL ) ;
command_event ( CMD_EVENT_BSV_MOVIE_DEINIT , NULL ) ;
2016-04-10 15:52:06 +02:00
2016-05-09 20:51:53 +02:00
command_event ( CMD_EVENT_CORE_DEINIT , NULL ) ;
2016-04-10 15:52:06 +02:00
2017-05-27 03:43:53 +02:00
content_deinit ( ) ;
2016-09-19 03:03:31 +02:00
2016-09-25 15:49:09 +02:00
path_deinit_subsystem ( ) ;
2016-09-19 03:03:31 +02:00
path_deinit_savefile ( ) ;
2016-04-10 15:52:06 +02:00
2017-05-08 03:59:02 +02:00
rarch_is_inited = false ;
2016-10-17 20:50:19 -03:00
2016-10-17 21:21:51 -03:00
# ifdef HAVE_THREAD_STORAGE
2016-10-17 20:50:19 -03:00
sthread_tls_delete ( & rarch_tls ) ;
# endif
2016-01-30 05:03:15 +01:00
break ;
2015-12-07 14:59:09 +01:00
case RARCH_CTL_INIT :
2019-02-27 16:47:39 +01:00
if ( rarch_is_inited )
2017-05-28 15:03:03 +02:00
driver_uninit ( DRIVERS_CMD_ALL ) ;
2017-05-12 03:39:37 +02:00
2016-10-17 21:21:51 -03:00
# ifdef HAVE_THREAD_STORAGE
2016-10-17 20:50:19 -03:00
sthread_tls_create ( & rarch_tls ) ;
sthread_tls_set ( & rarch_tls , MAGIC_POINTER ) ;
# endif
2019-06-17 13:06:56 +02:00
video_driver_set_active ( ) ;
audio_driver_active = true ;
2015-12-07 14:59:09 +01:00
{
2017-09-09 06:31:51 +02:00
uint8_t i ;
2015-12-07 14:59:09 +01:00
for ( i = 0 ; i < MAX_USERS ; i + + )
2017-01-17 19:59:33 +01:00
input_config_set_device ( i , RETRO_DEVICE_JOYPAD ) ;
2015-12-07 14:59:09 +01:00
}
2017-05-15 05:06:23 +02:00
rarch_ctl ( RARCH_CTL_HTTPSERVER_INIT , NULL ) ;
2017-05-11 09:20:35 +02:00
retroarch_msg_queue_init ( ) ;
2016-01-30 05:03:15 +01:00
break ;
2016-09-28 07:23:14 +02:00
case RARCH_CTL_IS_SRAM_LOAD_DISABLED :
return rarch_is_sram_load_disabled ;
case RARCH_CTL_IS_SRAM_SAVE_DISABLED :
return rarch_is_sram_save_disabled ;
2016-09-28 07:17:14 +02:00
case RARCH_CTL_IS_SRAM_USED :
return rarch_use_sram ;
2016-01-27 19:53:07 +01:00
case RARCH_CTL_SET_SRAM_ENABLE :
2017-01-25 15:44:21 +01:00
{
bool contentless = false ;
2017-01-25 15:51:57 +01:00
bool is_inited = false ;
content_get_status ( & contentless , & is_inited ) ;
2017-05-12 03:39:37 +02:00
rarch_use_sram = ( current_core_type = = CORE_TYPE_PLAIN )
2017-01-25 15:44:21 +01:00
& & ! contentless ;
}
2016-09-28 07:17:14 +02:00
break ;
case RARCH_CTL_SET_SRAM_ENABLE_FORCE :
rarch_use_sram = true ;
break ;
case RARCH_CTL_UNSET_SRAM_ENABLE :
rarch_use_sram = false ;
2016-01-27 19:53:07 +01:00
break ;
2015-11-30 22:09:28 +01:00
case RARCH_CTL_SET_BLOCK_CONFIG_READ :
rarch_block_config_read = true ;
break ;
case RARCH_CTL_UNSET_BLOCK_CONFIG_READ :
rarch_block_config_read = false ;
break ;
case RARCH_CTL_IS_BLOCK_CONFIG_READ :
return rarch_block_config_read ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SYSTEM_INFO_INIT :
2017-05-30 01:44:49 +02:00
core_get_system_info ( & runloop_system . info ) ;
2015-09-27 02:04:53 +02:00
2017-05-30 01:44:49 +02:00
if ( ! runloop_system . info . library_name )
runloop_system . info . library_name = msg_hash_to_str ( MSG_UNKNOWN ) ;
if ( ! runloop_system . info . library_version )
runloop_system . info . library_version = " v0 " ;
2014-09-03 18:16:49 +02:00
2017-05-30 01:44:49 +02:00
video_driver_set_title_buf ( ) ;
2016-08-01 20:47:19 +02:00
2017-05-30 01:44:49 +02:00
strlcpy ( runloop_system . valid_extensions ,
runloop_system . info . valid_extensions ?
runloop_system . info . valid_extensions : DEFAULT_EXT ,
sizeof ( runloop_system . valid_extensions ) ) ;
2017-05-15 05:06:23 +02:00
break ;
case RARCH_CTL_GET_CORE_OPTION_SIZE :
2016-10-01 06:06:07 +02:00
{
2017-05-15 05:06:23 +02:00
unsigned * idx = ( unsigned * ) data ;
if ( ! idx )
return false ;
* idx = ( unsigned ) core_option_manager_size ( runloop_core_options ) ;
2016-10-01 06:06:07 +02:00
}
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_HAS_CORE_OPTIONS :
2017-10-03 00:53:09 +02:00
return ( runloop_core_options ! = NULL ) ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_CORE_OPTIONS_LIST_GET :
2016-10-01 06:02:18 +02:00
{
2017-05-15 05:06:23 +02:00
core_option_manager_t * * coreopts = ( core_option_manager_t * * ) data ;
if ( ! coreopts )
return false ;
* coreopts = runloop_core_options ;
2016-10-01 06:02:18 +02:00
}
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SYSTEM_INFO_FREE :
if ( runloop_system . subsystem . data )
free ( runloop_system . subsystem . data ) ;
runloop_system . subsystem . data = NULL ;
runloop_system . subsystem . size = 0 ;
if ( runloop_system . ports . data )
free ( runloop_system . ports . data ) ;
runloop_system . ports . data = NULL ;
runloop_system . ports . size = 0 ;
if ( runloop_system . mmaps . descriptors )
free ( ( void * ) runloop_system . mmaps . descriptors ) ;
runloop_system . mmaps . descriptors = NULL ;
runloop_system . mmaps . num_descriptors = 0 ;
2019-01-10 02:49:25 +01:00
rarch_ctl ( RARCH_CTL_UNSET_KEY_EVENT , NULL ) ;
2017-05-15 05:06:23 +02:00
runloop_frontend_key_event = NULL ;
audio_driver_unset_callback ( ) ;
2017-05-28 17:21:57 +02:00
2017-05-30 01:44:49 +02:00
runloop_system . info . library_name = NULL ;
runloop_system . info . library_version = NULL ;
runloop_system . info . valid_extensions = NULL ;
runloop_system . info . need_fullpath = false ;
runloop_system . info . block_extract = false ;
2017-05-28 17:21:57 +02:00
2017-05-15 05:06:23 +02:00
memset ( & runloop_system , 0 , sizeof ( rarch_system_info_t ) ) ;
2016-08-01 20:54:16 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SET_FRAME_TIME_LAST :
runloop_frame_time_last = 0 ;
2016-08-01 20:47:19 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SET_OVERRIDES_ACTIVE :
runloop_overrides_active = true ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_UNSET_OVERRIDES_ACTIVE :
runloop_overrides_active = false ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_IS_OVERRIDES_ACTIVE :
return runloop_overrides_active ;
2017-08-05 00:37:26 -05:00
case RARCH_CTL_SET_REMAPS_CORE_ACTIVE :
runloop_remaps_core_active = true ;
break ;
case RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE :
runloop_remaps_core_active = false ;
break ;
case RARCH_CTL_IS_REMAPS_CORE_ACTIVE :
return runloop_remaps_core_active ;
case RARCH_CTL_SET_REMAPS_GAME_ACTIVE :
runloop_remaps_game_active = true ;
break ;
case RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE :
runloop_remaps_game_active = false ;
break ;
case RARCH_CTL_IS_REMAPS_GAME_ACTIVE :
return runloop_remaps_game_active ;
2018-05-13 23:17:44 -05:00
case RARCH_CTL_SET_REMAPS_CONTENT_DIR_ACTIVE :
runloop_remaps_content_dir_active = true ;
break ;
case RARCH_CTL_UNSET_REMAPS_CONTENT_DIR_ACTIVE :
runloop_remaps_content_dir_active = false ;
break ;
case RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE :
return runloop_remaps_content_dir_active ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SET_MISSING_BIOS :
runloop_missing_bios = true ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_UNSET_MISSING_BIOS :
runloop_missing_bios = false ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_IS_MISSING_BIOS :
return runloop_missing_bios ;
case RARCH_CTL_IS_GAME_OPTIONS_ACTIVE :
return runloop_game_options_active ;
case RARCH_CTL_SET_FRAME_LIMIT :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2017-05-15 05:06:23 +02:00
struct retro_system_av_info * av_info =
video_viewport_get_system_av_info ( ) ;
float fastforward_ratio =
( settings - > floats . fastforward_ratio = = 0.0f )
? 1.0f : settings - > floats . fastforward_ratio ;
frame_limit_last_time = cpu_features_get_time_usec ( ) ;
frame_limit_minimum_time = ( retro_time_t ) roundf ( 1000000.0f
/ ( av_info - > timing . fps * fastforward_ratio ) ) ;
}
2016-08-01 21:51:23 +02:00
break ;
2019-02-12 00:32:01 -05:00
case RARCH_CTL_CONTENT_RUNTIME_LOG_INIT :
2019-03-06 12:24:35 +00:00
{
const char * content_path = path_get ( RARCH_PATH_CONTENT ) ;
const char * core_path = path_get ( RARCH_PATH_CORE ) ;
2019-03-04 15:30:12 +00:00
libretro_core_runtime_last = cpu_features_get_time_usec ( ) ;
2019-02-12 00:32:01 -05:00
libretro_core_runtime_usec = 0 ;
2019-03-06 12:24:35 +00:00
/* Have to cache content and core path here, otherwise
* logging fails if new content is loaded without
* closing existing content
* i . e . RARCH_PATH_CONTENT and RARCH_PATH_CORE get
* updated when the new content is loaded , which
* happens * before * RARCH_CTL_CONTENT_RUNTIME_LOG_DEINIT
* - > using RARCH_PATH_CONTENT and RARCH_PATH_CORE
* directly in RARCH_CTL_CONTENT_RUNTIME_LOG_DEINIT
* can therefore lead to the runtime of the currently
* loaded content getting written to the * new *
* content ' s log file . . . */
memset ( runtime_content_path , 0 , sizeof ( runtime_content_path ) ) ;
memset ( runtime_core_path , 0 , sizeof ( runtime_core_path ) ) ;
if ( ! string_is_empty ( content_path ) )
strlcpy ( runtime_content_path , content_path , sizeof ( runtime_content_path ) ) ;
if ( ! string_is_empty ( core_path ) )
strlcpy ( runtime_core_path , core_path , sizeof ( runtime_core_path ) ) ;
2019-02-12 00:32:01 -05:00
break ;
2019-03-06 12:24:35 +00:00
}
2019-02-12 00:32:01 -05:00
case RARCH_CTL_CONTENT_RUNTIME_LOG_DEINIT :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
unsigned hours = 0 ;
unsigned minutes = 0 ;
unsigned seconds = 0 ;
2019-02-12 00:32:01 -05:00
char log [ PATH_MAX_LENGTH ] = { 0 } ;
2019-06-17 16:58:43 +02:00
int n = 0 ;
2019-02-12 00:32:01 -05:00
2019-06-17 16:58:43 +02:00
runtime_log_convert_usec2hms (
libretro_core_runtime_usec , & hours , & minutes , & seconds ) ;
2019-02-12 00:32:01 -05:00
2019-02-27 16:19:29 +00:00
n = snprintf ( log , sizeof ( log ) ,
2019-03-03 06:36:53 +08:00
" Content ran for a total of: %02u hours, %02u minutes, %02u seconds. " ,
2019-02-27 16:19:29 +00:00
hours , minutes , seconds ) ;
if ( ( n < 0 ) | | ( n > = PATH_MAX_LENGTH ) )
n = 0 ; /* Just silence any potential gcc warnings... */
2019-03-03 06:36:53 +08:00
RARCH_LOG ( " %s \n " , log ) ;
2019-02-12 00:32:01 -05:00
2019-03-07 12:28:21 +00:00
/* Only write to file if content has run for a non-zero length of time */
if ( libretro_core_runtime_usec > 0 )
2019-02-12 00:32:01 -05:00
{
2019-03-07 12:28:21 +00:00
/* Per core logging */
if ( settings - > bools . content_runtime_log )
update_runtime_log ( true ) ;
2019-02-12 00:32:01 -05:00
2019-03-07 12:28:21 +00:00
/* Aggregate logging */
if ( settings - > bools . content_runtime_log_aggregate )
update_runtime_log ( false ) ;
2019-02-12 00:32:01 -05:00
}
2019-03-06 12:24:35 +00:00
/* Reset runtime + content/core paths, to prevent any
* possibility of duplicate logging */
2019-03-04 11:33:19 +00:00
libretro_core_runtime_usec = 0 ;
2019-03-06 12:24:35 +00:00
memset ( runtime_content_path , 0 , sizeof ( runtime_content_path ) ) ;
memset ( runtime_core_path , 0 , sizeof ( runtime_core_path ) ) ;
2019-03-04 11:33:19 +00:00
2019-02-12 00:32:01 -05:00
break ;
}
2017-05-15 05:06:23 +02:00
case RARCH_CTL_GET_PERFCNT :
{
bool * * perfcnt = ( bool * * ) data ;
if ( ! perfcnt )
return false ;
* perfcnt = & runloop_perfcnt_enable ;
}
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SET_PERFCNT_ENABLE :
runloop_perfcnt_enable = true ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_UNSET_PERFCNT_ENABLE :
runloop_perfcnt_enable = false ;
2016-09-14 23:54:18 -04:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_IS_PERFCNT_ENABLE :
return runloop_perfcnt_enable ;
case RARCH_CTL_SET_NONBLOCK_FORCED :
runloop_force_nonblock = true ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_UNSET_NONBLOCK_FORCED :
runloop_force_nonblock = false ;
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_IS_NONBLOCK_FORCED :
return runloop_force_nonblock ;
case RARCH_CTL_SET_FRAME_TIME :
{
const struct retro_frame_time_callback * info =
( const struct retro_frame_time_callback * ) data ;
# ifdef HAVE_NETWORKING
/* retro_run() will be called in very strange and
* mysterious ways , have to disable it . */
if ( netplay_driver_ctl ( RARCH_NETPLAY_CTL_IS_ENABLED , NULL ) )
return false ;
# endif
runloop_frame_time = * info ;
}
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_GET_WINDOWED_SCALE :
{
unsigned * * scale = ( unsigned * * ) data ;
if ( ! scale )
return false ;
* scale = ( unsigned * ) & runloop_pending_windowed_scale ;
}
2016-08-01 20:41:42 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SET_WINDOWED_SCALE :
2016-10-01 06:14:30 +02:00
{
2017-05-15 05:06:23 +02:00
unsigned * idx = ( unsigned * ) data ;
if ( ! idx )
return false ;
runloop_pending_windowed_scale = * idx ;
2016-10-01 06:14:30 +02:00
}
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_FRAME_TIME_FREE :
memset ( & runloop_frame_time , 0 ,
sizeof ( struct retro_frame_time_callback ) ) ;
runloop_frame_time_last = 0 ;
runloop_max_frames = 0 ;
2016-08-01 20:54:16 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_STATE_FREE :
runloop_perfcnt_enable = false ;
runloop_idle = false ;
runloop_paused = false ;
runloop_slowmotion = false ;
runloop_overrides_active = false ;
runloop_autosave = false ;
rarch_ctl ( RARCH_CTL_FRAME_TIME_FREE , NULL ) ;
2016-08-01 20:47:19 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_IS_IDLE :
return runloop_idle ;
case RARCH_CTL_SET_IDLE :
{
bool * ptr = ( bool * ) data ;
if ( ! ptr )
return false ;
runloop_idle = * ptr ;
}
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_SET_PAUSED :
{
bool * ptr = ( bool * ) data ;
if ( ! ptr )
return false ;
runloop_paused = * ptr ;
}
break ;
case RARCH_CTL_IS_PAUSED :
return runloop_paused ;
case RARCH_CTL_TASK_INIT :
{
# ifdef HAVE_THREADS
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2017-05-15 05:06:23 +02:00
bool threaded_enable = settings - > bools . threaded_data_runloop_enable ;
# else
bool threaded_enable = false ;
# endif
task_queue_deinit ( ) ;
2018-11-22 15:45:52 +01:00
task_queue_init ( threaded_enable , runloop_task_msg_queue_push ) ;
2017-05-15 05:06:23 +02:00
}
break ;
case RARCH_CTL_SET_CORE_SHUTDOWN :
runloop_core_shutdown_initiated = true ;
break ;
case RARCH_CTL_SET_SHUTDOWN :
runloop_shutdown_initiated = true ;
break ;
2019-01-10 02:35:03 +01:00
case RARCH_CTL_UNSET_SHUTDOWN :
runloop_shutdown_initiated = false ;
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_IS_SHUTDOWN :
return runloop_shutdown_initiated ;
case RARCH_CTL_DATA_DEINIT :
task_queue_deinit ( ) ;
break ;
case RARCH_CTL_IS_CORE_OPTION_UPDATED :
if ( ! runloop_core_options )
return false ;
return core_option_manager_updated ( runloop_core_options ) ;
case RARCH_CTL_CORE_OPTION_PREV :
{
unsigned * idx = ( unsigned * ) data ;
if ( ! idx )
return false ;
core_option_manager_prev ( runloop_core_options , * idx ) ;
}
break ;
case RARCH_CTL_CORE_OPTION_NEXT :
{
unsigned * idx = ( unsigned * ) data ;
if ( ! idx )
return false ;
core_option_manager_next ( runloop_core_options , * idx ) ;
}
break ;
case RARCH_CTL_CORE_OPTIONS_GET :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-04-28 01:55:49 +02:00
unsigned log_level = settings - > uints . libretro_log_level ;
2017-05-15 05:06:23 +02:00
struct retro_variable * var = ( struct retro_variable * ) data ;
if ( ! runloop_core_options | | ! var )
return false ;
core_option_manager_get ( runloop_core_options , var ) ;
2019-04-28 01:55:49 +02:00
if ( log_level = = RETRO_LOG_DEBUG )
{
RARCH_LOG ( " Environ GET_VARIABLE %s: \n " , var - > key ) ;
RARCH_LOG ( " \t %s \n " , var - > value ? var - > value :
msg_hash_to_str ( MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE ) ) ;
}
2017-05-15 05:06:23 +02:00
}
break ;
case RARCH_CTL_CORE_OPTIONS_INIT :
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2017-05-15 05:06:23 +02:00
char * game_options_path = NULL ;
bool ret = false ;
const struct retro_variable * vars =
( const struct retro_variable * ) data ;
if ( settings & & settings - > bools . game_specific_options )
ret = rarch_game_specific_options ( & game_options_path ) ;
2018-09-26 14:03:29 +02:00
if ( ret )
2017-05-15 05:06:23 +02:00
{
runloop_game_options_active = true ;
runloop_core_options =
core_option_manager_new ( game_options_path , vars ) ;
free ( game_options_path ) ;
}
else
{
char buf [ PATH_MAX_LENGTH ] ;
const char * options_path = NULL ;
buf [ 0 ] = ' \0 ' ;
if ( settings )
options_path = settings - > paths . path_core_options ;
if ( string_is_empty ( options_path ) & & ! path_is_empty ( RARCH_PATH_CONFIG ) )
{
fill_pathname_resolve_relative ( buf , path_get ( RARCH_PATH_CONFIG ) ,
file_path_str ( FILE_PATH_CORE_OPTIONS_CONFIG ) , sizeof ( buf ) ) ;
options_path = buf ;
}
runloop_game_options_active = false ;
if ( ! string_is_empty ( options_path ) )
runloop_core_options =
core_option_manager_new ( options_path , vars ) ;
}
}
break ;
case RARCH_CTL_CORE_OPTIONS_DEINIT :
{
if ( ! runloop_core_options )
return false ;
/* check if game options file was just created and flush
to that file instead */
2018-09-26 14:03:29 +02:00
if ( ! path_is_empty ( RARCH_PATH_CORE_OPTIONS ) )
2017-05-15 05:06:23 +02:00
{
core_option_manager_flush_game_specific ( runloop_core_options ,
path_get ( RARCH_PATH_CORE_OPTIONS ) ) ;
path_clear ( RARCH_PATH_CORE_OPTIONS ) ;
}
else
core_option_manager_flush ( runloop_core_options ) ;
if ( runloop_game_options_active )
runloop_game_options_active = false ;
if ( runloop_core_options )
core_option_manager_free ( runloop_core_options ) ;
runloop_core_options = NULL ;
}
break ;
case RARCH_CTL_KEY_EVENT_GET :
{
retro_keyboard_event_t * * key_event =
( retro_keyboard_event_t * * ) data ;
if ( ! key_event )
return false ;
* key_event = & runloop_key_event ;
}
break ;
2019-01-10 02:49:25 +01:00
case RARCH_CTL_UNSET_KEY_EVENT :
runloop_key_event = NULL ;
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_FRONTEND_KEY_EVENT_GET :
{
retro_keyboard_event_t * * key_event =
( retro_keyboard_event_t * * ) data ;
if ( ! key_event )
return false ;
* key_event = & runloop_frontend_key_event ;
}
break ;
case RARCH_CTL_HTTPSERVER_INIT :
# if defined(HAVE_HTTPSERVER) && defined(HAVE_ZLIB)
httpserver_init ( 8888 ) ;
# endif
break ;
case RARCH_CTL_HTTPSERVER_DESTROY :
# if defined(HAVE_HTTPSERVER) && defined(HAVE_ZLIB)
httpserver_destroy ( ) ;
# endif
break ;
2019-06-17 11:38:28 +02:00
case RARCH_CTL_CAMERA_SET_ACTIVE :
camera_driver_active = true ;
break ;
case RARCH_CTL_CAMERA_UNSET_ACTIVE :
camera_driver_active = false ;
break ;
case RARCH_CTL_CAMERA_SET_CB :
{
struct retro_camera_callback * cb =
( struct retro_camera_callback * ) data ;
camera_cb = * cb ;
}
break ;
2017-05-15 05:06:23 +02:00
case RARCH_CTL_NONE :
default :
return false ;
}
return true ;
}
bool retroarch_is_forced_fullscreen ( void )
{
return rarch_force_fullscreen ;
}
2017-12-17 12:56:26 -05:00
void retroarch_unset_forced_fullscreen ( void )
{
rarch_force_fullscreen = false ;
}
2018-12-11 19:34:12 -05:00
bool retroarch_is_switching_display_mode ( void )
{
return rarch_is_switching_display_mode ;
}
void retroarch_set_switching_display_mode ( void )
{
rarch_is_switching_display_mode = true ;
}
void retroarch_unset_switching_display_mode ( void )
{
rarch_is_switching_display_mode = false ;
}
2018-01-29 22:11:08 -05:00
/* set a runtime shader preset without overwriting the settings value */
2018-01-30 22:11:09 -05:00
void retroarch_set_shader_preset ( const char * preset )
2018-01-29 22:11:08 -05:00
{
if ( ! string_is_empty ( preset ) )
strlcpy ( runtime_shader_preset , preset , sizeof ( runtime_shader_preset ) ) ;
else
runtime_shader_preset [ 0 ] = ' \0 ' ;
}
/* unset a runtime shader preset */
void retroarch_unset_shader_preset ( void )
{
runtime_shader_preset [ 0 ] = ' \0 ' ;
}
/* get the name of the current shader preset */
char * retroarch_get_shader_preset ( void )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2018-01-29 22:11:08 -05:00
if ( ! settings - > bools . video_shader_enable )
2018-01-30 22:38:03 -05:00
return NULL ;
2018-01-29 22:11:08 -05:00
if ( ! string_is_empty ( runtime_shader_preset ) )
return runtime_shader_preset ;
else if ( ! string_is_empty ( settings - > paths . path_shader ) )
return settings - > paths . path_shader ;
2018-10-11 03:26:39 +02:00
return NULL ;
2018-01-29 22:11:08 -05:00
}
2017-05-15 05:06:23 +02:00
bool retroarch_override_setting_is_set ( enum rarch_override_setting enum_idx , void * data )
{
switch ( enum_idx )
{
case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE :
{
unsigned * val = ( unsigned * ) data ;
if ( val )
{
unsigned bit = * val ;
2017-12-05 12:07:35 +01:00
return BIT256_GET ( has_set_libretro_device , bit ) ;
2017-05-15 05:06:23 +02:00
}
}
2016-08-01 21:51:23 +02:00
break ;
2017-05-15 05:06:23 +02:00
case RARCH_OVERRIDE_SETTING_VERBOSITY :
return has_set_verbosity ;
case RARCH_OVERRIDE_SETTING_LIBRETRO :
return has_set_libretro ;
case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY :
return has_set_libretro_directory ;
case RARCH_OVERRIDE_SETTING_SAVE_PATH :
return has_set_save_path ;
2016-08-01 21:51:23 +02:00
case RARCH_OVERRIDE_SETTING_STATE_PATH :
2017-05-15 05:06:23 +02:00
return has_set_state_path ;
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE :
return has_set_netplay_mode ;
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS :
return has_set_netplay_ip_address ;
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT :
return has_set_netplay_ip_port ;
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE :
return has_set_netplay_stateless_mode ;
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES :
return has_set_netplay_check_frames ;
case RARCH_OVERRIDE_SETTING_UPS_PREF :
return has_set_ups_pref ;
case RARCH_OVERRIDE_SETTING_BPS_PREF :
return has_set_bps_pref ;
case RARCH_OVERRIDE_SETTING_IPS_PREF :
return has_set_ips_pref ;
2019-05-17 17:19:13 +01:00
case RARCH_OVERRIDE_SETTING_LOG_TO_FILE :
return has_set_log_to_file ;
2017-05-15 05:06:23 +02:00
case RARCH_OVERRIDE_SETTING_NONE :
default :
break ;
}
return false ;
}
void retroarch_override_setting_set ( enum rarch_override_setting enum_idx , void * data )
{
switch ( enum_idx )
{
case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE :
{
unsigned * val = ( unsigned * ) data ;
if ( val )
{
unsigned bit = * val ;
2017-12-05 12:07:35 +01:00
BIT256_SET ( has_set_libretro_device , bit ) ;
2017-05-15 05:06:23 +02:00
}
}
break ;
case RARCH_OVERRIDE_SETTING_VERBOSITY :
has_set_verbosity = true ;
break ;
case RARCH_OVERRIDE_SETTING_LIBRETRO :
has_set_libretro = true ;
break ;
case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY :
has_set_libretro_directory = true ;
break ;
case RARCH_OVERRIDE_SETTING_SAVE_PATH :
has_set_save_path = true ;
break ;
case RARCH_OVERRIDE_SETTING_STATE_PATH :
has_set_state_path = true ;
2016-08-01 21:51:23 +02:00
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE :
2017-05-15 05:06:23 +02:00
has_set_netplay_mode = true ;
2016-08-01 21:51:23 +02:00
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS :
2017-05-15 05:06:23 +02:00
has_set_netplay_ip_address = true ;
2016-08-01 21:51:23 +02:00
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT :
2017-05-15 05:06:23 +02:00
has_set_netplay_ip_port = true ;
2016-08-01 21:51:23 +02:00
break ;
2016-12-15 23:09:55 -05:00
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE :
2017-05-15 05:06:23 +02:00
has_set_netplay_stateless_mode = true ;
2016-08-01 21:51:23 +02:00
break ;
2016-09-14 23:54:18 -04:00
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES :
2017-05-15 05:06:23 +02:00
has_set_netplay_check_frames = true ;
2016-09-14 23:54:18 -04:00
break ;
2016-08-01 21:51:23 +02:00
case RARCH_OVERRIDE_SETTING_UPS_PREF :
2017-05-15 05:06:23 +02:00
has_set_ups_pref = true ;
2016-08-01 21:51:23 +02:00
break ;
case RARCH_OVERRIDE_SETTING_BPS_PREF :
2017-05-15 05:06:23 +02:00
has_set_bps_pref = true ;
2016-08-01 21:51:23 +02:00
break ;
case RARCH_OVERRIDE_SETTING_IPS_PREF :
2017-05-15 05:06:23 +02:00
has_set_ips_pref = true ;
2016-08-01 21:51:23 +02:00
break ;
2019-05-17 17:19:13 +01:00
case RARCH_OVERRIDE_SETTING_LOG_TO_FILE :
has_set_log_to_file = true ;
break ;
2016-08-01 20:41:42 +02:00
case RARCH_OVERRIDE_SETTING_NONE :
default :
break ;
}
}
2017-05-15 05:06:23 +02:00
void retroarch_override_setting_unset ( enum rarch_override_setting enum_idx , void * data )
{
switch ( enum_idx )
{
case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE :
{
unsigned * val = ( unsigned * ) data ;
if ( val )
{
unsigned bit = * val ;
2017-12-05 12:07:35 +01:00
BIT256_CLEAR ( has_set_libretro_device , bit ) ;
2017-05-15 05:06:23 +02:00
}
}
break ;
case RARCH_OVERRIDE_SETTING_VERBOSITY :
has_set_verbosity = false ;
break ;
case RARCH_OVERRIDE_SETTING_LIBRETRO :
has_set_libretro = false ;
break ;
case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY :
has_set_libretro_directory = false ;
break ;
case RARCH_OVERRIDE_SETTING_SAVE_PATH :
has_set_save_path = false ;
break ;
case RARCH_OVERRIDE_SETTING_STATE_PATH :
has_set_state_path = false ;
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE :
has_set_netplay_mode = false ;
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS :
has_set_netplay_ip_address = false ;
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT :
has_set_netplay_ip_port = false ;
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE :
has_set_netplay_stateless_mode = false ;
break ;
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES :
has_set_netplay_check_frames = false ;
break ;
case RARCH_OVERRIDE_SETTING_UPS_PREF :
has_set_ups_pref = false ;
break ;
case RARCH_OVERRIDE_SETTING_BPS_PREF :
has_set_bps_pref = false ;
break ;
case RARCH_OVERRIDE_SETTING_IPS_PREF :
has_set_ips_pref = false ;
break ;
2019-05-17 17:19:13 +01:00
case RARCH_OVERRIDE_SETTING_LOG_TO_FILE :
has_set_log_to_file = false ;
break ;
2017-05-15 05:06:23 +02:00
case RARCH_OVERRIDE_SETTING_NONE :
default :
break ;
}
}
2016-05-09 07:09:26 +02:00
int retroarch_get_capabilities ( enum rarch_capabilities type ,
2016-01-26 05:38:40 +01:00
char * s , size_t len )
2015-11-28 20:11:55 +01:00
{
switch ( type )
{
case RARCH_CAPABILITIES_CPU :
{
2016-05-10 09:17:04 +02:00
uint64_t cpu = cpu_features_get ( ) ;
2015-11-28 20:11:55 +01:00
if ( cpu & RETRO_SIMD_MMX )
strlcat ( s , " MMX " , len ) ;
if ( cpu & RETRO_SIMD_MMXEXT )
strlcat ( s , " MMXEXT " , len ) ;
if ( cpu & RETRO_SIMD_SSE )
strlcat ( s , " SSE1 " , len ) ;
if ( cpu & RETRO_SIMD_SSE2 )
strlcat ( s , " SSE2 " , len ) ;
if ( cpu & RETRO_SIMD_SSE3 )
strlcat ( s , " SSE3 " , len ) ;
if ( cpu & RETRO_SIMD_SSSE3 )
strlcat ( s , " SSSE3 " , len ) ;
if ( cpu & RETRO_SIMD_SSE4 )
strlcat ( s , " SSE4 " , len ) ;
if ( cpu & RETRO_SIMD_SSE42 )
strlcat ( s , " SSE4.2 " , len ) ;
if ( cpu & RETRO_SIMD_AVX )
strlcat ( s , " AVX " , len ) ;
if ( cpu & RETRO_SIMD_AVX2 )
strlcat ( s , " AVX2 " , len ) ;
if ( cpu & RETRO_SIMD_VFPU )
strlcat ( s , " VFPU " , len ) ;
if ( cpu & RETRO_SIMD_NEON )
strlcat ( s , " NEON " , len ) ;
2016-05-14 13:37:07 +02:00
if ( cpu & RETRO_SIMD_VFPV3 )
strlcat ( s , " VFPv3 " , len ) ;
if ( cpu & RETRO_SIMD_VFPV4 )
strlcat ( s , " VFPv4 " , len ) ;
2015-11-28 20:11:55 +01:00
if ( cpu & RETRO_SIMD_PS )
strlcat ( s , " PS " , len ) ;
if ( cpu & RETRO_SIMD_AES )
strlcat ( s , " AES " , len ) ;
if ( cpu & RETRO_SIMD_VMX )
strlcat ( s , " VMX " , len ) ;
if ( cpu & RETRO_SIMD_VMX128 )
strlcat ( s , " VMX128 " , len ) ;
2016-10-18 17:39:02 +02:00
if ( cpu & RETRO_SIMD_ASIMD )
strlcat ( s , " ASIMD " , len ) ;
2015-11-28 20:11:55 +01:00
}
break ;
case RARCH_CAPABILITIES_COMPILER :
# if defined(_MSC_VER)
2016-11-08 15:17:02 +01:00
snprintf ( s , len , " %s: MSVC (%d) %u-bit " ,
msg_hash_to_str ( MSG_COMPILER ) ,
_MSC_VER , ( unsigned )
2015-11-28 20:11:55 +01:00
( CHAR_BIT * sizeof ( size_t ) ) ) ;
# elif defined(__SNC__)
2016-11-08 15:17:02 +01:00
snprintf ( s , len , " %s: SNC (%d) %u-bit " ,
msg_hash_to_str ( MSG_COMPILER ) ,
2015-11-28 20:11:55 +01:00
__SN_VER__ , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
# elif defined(_WIN32) && defined(__GNUC__)
2016-11-08 15:17:02 +01:00
snprintf ( s , len , " %s: MinGW (%d.%d.%d) %u-bit " ,
msg_hash_to_str ( MSG_COMPILER ) ,
2015-11-28 20:11:55 +01:00
__GNUC__ , __GNUC_MINOR__ , __GNUC_PATCHLEVEL__ , ( unsigned )
( CHAR_BIT * sizeof ( size_t ) ) ) ;
# elif defined(__clang__)
2016-11-08 15:17:02 +01:00
snprintf ( s , len , " %s: Clang/LLVM (%s) %u-bit " ,
msg_hash_to_str ( MSG_COMPILER ) ,
2015-11-28 20:11:55 +01:00
__clang_version__ , ( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
# elif defined(__GNUC__)
2016-11-08 15:17:02 +01:00
snprintf ( s , len , " %s: GCC (%d.%d.%d) %u-bit " ,
msg_hash_to_str ( MSG_COMPILER ) ,
2015-11-28 20:11:55 +01:00
__GNUC__ , __GNUC_MINOR__ , __GNUC_PATCHLEVEL__ , ( unsigned )
( CHAR_BIT * sizeof ( size_t ) ) ) ;
# else
2016-11-08 15:17:02 +01:00
snprintf ( s , len , " %s %u-bit " ,
msg_hash_to_str ( MSG_UNKNOWN_COMPILER ) ,
2015-11-28 20:11:55 +01:00
( unsigned ) ( CHAR_BIT * sizeof ( size_t ) ) ) ;
# endif
break ;
default :
case RARCH_CAPABILITIES_NONE :
break ;
}
return 0 ;
}
2015-11-29 02:27:48 +01:00
2016-05-27 21:16:25 +02:00
void retroarch_set_current_core_type ( enum rarch_core_type type , bool explicitly_set )
2016-05-27 19:26:45 +02:00
{
2016-10-03 16:42:08 +02:00
if ( explicitly_set & & ! has_set_core )
2016-05-27 21:16:25 +02:00
{
2016-10-03 16:42:08 +02:00
has_set_core = true ;
2016-05-27 21:16:25 +02:00
explicit_current_core_type = type ;
2016-06-27 14:13:09 +10:00
current_core_type = type ;
2016-05-27 21:16:25 +02:00
}
2016-10-03 16:42:08 +02:00
else if ( ! has_set_core )
2016-05-27 21:16:25 +02:00
current_core_type = type ;
2016-05-27 19:26:45 +02:00
}
2015-11-29 02:27:48 +01:00
/**
2016-05-09 07:09:26 +02:00
* retroarch_fail :
2015-11-29 02:27:48 +01:00
* @ error_code : Error code .
* @ error : Error message to show .
*
* Sanely kills the program .
* */
2016-05-09 07:09:26 +02:00
void retroarch_fail ( int error_code , const char * error )
2015-11-29 02:27:48 +01:00
{
2016-05-09 07:09:26 +02:00
/* We cannot longjmp unless we're in retroarch_main_init().
2016-03-10 17:36:46 -05:00
* If not , something went very wrong , and we should
2015-11-29 02:27:48 +01:00
* just exit right away . */
2017-05-08 03:59:02 +02:00
retro_assert ( rarch_error_on_init ) ;
2015-11-29 02:27:48 +01:00
2015-11-30 19:30:05 +01:00
strlcpy ( error_string , error , sizeof ( error_string ) ) ;
longjmp ( error_sjlj_context , error_code ) ;
2015-11-29 02:27:48 +01:00
}
2017-05-08 03:54:51 +02:00
bool retroarch_main_quit ( void )
{
2019-02-06 19:01:11 -05:00
# ifdef HAVE_DISCORD
if ( discord_is_inited )
{
discord_userdata_t userdata ;
userdata . status = DISCORD_PRESENCE_SHUTDOWN ;
command_event ( CMD_EVENT_DISCORD_UPDATE , & userdata ) ;
}
command_event ( CMD_EVENT_DISCORD_DEINIT , NULL ) ;
discord_is_inited = false ;
# endif
2019-01-10 02:35:35 +01:00
if ( ! rarch_ctl ( RARCH_CTL_IS_SHUTDOWN , NULL ) )
2017-05-31 00:34:01 -05:00
{
command_event ( CMD_EVENT_AUTOSAVE_STATE , NULL ) ;
command_event ( CMD_EVENT_DISABLE_OVERRIDES , NULL ) ;
command_event ( CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET , NULL ) ;
2017-08-04 23:56:17 -05:00
command_event ( CMD_EVENT_RESTORE_REMAPS , NULL ) ;
2017-05-31 00:34:01 -05:00
}
2017-05-08 03:54:51 +02:00
2019-01-10 02:35:03 +01:00
rarch_ctl ( RARCH_CTL_SET_SHUTDOWN , NULL ) ;
2017-05-15 04:31:40 +02:00
rarch_menu_running_finished ( ) ;
2017-05-08 03:54:51 +02:00
return true ;
}
2017-05-11 09:11:46 +02:00
global_t * global_get_ptr ( void )
{
return & g_extern ;
}
2019-02-21 10:23:21 +01:00
void runloop_task_msg_queue_push ( retro_task_t * task , const char * msg ,
2017-05-11 09:11:46 +02:00
unsigned prio , unsigned duration ,
bool flush )
2018-11-22 15:45:52 +01:00
{
2019-02-21 10:23:21 +01:00
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
2019-05-03 21:25:20 +02:00
if ( ! menu_widgets_task_msg_queue_push ( task , msg , prio , duration , flush ) )
2019-02-21 10:23:21 +01:00
# endif
runloop_msg_queue_push ( msg , prio , duration , flush , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
2018-11-22 15:45:52 +01:00
}
void runloop_msg_queue_push ( const char * msg ,
unsigned prio , unsigned duration ,
bool flush ,
char * title ,
enum message_queue_icon icon , enum message_queue_category category )
2017-05-11 09:11:46 +02:00
{
runloop_ctx_msg_info_t msg_info ;
2019-02-21 10:23:21 +01:00
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
2019-05-03 21:25:20 +02:00
if ( menu_widgets_msg_queue_push ( msg ,
2019-05-27 09:59:41 +02:00
roundf ( ( float ) duration / 60.0f * 1000.0f ) , title , icon , category , prio , flush ) )
2019-02-21 10:23:21 +01:00
return ;
# endif
2017-05-11 09:11:46 +02:00
# ifdef HAVE_THREADS
2019-06-17 15:10:22 +02:00
runloop_msg_queue_lock_internal ( ) ;
2017-05-11 09:11:46 +02:00
# endif
if ( flush )
msg_queue_clear ( runloop_msg_queue ) ;
msg_info . msg = msg ;
msg_info . prio = prio ;
msg_info . duration = duration ;
msg_info . flush = flush ;
if ( runloop_msg_queue )
{
msg_queue_push ( runloop_msg_queue , msg_info . msg ,
2018-11-22 15:45:52 +01:00
msg_info . prio , msg_info . duration ,
title , icon , category ) ;
2017-05-11 09:11:46 +02:00
2018-04-30 14:33:05 -04:00
ui_companion_driver_msg_queue_push ( msg_info . msg ,
msg_info . prio , msg_info . duration , msg_info . flush ) ;
2017-05-11 09:11:46 +02:00
}
# ifdef HAVE_THREADS
2019-06-17 15:10:22 +02:00
runloop_msg_queue_unlock_internal ( ) ;
2017-05-11 09:11:46 +02:00
# endif
}
2017-07-04 21:46:22 -04:00
void runloop_get_status ( bool * is_paused , bool * is_idle ,
2017-05-11 09:11:46 +02:00
bool * is_slowmotion , bool * is_perfcnt_enable )
{
* is_paused = runloop_paused ;
* is_idle = runloop_idle ;
* is_slowmotion = runloop_slowmotion ;
* is_perfcnt_enable = runloop_perfcnt_enable ;
}
2019-01-14 04:39:58 +01:00
# define bsv_movie_is_end_of_file() (bsv_movie_state.movie_end && bsv_movie_state.eof_exit)
2017-05-11 09:11:46 +02:00
/* Time to exit out of the main loop?
* Reasons for exiting :
* a ) Shutdown environment callback was invoked .
* b ) Quit key was pressed .
* c ) Frame count exceeds or equals maximum amount of frames to run .
* d ) Video driver no longer alive .
* e ) End of BSV movie and BSV EOF exit is true . ( TODO / FIXME - explain better )
*/
2019-01-14 04:39:58 +01:00
# define time_to_exit(quit_key_pressed) (runloop_shutdown_initiated || quit_key_pressed || !is_alive || bsv_movie_is_end_of_file() || ((runloop_max_frames != 0) && (frame_count >= runloop_max_frames)) || runloop_exec)
2017-05-11 09:11:46 +02:00
2019-05-29 14:26:22 -03:00
# define runloop_check_cheevos() (settings->bools.cheevos_enable && rcheevos_loaded && (!rcheevos_cheats_are_enabled && !rcheevos_cheats_were_enabled))
2017-05-11 09:11:46 +02:00
2017-05-21 11:36:47 +02:00
# ifdef HAVE_NETWORKING
/* FIXME: This is an ugly way to tell Netplay this... */
# define runloop_netplay_pause() netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL)
# else
# define runloop_netplay_pause() ((void)0)
# endif
2017-05-24 02:02:01 +02:00
# ifdef HAVE_MENU
static bool input_driver_toggle_button_combo (
2018-04-08 20:21:12 +02:00
unsigned mode , input_bits_t * p_input )
2017-05-24 02:02:01 +02:00
{
switch ( mode )
{
case INPUT_TOGGLE_DOWN_Y_L_R :
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_DOWN ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_Y ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_L ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_R ) )
2017-05-24 02:02:01 +02:00
return false ;
break ;
case INPUT_TOGGLE_L3_R3 :
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_L3 ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_R3 ) )
2017-05-24 02:02:01 +02:00
return false ;
break ;
case INPUT_TOGGLE_L1_R1_START_SELECT :
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_START ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_SELECT ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_L ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_R ) )
2017-05-24 02:02:01 +02:00
return false ;
break ;
case INPUT_TOGGLE_START_SELECT :
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_START ) )
2017-05-24 02:02:01 +02:00
return false ;
2017-12-05 12:07:35 +01:00
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_SELECT ) )
2017-05-24 02:02:01 +02:00
return false ;
break ;
2018-10-01 00:20:45 +02:00
case INPUT_TOGGLE_L3_R :
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_L3 ) )
return false ;
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_R ) )
return false ;
break ;
2018-10-01 01:36:31 +02:00
case INPUT_TOGGLE_L_R :
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_L ) )
return false ;
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_R ) )
return false ;
break ;
2019-01-28 11:43:57 -05:00
case INPUT_TOGGLE_DOWN_SELECT :
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_DOWN ) )
return false ;
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_SELECT ) )
return false ;
break ;
2018-12-19 14:53:17 -05:00
case INPUT_TOGGLE_HOLD_START :
{
static rarch_timer_t timer = { 0 } ;
if ( ! BIT256_GET_PTR ( p_input , RETRO_DEVICE_ID_JOYPAD_START ) )
{
/* timer only runs while start is held down */
rarch_timer_end ( & timer ) ;
return false ;
}
2019-05-31 16:38:17 +02:00
/* user started holding down the start button, start the timer */
2018-12-19 14:53:17 -05:00
if ( ! rarch_timer_is_running ( & timer ) )
rarch_timer_begin ( & timer , HOLD_START_DELAY_SEC ) ;
rarch_timer_tick ( & timer ) ;
if ( ! timer . timer_end & & rarch_timer_has_expired ( & timer ) )
{
/* start has been held down long enough, stop timer and enter menu */
rarch_timer_end ( & timer ) ;
return true ;
}
return false ;
}
2017-05-24 02:02:01 +02:00
default :
case INPUT_TOGGLE_NONE :
return false ;
}
2017-07-04 21:46:22 -04:00
2017-05-24 02:02:01 +02:00
return true ;
}
# endif
2019-06-16 16:20:43 +02:00
# define HOTKEY_CHECK(cmd1, cmd2, cond, cond2) \
2019-06-08 05:17:14 +02:00
{ \
static bool old_pressed = false ; \
bool pressed = BIT256_GET ( current_input , cmd1 ) ; \
if ( pressed & & ! old_pressed ) \
2019-06-09 08:35:16 +02:00
if ( cond ) \
2019-06-16 16:20:43 +02:00
command_event ( cmd2 , cond2 ) ; \
2019-06-08 05:17:14 +02:00
old_pressed = pressed ; \
}
2019-06-09 08:48:59 +02:00
# define HOTKEY_CHECK3(cmd1, cmd2, cmd3, cmd4, cmd5, cmd6) \
{ \
static bool old_pressed = false ; \
static bool old_pressed2 = false ; \
static bool old_pressed3 = false ; \
bool pressed = BIT256_GET ( current_input , cmd1 ) ; \
bool pressed2 = BIT256_GET ( current_input , cmd3 ) ; \
bool pressed3 = BIT256_GET ( current_input , cmd5 ) ; \
if ( pressed & & ! old_pressed ) \
command_event ( cmd2 , ( void * ) ( intptr_t ) 0 ) ; \
else if ( pressed2 & & ! old_pressed2 ) \
command_event ( cmd4 , ( void * ) ( intptr_t ) 0 ) ; \
else if ( pressed3 & & ! old_pressed3 ) \
command_event ( cmd6 , ( void * ) ( intptr_t ) 0 ) ; \
old_pressed = pressed ; \
old_pressed2 = pressed2 ; \
old_pressed3 = pressed3 ; \
}
2017-05-11 09:11:46 +02:00
static enum runloop_state runloop_check_state (
settings_t * settings ,
2017-05-21 21:55:20 +02:00
bool input_nonblock_state ,
2019-01-12 17:58:35 +01:00
bool runloop_is_paused ,
float fastforward_ratio ,
2017-05-11 09:11:46 +02:00
unsigned * sleep_ms )
{
2018-04-08 20:21:12 +02:00
input_bits_t current_input ;
2017-12-31 18:02:14 +01:00
# ifdef HAVE_MENU
2019-06-14 13:13:49 +02:00
static input_bits_t last_input = { { 0 } } ;
2017-12-31 18:02:14 +01:00
# endif
2019-02-25 19:12:50 +01:00
static bool old_focus = true ;
2019-06-17 15:10:22 +02:00
bool is_focused = video_driver_cb_has_focus ( ) ;
bool is_alive = current_video ?
current_video - > alive ( video_driver_data ) : true ;
uint64_t frame_count = video_driver_frame_count ;
2019-02-25 19:12:50 +01:00
bool focused = true ;
bool pause_nonactive = settings - > bools . pause_nonactive ;
2019-02-27 16:47:39 +01:00
bool rarch_is_initialized = rarch_is_inited ;
2017-05-21 23:53:39 +02:00
# ifdef HAVE_MENU
2019-02-25 19:12:50 +01:00
bool menu_driver_binding_state = menu_driver_is_binding_state ( ) ;
bool menu_is_alive = menu_driver_is_alive ( ) ;
unsigned menu_toggle_gamepad_combo = settings - > uints . input_menu_toggle_gamepad_combo ;
2019-01-06 14:21:15 -08:00
# ifdef HAVE_EASTEREGG
2019-02-25 19:12:50 +01:00
static uint64_t seq = 0 ;
2019-01-06 14:21:15 -08:00
# endif
2018-04-09 00:30:45 +02:00
# endif
2018-11-07 19:25:26 +01:00
# ifdef HAVE_LIBNX
2019-01-12 17:58:35 +01:00
/* Should be called once per frame */
if ( ! appletMainLoop ( ) )
2018-11-07 19:25:26 +01:00
return RUNLOOP_STATE_QUIT ;
# endif
2018-04-09 00:30:45 +02:00
BIT256_CLEAR_ALL_PTR ( & current_input ) ;
2017-11-24 11:19:17 +00:00
2018-04-09 00:30:45 +02:00
# ifdef HAVE_MENU
2017-12-05 09:22:33 +01:00
if ( menu_is_alive & & ! ( settings - > bools . menu_unified_controls & & ! menu_input_dialog_get_display_kb ( ) ) )
2018-04-30 14:33:05 -04:00
input_menu_keys_pressed ( settings , & current_input ) ;
2017-11-24 11:19:17 +00:00
else
2017-12-17 04:11:56 +01:00
# endif
2018-04-30 14:33:05 -04:00
input_keys_pressed ( settings , & current_input ) ;
2017-11-24 11:19:17 +00:00
2017-05-21 20:42:46 +02:00
# ifdef HAVE_MENU
2017-12-31 18:02:14 +01:00
last_input = current_input ;
2017-05-24 02:02:01 +02:00
if (
2019-01-12 17:58:35 +01:00
( ( menu_toggle_gamepad_combo ! = INPUT_TOGGLE_NONE ) & &
2017-05-24 02:02:01 +02:00
input_driver_toggle_button_combo (
2019-01-12 17:58:35 +01:00
menu_toggle_gamepad_combo , & last_input ) ) )
2017-12-05 12:07:35 +01:00
BIT256_SET ( current_input , RARCH_MENU_TOGGLE ) ;
2017-05-21 20:42:46 +02:00
# endif
2017-05-21 23:53:39 +02:00
if ( input_driver_flushing_input )
2017-07-04 21:46:22 -04:00
{
input_driver_flushing_input = false ;
2017-12-05 13:15:15 +01:00
if ( bits_any_set ( current_input . data , ARRAY_SIZE ( current_input . data ) ) )
2017-05-21 23:53:39 +02:00
{
2017-12-05 12:07:35 +01:00
BIT256_CLEAR_ALL ( current_input ) ;
2019-01-12 17:58:35 +01:00
if ( runloop_is_paused )
2017-12-05 12:07:35 +01:00
BIT256_SET ( current_input , RARCH_PAUSE_TOGGLE ) ;
2017-07-04 21:46:22 -04:00
input_driver_flushing_input = true ;
2017-05-21 23:53:39 +02:00
}
}
2019-06-17 15:10:22 +02:00
if ( ! video_driver_is_threaded_internal ( ) )
2018-07-13 22:34:03 -05:00
{
const ui_application_t * application =
ui_companion_driver_get_application_ptr ( ) ;
if ( application )
application - > process_events ( ) ;
}
2017-06-10 23:26:41 +02:00
# ifdef HAVE_MENU
if ( menu_driver_binding_state )
2017-12-05 12:07:35 +01:00
BIT256_CLEAR_ALL ( current_input ) ;
2017-06-10 23:26:41 +02:00
# endif
2017-05-20 14:17:14 +02:00
# ifdef HAVE_OVERLAY
2017-05-21 12:09:24 +02:00
/* Check next overlay */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_OVERLAY_NEXT , CMD_EVENT_OVERLAY_NEXT , true , NULL ) ;
2017-05-20 14:17:14 +02:00
# endif
2017-05-11 09:11:46 +02:00
2017-05-21 16:36:08 +02:00
/* Check fullscreen toggle */
2017-05-11 09:11:46 +02:00
{
2019-06-09 08:35:16 +02:00
bool fullscreen_toggled = ! runloop_is_paused
2017-05-19 16:26:00 +02:00
# ifdef HAVE_MENU
2019-06-09 08:35:16 +02:00
| | menu_is_alive ;
2017-06-20 20:53:46 -05:00
# else
2019-06-09 08:35:16 +02:00
;
2017-05-19 16:26:00 +02:00
# endif
2019-06-09 08:35:16 +02:00
HOTKEY_CHECK ( RARCH_FULLSCREEN_TOGGLE_KEY , CMD_EVENT_FULLSCREEN_TOGGLE ,
2019-06-16 16:20:43 +02:00
fullscreen_toggled , NULL ) ;
2017-05-11 09:11:46 +02:00
}
2017-05-21 13:06:48 +02:00
/* Check mouse grab toggle */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_GRAB_MOUSE_TOGGLE , CMD_EVENT_GRAB_MOUSE_TOGGLE , true , NULL ) ;
2017-05-11 09:11:46 +02:00
# ifdef HAVE_OVERLAY
{
2017-05-21 12:57:28 +02:00
static char prev_overlay_restore = false ;
if ( input_keyboard_ctl (
RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED , NULL ) )
{
prev_overlay_restore = false ;
2017-05-11 09:11:46 +02:00
command_event ( CMD_EVENT_OVERLAY_INIT , NULL ) ;
2017-05-21 12:57:28 +02:00
}
else if ( prev_overlay_restore )
{
if ( ! settings - > bools . input_overlay_hide_in_menu )
command_event ( CMD_EVENT_OVERLAY_INIT , NULL ) ;
prev_overlay_restore = false ;
}
2017-05-11 09:11:46 +02:00
}
# endif
2017-05-21 13:50:59 +02:00
/* Check quit key */
2017-05-11 09:11:46 +02:00
{
2019-06-16 16:06:37 +02:00
bool trig_quit_key ;
2019-06-16 20:04:43 +02:00
static bool quit_key = false ;
static bool old_quit_key = false ;
2019-06-16 16:06:37 +02:00
static bool runloop_exec = false ;
2019-01-17 19:58:44 -08:00
quit_key = BIT256_GET (
2019-01-14 00:04:37 -08:00
current_input , RARCH_QUIT_KEY ) ;
2019-01-17 19:58:44 -08:00
trig_quit_key = quit_key & & ! old_quit_key ;
2017-05-21 13:50:59 +02:00
old_quit_key = quit_key ;
2019-02-25 19:12:50 +01:00
/* Check double press if enabled */
if ( trig_quit_key & & settings - > bools . quit_press_twice )
{
2019-06-16 16:06:37 +02:00
static retro_time_t quit_key_time = 0 ;
retro_time_t cur_time = cpu_features_get_time_usec ( ) ;
trig_quit_key = ( cur_time - quit_key_time < QUIT_DELAY_USEC ) ;
quit_key_time = cur_time ;
2019-02-27 04:43:14 +01:00
2019-06-16 16:06:37 +02:00
if ( ! trig_quit_key )
{
float target_hz = 0.0 ;
2019-02-27 04:43:14 +01:00
2019-06-16 16:06:37 +02:00
rarch_environment_cb (
RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE , & target_hz ) ;
2019-02-25 19:12:50 +01:00
2019-02-27 04:43:14 +01:00
runloop_msg_queue_push ( msg_hash_to_str ( MSG_PRESS_AGAIN_TO_QUIT ) , 1 ,
QUIT_DELAY_USEC * target_hz / 1000000 ,
2019-06-16 16:06:37 +02:00
true , NULL ,
MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
2019-02-25 19:12:50 +01:00
}
2017-05-21 13:50:59 +02:00
if ( time_to_exit ( trig_quit_key ) )
2017-05-11 09:11:46 +02:00
{
2019-06-16 20:04:43 +02:00
bool quit_runloop = false ;
2019-04-22 04:25:43 +02:00
if ( ( runloop_max_frames ! = 0 ) & & ( frame_count > = runloop_max_frames )
& & runloop_max_frames_screenshot )
2018-08-18 23:09:40 -04:00
{
2019-04-22 04:25:43 +02:00
const char * screenshot_path = NULL ;
bool fullpath = false ;
2018-08-18 23:09:40 -04:00
2019-04-22 04:25:43 +02:00
if ( string_is_empty ( runloop_max_frames_screenshot_path ) )
screenshot_path = path_get ( RARCH_PATH_BASENAME ) ;
else
{
fullpath = true ;
screenshot_path = runloop_max_frames_screenshot_path ;
}
2018-08-18 23:09:40 -04:00
2019-04-22 04:25:43 +02:00
RARCH_LOG ( " Taking a screenshot before exiting... \n " ) ;
2018-08-18 23:09:40 -04:00
2019-04-22 04:25:43 +02:00
/* Take a screenshot before we exit. */
2019-05-22 05:54:35 +02:00
if ( ! take_screenshot ( settings - > paths . directory_screenshot ,
screenshot_path , false ,
2019-04-22 04:25:43 +02:00
video_driver_cached_frame_has_valid_framebuffer ( ) , fullpath , false ) )
{
RARCH_ERR ( " Could not take a screenshot before exiting. \n " ) ;
2018-08-18 23:09:40 -04:00
}
}
2017-05-21 13:50:59 +02:00
if ( runloop_exec )
runloop_exec = false ;
if ( runloop_core_shutdown_initiated & & settings - > bools . load_dummy_on_core_shutdown )
{
content_ctx_info_t content_info ;
2017-05-11 09:11:46 +02:00
2017-05-21 13:50:59 +02:00
content_info . argc = 0 ;
content_info . argv = NULL ;
content_info . args = NULL ;
content_info . environ_get = NULL ;
2019-06-16 20:04:43 +02:00
if ( task_push_start_dummy_core ( & content_info ) )
{
/* Loads dummy core instead of exiting RetroArch completely.
* Aborts core shutdown if invoked . */
rarch_ctl ( RARCH_CTL_UNSET_SHUTDOWN , NULL ) ;
runloop_core_shutdown_initiated = false ;
}
else
quit_runloop = true ;
2017-05-21 13:50:59 +02:00
}
else
2019-06-16 20:04:43 +02:00
quit_runloop = true ;
if ( quit_runloop )
{
old_quit_key = quit_key ;
retroarch_main_quit ( ) ;
return RUNLOOP_STATE_QUIT ;
}
2017-05-11 09:11:46 +02:00
}
}
2018-11-22 15:45:52 +01:00
# if defined(HAVE_MENU)
2019-02-14 11:58:27 +01:00
menu_animation_update ( ) ;
2019-02-08 20:02:45 +01:00
2019-02-21 10:23:21 +01:00
# ifdef HAVE_MENU_WIDGETS
menu_widgets_iterate ( ) ;
# endif
2017-05-19 16:29:11 +02:00
if ( menu_is_alive )
2017-05-11 09:11:46 +02:00
{
2019-01-12 17:58:35 +01:00
enum menu_action action ;
2018-04-08 20:21:12 +02:00
static input_bits_t old_input = { { 0 } } ;
2019-02-03 15:49:35 -08:00
static enum menu_action
2019-01-12 17:58:35 +01:00
old_action = MENU_ACTION_CANCEL ;
bool focused = false ;
input_bits_t trigger_input = current_input ;
2019-06-17 15:37:34 +02:00
global_t * global = & g_extern ;
2018-07-25 19:19:14 -04:00
2017-05-11 09:11:46 +02:00
menu_ctx_iterate_t iter ;
2017-05-29 20:30:01 +02:00
retro_ctx . poll_cb ( ) ;
2017-05-11 09:11:46 +02:00
2019-01-12 17:58:35 +01:00
bits_clear_bits ( trigger_input . data , old_input . data ,
ARRAY_SIZE ( trigger_input . data ) ) ;
2017-11-23 23:04:09 +00:00
2019-01-12 17:58:35 +01:00
action = ( enum menu_action ) menu_event ( & current_input , & trigger_input ) ;
focused = pause_nonactive ? is_focused : true ;
focused = focused & & ! ui_companion_is_on_foreground ( ) ;
2017-05-11 09:11:46 +02:00
2019-01-12 17:58:35 +01:00
iter . action = action ;
2017-05-11 09:11:46 +02:00
2019-01-12 17:58:35 +01:00
if ( global )
{
if ( action = = old_action )
{
2019-04-22 04:25:43 +02:00
retro_time_t press_time = cpu_features_get_time_usec ( ) ;
2019-01-12 17:58:35 +01:00
if ( action = = MENU_ACTION_NOOP )
global - > menu . noop_press_time = press_time - global - > menu . noop_start_time ;
else
global - > menu . action_press_time = press_time - global - > menu . action_start_time ;
}
else
2018-07-25 19:19:14 -04:00
{
2019-01-12 17:58:35 +01:00
if ( action = = MENU_ACTION_NOOP )
2018-07-25 19:19:14 -04:00
{
2019-04-22 04:25:43 +02:00
global - > menu . noop_start_time = cpu_features_get_time_usec ( ) ;
global - > menu . noop_press_time = 0 ;
2019-01-12 17:58:35 +01:00
if ( global - > menu . prev_action = = old_action )
global - > menu . action_start_time = global - > menu . prev_start_time ;
2018-07-25 19:19:14 -04:00
else
2019-01-12 17:58:35 +01:00
global - > menu . action_start_time = cpu_features_get_time_usec ( ) ;
2018-07-25 19:19:14 -04:00
}
else
{
2019-04-22 04:25:43 +02:00
if ( global - > menu . prev_action = = action & &
2019-01-12 17:58:35 +01:00
global - > menu . noop_press_time < 200000 ) /* 250ms */
2018-07-25 19:19:14 -04:00
{
2019-01-12 17:58:35 +01:00
global - > menu . action_start_time = global - > menu . prev_start_time ;
global - > menu . action_press_time = cpu_features_get_time_usec ( ) - global - > menu . action_start_time ;
2018-07-25 19:19:14 -04:00
}
else
{
2019-01-12 17:58:35 +01:00
global - > menu . prev_start_time = cpu_features_get_time_usec ( ) ;
global - > menu . prev_action = action ;
global - > menu . action_press_time = 0 ;
2018-07-25 19:19:14 -04:00
}
}
}
2019-01-12 17:58:35 +01:00
}
2018-07-25 19:19:14 -04:00
2019-01-12 17:58:35 +01:00
if ( ! menu_driver_iterate ( & iter ) )
rarch_menu_running_finished ( ) ;
2017-05-21 21:19:07 +02:00
2019-01-12 17:58:35 +01:00
if ( focused | | ! runloop_idle )
{
bool libretro_running = menu_display_libretro_running (
rarch_is_initialized ,
( current_core_type = = CORE_TYPE_DUMMY ) ) ;
menu_driver_render ( runloop_idle , rarch_is_initialized ,
( current_core_type = = CORE_TYPE_DUMMY )
)
;
if ( settings - > bools . audio_enable_menu & &
! libretro_running )
audio_driver_menu_sample ( ) ;
2019-01-05 18:33:29 -05:00
# ifdef HAVE_EASTEREGG
2019-01-12 17:58:35 +01:00
{
bool library_name_is_empty = string_is_empty ( runloop_system . info . library_name ) ;
2019-01-05 18:33:29 -05:00
2019-01-12 17:58:35 +01:00
if ( library_name_is_empty & & trigger_input . data [ 0 ] )
{
seq | = trigger_input . data [ 0 ] & 0xF0 ;
2019-01-05 18:33:29 -05:00
2019-01-12 17:58:35 +01:00
if ( seq = = 1157460427127406720ULL )
{
content_ctx_info_t content_info ;
content_info . argc = 0 ;
content_info . argv = NULL ;
content_info . args = NULL ;
content_info . environ_get = NULL ;
task_push_start_builtin_core (
& content_info ,
CORE_TYPE_GONG , NULL , NULL ) ;
2019-01-05 18:33:29 -05:00
}
2019-01-12 17:58:35 +01:00
seq < < = 8 ;
2019-01-05 18:33:29 -05:00
}
2019-01-12 17:58:35 +01:00
else if ( ! library_name_is_empty )
seq = 0 ;
2018-04-29 00:06:54 +02:00
}
2019-01-12 17:58:35 +01:00
# endif
}
2017-05-29 20:30:01 +02:00
2019-01-12 17:58:35 +01:00
old_input = current_input ;
old_action = action ;
2017-05-29 20:30:01 +02:00
2019-06-09 06:34:01 +02:00
if ( ! focused | | runloop_idle )
2017-05-29 20:30:01 +02:00
return RUNLOOP_STATE_POLLED_AND_SLEEP ;
2017-05-11 09:11:46 +02:00
}
2017-05-29 20:30:01 +02:00
else
2017-05-11 09:11:46 +02:00
# endif
2019-01-05 18:33:29 -05:00
{
2019-01-06 14:21:15 -08:00
# if defined(HAVE_MENU) && defined(HAVE_EASTEREGG)
2019-01-05 18:33:29 -05:00
seq = 0 ;
2017-05-11 09:11:46 +02:00
# endif
2017-05-29 20:30:01 +02:00
if ( runloop_idle )
2019-05-31 16:38:17 +02:00
{
retro_ctx . poll_cb ( ) ;
return RUNLOOP_STATE_POLLED_AND_SLEEP ;
}
2019-01-05 18:33:29 -05:00
}
2017-05-11 09:11:46 +02:00
2017-05-21 13:39:29 +02:00
/* Check game focus toggle */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_GAME_FOCUS_TOGGLE , CMD_EVENT_GAME_FOCUS_TOGGLE , true , NULL ) ;
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the UI companion toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_UI_COMPANION_TOGGLE , CMD_EVENT_UI_COMPANION_TOGGLE , true , NULL ) ;
2018-04-30 14:33:05 -04:00
2017-05-11 09:11:46 +02:00
# ifdef HAVE_MENU
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the menu toggle button */
2017-05-11 09:11:46 +02:00
{
2017-05-21 13:54:17 +02:00
static bool old_pressed = false ;
2019-01-07 11:26:13 -08:00
char * menu_driver = settings - > arrays . menu_driver ;
2017-12-05 12:07:35 +01:00
bool pressed = BIT256_GET (
2019-01-07 11:26:13 -08:00
current_input , RARCH_MENU_TOGGLE ) & &
2019-04-29 04:04:33 +02:00
! string_is_equal ( menu_driver , " null " ) ;
2017-05-21 13:54:17 +02:00
2017-12-17 17:21:51 +01:00
if ( menu_event_kb_is_set ( RETROK_F1 ) = = 1 )
{
if ( menu_driver_is_alive ( ) )
{
2019-02-03 15:49:35 -08:00
if ( rarch_is_initialized & &
2019-01-12 17:58:35 +01:00
( current_core_type ! = CORE_TYPE_DUMMY ) )
2017-12-17 17:21:51 +01:00
{
rarch_menu_running_finished ( ) ;
menu_event_kb_set ( false , RETROK_F1 ) ;
}
}
}
else if ( ( ! menu_event_kb_is_set ( RETROK_F1 ) & &
( pressed & & ! old_pressed ) ) | |
( current_core_type = = CORE_TYPE_DUMMY ) )
{
if ( menu_driver_is_alive ( ) )
{
2019-02-03 15:49:35 -08:00
if ( rarch_is_initialized & &
2019-01-12 17:58:35 +01:00
( current_core_type ! = CORE_TYPE_DUMMY ) )
2017-12-17 17:21:51 +01:00
rarch_menu_running_finished ( ) ;
}
else
{
menu_display_toggle_set_reason ( MENU_TOGGLE_REASON_USER ) ;
rarch_menu_running ( ) ;
}
}
else
menu_event_kb_set ( false , RETROK_F1 ) ;
2017-05-21 13:54:17 +02:00
old_pressed = pressed ;
2017-05-11 09:11:46 +02:00
}
2019-03-09 16:03:17 -05:00
/* Check if we have pressed the "send debug info" button.
* Must press 3 times in a row to activate , but it will
* alert the user of this with each press of the hotkey . */
{
int any_i ;
2019-05-31 15:29:52 +02:00
static uint32_t debug_seq = 0 ;
static bool old_pressed = false ;
static bool old_any_pressed = false ;
bool any_pressed = false ;
bool pressed = BIT256_GET ( current_input , RARCH_SEND_DEBUG_INFO ) ;
2019-03-09 16:03:17 -05:00
for ( any_i = 0 ; any_i < ARRAY_SIZE ( current_input . data ) ; any_i + + )
{
if ( current_input . data [ any_i ] )
{
any_pressed = true ;
break ;
}
}
if ( pressed & & ! old_pressed )
debug_seq | = pressed ? 1 : 0 ;
switch ( debug_seq )
{
case 1 : /* pressed hotkey one time */
runloop_msg_queue_push (
msg_hash_to_str ( MSG_PRESS_TWO_MORE_TIMES_TO_SEND_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
break ;
case 3 : /* pressed hotkey two times */
runloop_msg_queue_push (
msg_hash_to_str ( MSG_PRESS_ONE_MORE_TIME_TO_SEND_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
break ;
case 7 : /* pressed hotkey third and final time */
debug_seq = 0 ;
command_event ( CMD_EVENT_SEND_DEBUG_INFO , NULL ) ;
break ;
}
if ( any_pressed & & ! old_any_pressed )
{
debug_seq < < = 1 ;
if ( debug_seq > 7 )
debug_seq = 0 ;
}
old_pressed = pressed ;
old_any_pressed = any_pressed ;
}
/* Check if we have pressed the FPS toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_FPS_TOGGLE , CMD_EVENT_FPS_TOGGLE , true , NULL ) ;
2019-03-09 16:03:17 -05:00
2019-03-09 17:48:03 -05:00
/* Check if we have pressed the netplay host toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_NETPLAY_HOST_TOGGLE , CMD_EVENT_NETPLAY_HOST_TOGGLE , true , NULL ) ;
2019-03-09 17:48:03 -05:00
2017-05-19 16:26:00 +02:00
if ( menu_driver_is_alive ( ) )
2017-05-11 09:11:46 +02:00
{
2019-01-12 17:58:35 +01:00
if ( ! settings - > bools . menu_throttle_framerate & & ! fastforward_ratio )
2017-05-11 09:11:46 +02:00
return RUNLOOP_STATE_MENU_ITERATE ;
return RUNLOOP_STATE_END ;
}
# endif
2017-05-17 08:51:49 +02:00
if ( pause_nonactive )
2017-05-11 09:11:46 +02:00
focused = is_focused ;
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the screenshot toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_SCREENSHOT , CMD_EVENT_TAKE_SCREENSHOT , true , NULL ) ;
2017-05-11 09:11:46 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the audio mute toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_MUTE , CMD_EVENT_AUDIO_MUTE_TOGGLE , true , NULL ) ;
2017-05-21 13:06:48 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the OSK toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_OSK , CMD_EVENT_OSK_TOGGLE , true , NULL ) ;
2017-05-11 09:11:46 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the recording toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_RECORDING_TOGGLE , CMD_EVENT_RECORDING_TOGGLE , true , NULL ) ;
2018-09-18 08:51:35 +02:00
2019-06-06 03:41:40 +02:00
/* Check if we have pressed the AI Service toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_AI_SERVICE , CMD_EVENT_AI_SERVICE_TOGGLE , true , NULL ) ;
2019-06-06 03:41:40 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the streaming toggle button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_STREAMING_TOGGLE , CMD_EVENT_STREAMING_TOGGLE , true , NULL ) ;
2018-09-18 08:51:35 +02:00
2017-12-05 12:07:35 +01:00
if ( BIT256_GET ( current_input , RARCH_VOLUME_UP ) )
2017-05-11 09:11:46 +02:00
command_event ( CMD_EVENT_VOLUME_UP , NULL ) ;
2017-12-05 12:07:35 +01:00
else if ( BIT256_GET ( current_input , RARCH_VOLUME_DOWN ) )
2017-05-11 09:11:46 +02:00
command_event ( CMD_EVENT_VOLUME_DOWN , NULL ) ;
# ifdef HAVE_NETWORKING
2017-05-21 14:18:10 +02:00
/* Check Netplay */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_NETPLAY_GAME_WATCH , CMD_EVENT_NETPLAY_GAME_WATCH , true , NULL ) ;
2017-05-11 09:11:46 +02:00
# endif
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the pause button */
2017-05-21 12:59:36 +02:00
{
2017-05-21 16:31:05 +02:00
static bool old_frameadvance = false ;
2017-05-21 12:59:36 +02:00
static bool old_pause_pressed = false ;
2017-12-05 12:07:35 +01:00
bool frameadvance_pressed = BIT256_GET (
2017-05-21 16:31:05 +02:00
current_input , RARCH_FRAMEADVANCE ) ;
2017-12-05 12:07:35 +01:00
bool pause_pressed = BIT256_GET (
2017-05-21 12:59:36 +02:00
current_input , RARCH_PAUSE_TOGGLE ) ;
2017-05-21 16:31:05 +02:00
bool trig_frameadvance = frameadvance_pressed & & ! old_frameadvance ;
2017-05-21 12:59:36 +02:00
/* Check if libretro pause key was pressed. If so, pause or
* unpause the libretro core . */
/* FRAMEADVANCE will set us into pause mode. */
2019-01-12 17:58:35 +01:00
pause_pressed | = ! runloop_is_paused & & trig_frameadvance ;
2017-05-21 12:59:36 +02:00
if ( focused & & pause_pressed & & ! old_pause_pressed )
command_event ( CMD_EVENT_PAUSE_TOGGLE , NULL ) ;
else if ( focused & & ! old_focus )
command_event ( CMD_EVENT_UNPAUSE , NULL ) ;
else if ( ! focused & & old_focus )
command_event ( CMD_EVENT_PAUSE , NULL ) ;
old_focus = focused ;
2017-07-04 21:46:22 -04:00
old_pause_pressed = pause_pressed ;
2017-05-21 16:31:05 +02:00
old_frameadvance = frameadvance_pressed ;
2017-05-11 09:11:46 +02:00
2019-01-12 17:58:35 +01:00
if ( runloop_is_paused )
2017-05-11 09:11:46 +02:00
{
2019-06-16 16:20:43 +02:00
bool toggle = ! runloop_idle ? true : false ;
HOTKEY_CHECK ( RARCH_FULLSCREEN_TOGGLE_KEY ,
CMD_EVENT_FULLSCREEN_TOGGLE , true , & toggle ) ;
2017-05-21 16:31:05 +02:00
2019-06-09 06:34:01 +02:00
/* Check if it's not oneshot */
if ( ! ( trig_frameadvance | | BIT256_GET ( current_input , RARCH_REWIND ) ) )
focused = false ;
2019-05-31 16:38:17 +02:00
}
2017-05-11 09:11:46 +02:00
}
2017-05-21 16:31:05 +02:00
if ( ! focused )
2019-05-31 16:38:17 +02:00
{
retro_ctx . poll_cb ( ) ;
return RUNLOOP_STATE_POLLED_AND_SLEEP ;
}
2017-05-21 16:31:05 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the fast forward button */
2017-05-11 09:11:46 +02:00
/* To avoid continous switching if we hold the button down, we require
* that the button must go from pressed to unpressed back to pressed
* to be able to toggle between then .
*/
{
2017-05-21 13:32:36 +02:00
static bool old_button_state = false ;
static bool old_hold_button_state = false ;
2017-12-05 12:07:35 +01:00
bool new_button_state = BIT256_GET (
2017-05-21 13:32:36 +02:00
current_input , RARCH_FAST_FORWARD_KEY ) ;
2017-12-05 12:07:35 +01:00
bool new_hold_button_state = BIT256_GET (
2017-05-21 13:32:36 +02:00
current_input , RARCH_FAST_FORWARD_HOLD_KEY ) ;
if ( new_button_state & & ! old_button_state )
{
2018-04-10 07:19:27 +02:00
if ( input_nonblock_state )
{
2017-05-21 13:32:36 +02:00
input_driver_unset_nonblock_state ( ) ;
2019-01-12 17:58:35 +01:00
runloop_fastmotion = false ;
2018-08-05 00:34:10 +02:00
fastforward_after_frames = 1 ;
2017-11-18 10:48:53 -05:00
}
2018-04-10 07:19:27 +02:00
else
{
2017-05-21 13:32:36 +02:00
input_driver_set_nonblock_state ( ) ;
2017-11-18 10:48:53 -05:00
runloop_fastmotion = true ;
}
2017-05-21 13:32:36 +02:00
driver_set_nonblock_state ( ) ;
}
else if ( old_hold_button_state ! = new_hold_button_state )
{
2018-04-10 07:19:27 +02:00
if ( new_hold_button_state )
{
2017-05-21 13:32:36 +02:00
input_driver_set_nonblock_state ( ) ;
2017-11-18 10:48:53 -05:00
runloop_fastmotion = true ;
}
2018-04-10 07:19:27 +02:00
else
{
2017-05-21 13:32:36 +02:00
input_driver_unset_nonblock_state ( ) ;
2019-01-12 17:58:35 +01:00
runloop_fastmotion = false ;
2018-08-05 00:34:10 +02:00
fastforward_after_frames = 1 ;
2017-11-18 10:48:53 -05:00
}
2017-05-21 13:32:36 +02:00
driver_set_nonblock_state ( ) ;
}
2017-11-26 22:53:42 +01:00
/* Display the fast forward state to the user, if needed. */
if ( runloop_fastmotion )
2019-04-08 16:49:15 +02:00
{
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
2019-05-03 21:25:20 +02:00
if ( ! menu_widgets_set_fast_forward ( true ) )
2019-04-08 16:49:15 +02:00
# endif
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAST_FORWARD ) , 1 , 1 , false , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
else
menu_widgets_set_fast_forward ( false ) ;
# endif
2017-11-18 10:48:53 -05:00
2017-05-21 13:32:36 +02:00
old_button_state = new_button_state ;
old_hold_button_state = new_hold_button_state ;
2017-05-11 09:11:46 +02:00
}
2019-02-28 21:54:46 +01:00
/* Check if we have pressed any of the state slot buttons */
2017-05-21 12:09:24 +02:00
{
static bool old_should_slot_increase = false ;
static bool old_should_slot_decrease = false ;
2017-12-05 12:07:35 +01:00
bool should_slot_increase = BIT256_GET (
2017-05-21 12:09:24 +02:00
current_input , RARCH_STATE_SLOT_PLUS ) ;
2017-12-05 12:07:35 +01:00
bool should_slot_decrease = BIT256_GET (
2017-05-21 12:09:24 +02:00
current_input , RARCH_STATE_SLOT_MINUS ) ;
2018-09-27 14:02:11 +02:00
bool should_set = false ;
2019-01-14 05:25:04 +01:00
int cur_state_slot = settings - > ints . state_slot ;
2017-05-21 12:09:24 +02:00
2017-07-04 21:46:22 -04:00
/* Checks if the state increase/decrease keys have been pressed
2017-05-21 12:09:24 +02:00
* for this frame . */
if ( should_slot_increase & & ! old_should_slot_increase )
{
2019-01-14 05:25:04 +01:00
configuration_set_int ( settings , settings - > ints . state_slot , cur_state_slot + 1 ) ;
2017-05-21 12:09:24 +02:00
2018-09-27 14:02:11 +02:00
should_set = true ;
2017-05-21 12:09:24 +02:00
}
else if ( should_slot_decrease & & ! old_should_slot_decrease )
{
2019-01-12 17:58:35 +01:00
if ( cur_state_slot > 0 )
2019-01-14 05:25:04 +01:00
configuration_set_int ( settings , settings - > ints . state_slot , cur_state_slot - 1 ) ;
2018-09-27 14:02:11 +02:00
should_set = true ;
}
if ( should_set )
{
char msg [ 128 ] ;
msg [ 0 ] = ' \0 ' ;
2017-05-21 12:09:24 +02:00
snprintf ( msg , sizeof ( msg ) , " %s: %d " ,
msg_hash_to_str ( MSG_STATE_SLOT ) ,
settings - > ints . state_slot ) ;
2018-11-22 15:45:52 +01:00
runloop_msg_queue_push ( msg , 2 , 180 , true , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
2017-05-21 12:09:24 +02:00
RARCH_LOG ( " %s \n " , msg ) ;
}
old_should_slot_increase = should_slot_increase ;
old_should_slot_decrease = should_slot_decrease ;
}
2019-02-28 21:54:46 +01:00
/* Check if we have pressed any of the savestate buttons */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_SAVE_STATE_KEY , CMD_EVENT_SAVE_STATE , true , NULL ) ;
HOTKEY_CHECK ( RARCH_LOAD_STATE_KEY , CMD_EVENT_LOAD_STATE , true , NULL ) ;
2017-05-11 09:11:46 +02:00
2018-05-14 01:44:08 +02:00
# ifdef HAVE_CHEEVOS
2019-05-16 21:02:46 -05:00
rcheevos_hardcore_active = settings - > bools . cheevos_enable
2019-01-14 05:25:04 +01:00
& & settings - > bools . cheevos_hardcore_mode_enable
2019-05-20 20:24:39 -05:00
& & rcheevos_loaded & & ! rcheevos_hardcore_paused ;
2018-04-30 14:39:20 -05:00
2019-05-29 14:26:22 -03:00
if ( rcheevos_hardcore_active & & rcheevos_state_loaded_flag )
2019-05-21 03:32:18 +02:00
{
2019-05-29 14:26:22 -03:00
rcheevos_hardcore_paused = true ;
runloop_msg_queue_push ( msg_hash_to_str ( MSG_CHEEVOS_HARDCORE_MODE_DISABLED ) , 0 , 180 , true , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
2019-05-21 03:32:18 +02:00
}
2018-09-20 23:20:38 -05:00
2019-05-29 14:26:22 -03:00
if ( ! rcheevos_hardcore_active )
2017-05-11 09:11:46 +02:00
# endif
{
char s [ 128 ] ;
2019-05-16 21:02:46 -05:00
bool rewinding = false ;
2019-04-08 20:48:47 +02:00
unsigned t = 0 ;
2017-05-11 09:11:46 +02:00
2019-04-08 20:48:47 +02:00
s [ 0 ] = ' \0 ' ;
2017-05-11 09:11:46 +02:00
2019-04-08 20:48:47 +02:00
rewinding = state_manager_check_rewind ( BIT256_GET ( current_input , RARCH_REWIND ) ,
2019-04-08 16:47:06 +02:00
settings - > uints . rewind_granularity , runloop_paused , s , sizeof ( s ) , & t ) ;
2017-05-11 09:11:46 +02:00
2019-04-08 16:47:06 +02:00
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
2019-05-03 21:25:20 +02:00
if ( ! menu_widgets_ready ( ) )
2019-04-08 16:47:06 +02:00
# endif
2019-04-08 19:36:44 +02:00
if ( rewinding )
2019-04-08 16:47:06 +02:00
runloop_msg_queue_push ( s , 0 , t , true , NULL ,
MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
2017-05-11 09:11:46 +02:00
2019-04-08 16:47:06 +02:00
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
menu_widgets_set_rewind ( rewinding ) ;
# endif
2017-05-11 09:11:46 +02:00
}
2017-05-21 13:06:48 +02:00
/* Checks if slowmotion toggle/hold was being pressed and/or held. */
2018-04-30 12:27:35 -03:00
# ifdef HAVE_CHEEVOS
2019-05-29 14:26:22 -03:00
if ( ! rcheevos_hardcore_active )
2018-04-30 12:27:35 -03:00
# endif
2017-05-11 09:11:46 +02:00
{
2018-03-10 18:42:45 +01:00
static bool old_slowmotion_button_state = false ;
static bool old_slowmotion_hold_button_state = false ;
bool new_slowmotion_button_state = BIT256_GET (
current_input , RARCH_SLOWMOTION_KEY ) ;
bool new_slowmotion_hold_button_state = BIT256_GET (
current_input , RARCH_SLOWMOTION_HOLD_KEY ) ;
if ( new_slowmotion_button_state & & ! old_slowmotion_button_state )
2019-05-31 15:29:52 +02:00
runloop_slowmotion = ! runloop_slowmotion ;
2018-03-10 18:42:45 +01:00
else if ( old_slowmotion_hold_button_state ! = new_slowmotion_hold_button_state )
2019-05-31 15:29:52 +02:00
runloop_slowmotion = new_slowmotion_hold_button_state ;
2017-05-21 13:06:48 +02:00
if ( runloop_slowmotion )
2017-05-11 09:11:46 +02:00
{
2017-05-21 13:06:48 +02:00
if ( settings - > bools . video_black_frame_insertion )
if ( ! runloop_idle )
video_driver_cached_frame ( ) ;
2017-05-11 09:11:46 +02:00
2019-04-08 16:55:03 +02:00
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
2019-05-03 21:25:20 +02:00
if ( ! menu_widgets_ready ( ) )
2019-04-08 16:55:03 +02:00
{
# endif
if ( state_manager_frame_is_reversed ( ) )
runloop_msg_queue_push (
msg_hash_to_str ( MSG_SLOW_MOTION_REWIND ) , 1 , 1 , false , NULL ,
MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
else
runloop_msg_queue_push (
msg_hash_to_str ( MSG_SLOW_MOTION ) , 1 , 1 , false ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
# if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS)
2017-05-21 13:06:48 +02:00
}
2019-04-08 16:55:03 +02:00
# endif
2018-03-10 18:42:45 +01:00
old_slowmotion_button_state = new_slowmotion_button_state ;
old_slowmotion_hold_button_state = new_slowmotion_hold_button_state ;
2017-05-11 09:11:46 +02:00
}
2017-05-21 13:06:48 +02:00
/* Check movie record toggle */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_BSV_RECORD_TOGGLE , CMD_EVENT_BSV_RECORDING_TOGGLE , true , NULL ) ;
2017-05-11 09:11:46 +02:00
2017-05-21 13:26:25 +02:00
/* Check shader prev/next */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_SHADER_NEXT , CMD_EVENT_SHADER_NEXT , true , NULL ) ;
HOTKEY_CHECK ( RARCH_SHADER_PREV , CMD_EVENT_SHADER_PREV , true , NULL ) ;
2017-05-11 09:11:46 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed any of the disk buttons */
2019-06-09 08:48:59 +02:00
HOTKEY_CHECK3 (
RARCH_DISK_EJECT_TOGGLE , CMD_EVENT_DISK_EJECT_TOGGLE ,
RARCH_DISK_NEXT , CMD_EVENT_DISK_NEXT ,
RARCH_DISK_PREV , CMD_EVENT_DISK_PREV ) ;
2017-05-11 09:11:46 +02:00
2019-02-28 21:54:46 +01:00
/* Check if we have pressed the reset button */
2019-06-16 16:20:43 +02:00
HOTKEY_CHECK ( RARCH_RESET , CMD_EVENT_RESET , true , NULL ) ;
2017-05-11 09:11:46 +02:00
2017-05-21 13:17:48 +02:00
/* Check cheats */
2019-06-09 08:48:59 +02:00
HOTKEY_CHECK3 (
RARCH_CHEAT_INDEX_PLUS , CMD_EVENT_CHEAT_INDEX_PLUS ,
RARCH_CHEAT_INDEX_MINUS , CMD_EVENT_CHEAT_INDEX_MINUS ,
RARCH_CHEAT_TOGGLE , CMD_EVENT_CHEAT_TOGGLE ) ;
2017-05-11 09:11:46 +02:00
2018-01-25 15:50:57 -05:00
if ( settings - > bools . video_shader_watch_files )
{
2018-01-26 20:27:29 -05:00
static rarch_timer_t timer = { 0 } ;
2018-01-25 19:09:55 -05:00
static bool need_to_apply = false ;
2018-01-25 15:50:57 -05:00
if ( video_shader_check_for_changes ( ) )
2018-01-25 19:09:55 -05:00
{
need_to_apply = true ;
2018-01-26 20:27:29 -05:00
if ( ! rarch_timer_is_running ( & timer ) )
{
/* rarch_timer_t convenience functions only support whole seconds. */
/* rarch_timer_begin */
timer . timeout_end = cpu_features_get_time_usec ( ) + SHADER_FILE_WATCH_DELAY_MSEC * 1000 ;
timer . timer_begin = true ;
2018-09-27 14:02:11 +02:00
timer . timer_end = false ;
2018-01-26 20:27:29 -05:00
}
2018-01-25 19:09:55 -05:00
}
/* If a file is modified atomically (moved/renamed from a different file), we have no idea how long that might take.
* If we ' re trying to re - apply shaders immediately after changes are made to the original file ( s ) , the filesystem might be in an in - between
* state where the new file hasn ' t been moved over yet and the original file was already deleted . This leaves us no choice
* but to wait an arbitrary amount of time and hope for the best .
*/
if ( need_to_apply )
{
2018-01-26 20:27:29 -05:00
/* rarch_timer_tick */
2018-09-27 14:02:11 +02:00
timer . current = cpu_features_get_time_usec ( ) ;
2018-04-04 09:37:16 +01:00
timer . timeout_us = ( timer . timeout_end - timer . current ) ;
2018-01-26 20:27:29 -05:00
if ( ! timer . timer_end & & rarch_timer_has_expired ( & timer ) )
2018-01-25 19:09:55 -05:00
{
2018-01-26 20:27:29 -05:00
rarch_timer_end ( & timer ) ;
2018-01-25 19:09:55 -05:00
need_to_apply = false ;
command_event ( CMD_EVENT_SHADERS_APPLY_CHANGES , NULL ) ;
}
}
2018-01-25 15:50:57 -05:00
}
2017-05-11 09:11:46 +02:00
return RUNLOOP_STATE_ITERATE ;
}
void runloop_set ( enum runloop_action action )
{
switch ( action )
{
case RUNLOOP_ACTION_AUTOSAVE :
runloop_autosave = true ;
break ;
case RUNLOOP_ACTION_NONE :
break ;
}
}
void runloop_unset ( enum runloop_action action )
{
switch ( action )
{
case RUNLOOP_ACTION_AUTOSAVE :
runloop_autosave = false ;
break ;
case RUNLOOP_ACTION_NONE :
break ;
}
}
/**
* runloop_iterate :
*
* Run Libretro core in RetroArch for one frame .
*
* Returns : 0 on success , 1 if we have to wait until
* button input in order to wake up the loop ,
* - 1 if we forcibly quit out of the RetroArch iteration loop .
* */
int runloop_iterate ( unsigned * sleep_ms )
{
unsigned i ;
2019-01-12 17:58:35 +01:00
bool runloop_is_paused = runloop_paused ;
2017-05-21 21:55:20 +02:00
bool input_nonblock_state = input_driver_is_nonblock_state ( ) ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-01-12 17:58:35 +01:00
float fastforward_ratio = settings - > floats . fastforward_ratio ;
unsigned video_frame_delay = settings - > uints . video_frame_delay ;
bool vrr_runloop_enable = settings - > bools . vrr_runloop_enable ;
2017-05-11 09:11:46 +02:00
unsigned max_users = * ( input_driver_get_uint ( INPUT_ACTION_MAX_USERS ) ) ;
2017-05-20 22:55:12 +02:00
2018-09-09 16:41:50 -05:00
# ifdef HAVE_DISCORD
2018-09-15 07:17:29 +02:00
if ( discord_is_inited )
2018-09-09 16:41:50 -05:00
discord_run_callbacks ( ) ;
# endif
2017-05-11 09:11:46 +02:00
if ( runloop_frame_time . callback )
{
/* Updates frame timing if frame timing callback is in use by the core.
* Limits frame time if fast forward ratio throttle is enabled . */
2019-01-12 17:58:35 +01:00
retro_usec_t runloop_last_frame_time = runloop_frame_time_last ;
retro_time_t current = cpu_features_get_time_usec ( ) ;
bool is_locked_fps = ( runloop_is_paused | | input_nonblock_state )
| ! ! recording_data ;
retro_time_t delta = ( ! runloop_last_frame_time | | is_locked_fps ) ?
runloop_frame_time . reference
: ( current - runloop_last_frame_time ) ;
2017-05-11 09:11:46 +02:00
if ( is_locked_fps )
runloop_frame_time_last = 0 ;
2019-01-12 17:58:35 +01:00
else
{
float slowmotion_ratio = settings - > floats . slowmotion_ratio ;
runloop_frame_time_last = current ;
if ( runloop_slowmotion )
delta / = slowmotion_ratio ;
}
2017-05-11 09:11:46 +02:00
runloop_frame_time . callback ( delta ) ;
}
switch ( ( enum runloop_state )
runloop_check_state (
settings ,
2017-05-21 21:55:20 +02:00
input_nonblock_state ,
2019-01-12 17:58:35 +01:00
runloop_is_paused ,
fastforward_ratio ,
2017-05-11 09:11:46 +02:00
sleep_ms ) )
{
case RUNLOOP_STATE_QUIT :
frame_limit_last_time = 0.0 ;
command_event ( CMD_EVENT_QUIT , NULL ) ;
return - 1 ;
2017-05-29 20:30:01 +02:00
case RUNLOOP_STATE_POLLED_AND_SLEEP :
runloop_netplay_pause ( ) ;
* sleep_ms = 10 ;
return 1 ;
2017-05-11 09:11:46 +02:00
case RUNLOOP_STATE_END :
2019-05-27 04:04:27 +02:00
# ifdef HAVE_NETWORKING
2019-05-26 15:17:31 -05:00
if ( netplay_driver_ctl ( RARCH_NETPLAY_CTL_IS_ENABLED , NULL )
2019-05-31 16:38:17 +02:00
& & settings - > bools . menu_pause_libretro )
2019-05-26 15:17:31 -05:00
runloop_netplay_pause ( ) ;
2019-05-27 04:04:27 +02:00
# endif
2017-05-11 09:11:46 +02:00
goto end ;
case RUNLOOP_STATE_MENU_ITERATE :
2019-05-27 04:04:27 +02:00
# ifdef HAVE_NETWORKING
runloop_netplay_pause ( ) ;
2017-05-11 09:11:46 +02:00
return 0 ;
2019-05-27 04:04:27 +02:00
# endif
2017-05-11 09:11:46 +02:00
case RUNLOOP_STATE_ITERATE :
break ;
}
if ( runloop_autosave )
autosave_lock ( ) ;
2019-01-13 07:46:35 +01:00
/* Used for rewinding while playback/record. */
if ( bsv_movie_state_handle )
bsv_movie_state_handle - > frame_pos [ bsv_movie_state_handle - > frame_ptr ]
= intfstream_tell ( bsv_movie_state_handle - > file ) ;
2017-05-11 09:11:46 +02:00
2019-06-17 11:18:27 +02:00
if ( camera_cb . caps & & camera_driver & & camera_driver - > poll & & camera_data )
camera_driver - > poll ( camera_data ,
camera_cb . frame_raw_framebuffer ,
camera_cb . frame_opengl_texture ) ;
2017-05-11 09:11:46 +02:00
/* Update binds for analog dpad modes. */
for ( i = 0 ; i < max_users ; i + + )
{
enum analog_dpad_mode dpad_mode = ( enum analog_dpad_mode ) settings - > uints . input_analog_dpad_mode [ i ] ;
2019-06-17 10:14:41 +02:00
if ( dpad_mode ! = ANALOG_DPAD_NONE )
{
struct retro_keybind * general_binds = input_config_binds [ i ] ;
struct retro_keybind * auto_binds = input_autoconf_binds [ i ] ;
input_push_analog_dpad ( general_binds , dpad_mode ) ;
input_push_analog_dpad ( auto_binds , dpad_mode ) ;
}
2017-05-11 09:11:46 +02:00
}
2019-01-12 17:58:35 +01:00
if ( ( video_frame_delay > 0 ) & & ! input_nonblock_state )
retro_sleep ( video_frame_delay ) ;
2017-05-11 09:11:46 +02:00
2018-03-29 15:38:22 +02:00
# ifdef HAVE_RUNAHEAD
2019-01-12 17:58:35 +01:00
{
unsigned run_ahead_num_frames = settings - > uints . run_ahead_frames ;
/* Run Ahead Feature replaces the call to core_run in this loop */
if ( settings - > bools . run_ahead_enabled & & run_ahead_num_frames > 0
2018-05-30 22:01:02 -04:00
# ifdef HAVE_NETWORKING
2019-01-12 17:58:35 +01:00
& & ! netplay_driver_ctl ( RARCH_NETPLAY_CTL_IS_ENABLED , NULL )
2018-05-30 22:01:02 -04:00
# endif
2019-01-12 17:58:35 +01:00
)
run_ahead ( run_ahead_num_frames , settings - > bools . run_ahead_secondary_instance ) ;
else
core_run ( ) ;
}
# else
2019-02-12 00:32:01 -05:00
{
core_run ( ) ;
}
2018-03-29 15:38:22 +02:00
# endif
2017-05-11 09:11:46 +02:00
2019-03-04 11:33:19 +00:00
/* Increment runtime tick counter after each call to
* core_run ( ) or run_ahead ( ) */
rarch_core_runtime_tick ( ) ;
2017-05-11 09:11:46 +02:00
# ifdef HAVE_CHEEVOS
2019-05-29 14:26:22 -03:00
if ( runloop_check_cheevos ( ) )
rcheevos_test ( ) ;
2017-05-11 09:11:46 +02:00
# endif
2019-01-12 17:58:35 +01:00
cheat_manager_apply_retro_cheats ( ) ;
2018-07-25 19:19:14 -04:00
2018-05-28 23:43:30 -05:00
# ifdef HAVE_DISCORD
2018-05-29 11:06:43 +02:00
if ( discord_is_inited )
2018-05-29 12:41:13 +02:00
{
discord_userdata_t userdata ;
userdata . status = DISCORD_PRESENCE_GAME ;
command_event ( CMD_EVENT_DISCORD_UPDATE , & userdata ) ;
}
2018-05-28 23:43:30 -05:00
# endif
2017-05-11 09:11:46 +02:00
for ( i = 0 ; i < max_users ; i + + )
{
enum analog_dpad_mode dpad_mode = ( enum analog_dpad_mode ) settings - > uints . input_analog_dpad_mode [ i ] ;
2019-06-17 10:14:41 +02:00
if ( dpad_mode ! = ANALOG_DPAD_NONE )
{
struct retro_keybind * general_binds = input_config_binds [ i ] ;
struct retro_keybind * auto_binds = input_autoconf_binds [ i ] ;
2017-05-11 09:11:46 +02:00
2019-06-17 10:14:41 +02:00
input_pop_analog_dpad ( general_binds ) ;
input_pop_analog_dpad ( auto_binds ) ;
}
2017-05-11 09:11:46 +02:00
}
2019-01-13 07:46:35 +01:00
if ( bsv_movie_state_handle )
{
bsv_movie_state_handle - > frame_ptr =
( bsv_movie_state_handle - > frame_ptr + 1 )
& bsv_movie_state_handle - > frame_mask ;
bsv_movie_state_handle - > first_rewind =
! bsv_movie_state_handle - > did_rewind ;
bsv_movie_state_handle - > did_rewind = false ;
}
2017-05-11 09:11:46 +02:00
if ( runloop_autosave )
autosave_unlock ( ) ;
2018-08-05 00:34:10 +02:00
/* Condition for max speed x0.0 when vrr_runloop is off to skip that part */
2019-06-02 17:18:52 +02:00
if ( ! ( fastforward_ratio | | vrr_runloop_enable ) )
return 0 ;
2018-08-18 23:09:40 -04:00
2019-06-02 17:18:52 +02:00
end :
if ( vrr_runloop_enable )
{
struct retro_system_av_info * av_info =
2018-08-05 00:34:10 +02:00
video_viewport_get_system_av_info ( ) ;
2019-06-02 17:18:52 +02:00
/* Sync on video only, block audio later. */
if ( fastforward_after_frames & & settings - > bools . audio_sync )
{
if ( fastforward_after_frames = = 1 )
command_event ( CMD_EVENT_AUDIO_SET_NONBLOCKING_STATE , NULL ) ;
2018-08-05 00:34:10 +02:00
2019-06-02 17:18:52 +02:00
fastforward_after_frames + + ;
2018-08-05 00:34:10 +02:00
2019-06-02 17:18:52 +02:00
if ( fastforward_after_frames = = 6 )
{
command_event ( CMD_EVENT_AUDIO_SET_BLOCKING_STATE , NULL ) ;
fastforward_after_frames = 0 ;
2018-08-05 00:34:10 +02:00
}
2019-06-02 17:18:52 +02:00
}
2018-08-05 00:34:10 +02:00
2019-06-02 17:18:52 +02:00
/* Fast Forward for max speed x0.0 */
if ( ! fastforward_ratio & & runloop_fastmotion )
return 0 ;
2018-08-05 00:34:10 +02:00
2019-06-02 17:18:52 +02:00
frame_limit_minimum_time =
( retro_time_t ) roundf ( 1000000.0f / ( av_info - > timing . fps *
( runloop_fastmotion ? fastforward_ratio : 1.0f ) ) ) ;
}
2018-08-05 00:34:10 +02:00
2019-06-02 17:18:52 +02:00
{
retro_time_t to_sleep_ms = (
2017-05-21 22:43:40 +02:00
( frame_limit_last_time + frame_limit_minimum_time )
- cpu_features_get_time_usec ( ) ) / 1000 ;
2017-05-11 09:11:46 +02:00
2017-05-21 22:43:40 +02:00
if ( to_sleep_ms > 0 )
{
2019-01-12 17:58:35 +01:00
* sleep_ms = ( unsigned ) to_sleep_ms ;
2017-05-21 22:43:40 +02:00
/* Combat jitter a bit. */
frame_limit_last_time + = frame_limit_minimum_time ;
return 1 ;
}
2017-05-11 09:11:46 +02:00
}
2019-06-02 17:18:52 +02:00
frame_limit_last_time = cpu_features_get_time_usec ( ) ;
2017-05-11 09:11:46 +02:00
return 0 ;
}
rarch_system_info_t * runloop_get_system_info ( void )
{
return & runloop_system ;
}
2018-10-30 08:21:32 +01:00
struct retro_system_info * runloop_get_libretro_system_info ( void )
{
struct retro_system_info * system = & runloop_system . info ;
return system ;
}
2019-01-05 15:11:58 -05:00
char * get_retroarch_launch_arguments ( void )
{
return launch_arguments ;
2019-01-06 17:04:28 +01:00
}
2019-01-31 09:48:10 -05:00
void rarch_force_video_driver_fallback ( const char * driver )
{
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-01-31 09:48:10 -05:00
ui_msg_window_t * msg_window = NULL ;
2019-03-11 16:58:43 +01:00
strlcpy ( settings - > arrays . video_driver ,
driver , sizeof ( settings - > arrays . video_driver ) ) ;
2019-01-31 09:48:10 -05:00
command_event ( CMD_EVENT_MENU_SAVE_CURRENT_CONFIG , NULL ) ;
2019-02-04 23:13:56 +01:00
# if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) && !defined(WINAPI_FAMILY)
2019-01-31 09:48:10 -05:00
/* UI companion driver is not inited yet, just call into it directly */
msg_window = & ui_msg_window_win32 ;
# endif
if ( msg_window )
{
char text [ PATH_MAX_LENGTH ] ;
2019-03-11 16:58:43 +01:00
ui_msg_window_state window_state ;
char * title = strdup ( msg_hash_to_str ( MSG_ERROR ) ) ;
2019-01-31 09:48:10 -05:00
2019-01-31 20:12:41 +01:00
text [ 0 ] = ' \0 ' ;
2019-01-31 09:48:10 -05:00
2019-01-31 20:12:41 +01:00
snprintf ( text , sizeof ( text ) ,
msg_hash_to_str ( MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER_FALLBACK ) ,
driver ) ;
2019-01-31 09:48:10 -05:00
window_state . buttons = UI_MSG_WINDOW_OK ;
2019-01-31 20:12:41 +01:00
window_state . text = strdup ( text ) ;
window_state . title = title ;
window_state . window = NULL ;
2019-01-31 09:48:10 -05:00
msg_window - > error ( & window_state ) ;
free ( title ) ;
}
exit ( 1 ) ;
}
2019-03-07 19:17:54 -05:00
void rarch_get_cpu_architecture_string ( char * cpu_arch_str , size_t len )
{
enum frontend_architecture arch = frontend_driver_get_cpu_architecture ( ) ;
if ( ! cpu_arch_str | | ! len )
return ;
switch ( arch )
{
case FRONTEND_ARCH_X86 :
strlcpy ( cpu_arch_str , " x86 " , len ) ;
break ;
case FRONTEND_ARCH_X86_64 :
strlcpy ( cpu_arch_str , " x64 " , len ) ;
break ;
case FRONTEND_ARCH_PPC :
strlcpy ( cpu_arch_str , " PPC " , len ) ;
break ;
case FRONTEND_ARCH_ARM :
strlcpy ( cpu_arch_str , " ARM " , len ) ;
break ;
case FRONTEND_ARCH_ARMV7 :
strlcpy ( cpu_arch_str , " ARMv7 " , len ) ;
break ;
case FRONTEND_ARCH_ARMV8 :
strlcpy ( cpu_arch_str , " ARMv8 " , len ) ;
break ;
case FRONTEND_ARCH_MIPS :
strlcpy ( cpu_arch_str , " MIPS " , len ) ;
break ;
case FRONTEND_ARCH_TILE :
strlcpy ( cpu_arch_str , " Tilera " , len ) ;
break ;
case FRONTEND_ARCH_NONE :
default :
strlcpy ( cpu_arch_str ,
msg_hash_to_str ( MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE ) ,
len ) ;
break ;
}
}
bool rarch_write_debug_info ( void )
{
2019-03-11 16:58:43 +01:00
int i ;
2019-03-07 19:17:54 -05:00
char str [ PATH_MAX_LENGTH ] ;
char debug_filepath [ PATH_MAX_LENGTH ] ;
2019-04-22 04:25:43 +02:00
gfx_ctx_mode_t mode_info = { 0 } ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-03-11 16:58:43 +01:00
RFILE * file = NULL ;
2019-03-07 19:17:54 -05:00
const frontend_ctx_driver_t * frontend = frontend_get_ptr ( ) ;
2019-03-11 16:58:43 +01:00
const char * cpu_model = NULL ;
const char * path_config = path_get ( RARCH_PATH_CONFIG ) ;
unsigned lang =
* msg_hash_get_uint ( MSG_HASH_USER_LANGUAGE ) ;
2019-03-07 19:17:54 -05:00
2019-04-22 04:25:43 +02:00
str [ 0 ] =
debug_filepath [ 0 ] = ' \0 ' ;
2019-03-07 19:17:54 -05:00
2019-03-11 16:58:43 +01:00
/* Only print our debug info in English */
2019-03-07 19:17:54 -05:00
if ( lang ! = RETRO_LANGUAGE_ENGLISH )
msg_hash_set_uint ( MSG_HASH_USER_LANGUAGE , RETRO_LANGUAGE_ENGLISH ) ;
fill_pathname_resolve_relative (
debug_filepath ,
path_config ,
DEBUG_INFO_FILENAME ,
sizeof ( debug_filepath ) ) ;
2019-03-11 16:58:43 +01:00
file = filestream_open ( debug_filepath ,
RETRO_VFS_FILE_ACCESS_WRITE , RETRO_VFS_FILE_ACCESS_HINT_NONE ) ;
2019-03-07 19:17:54 -05:00
if ( ! file )
{
RARCH_ERR ( " Could not open debug info file for writing: %s \n " , debug_filepath ) ;
goto error ;
}
# ifdef HAVE_MENU
{
time_t time_ ;
char timedate [ 255 ] ;
timedate [ 0 ] = ' \0 ' ;
time ( & time_ ) ;
setlocale ( LC_TIME , " " ) ;
strftime ( timedate , sizeof ( timedate ) ,
" %Y-%m-%d %H:%M:%S " , localtime ( & time_ ) ) ;
filestream_printf ( file , " Log Date/Time: %s \n " , timedate ) ;
}
# endif
filestream_printf ( file , " RetroArch Version: %s \n " , PACKAGE_VERSION ) ;
# ifdef HAVE_LAKKA
if ( frontend - > get_lakka_version )
{
frontend - > get_lakka_version ( str , sizeof ( str ) ) ;
filestream_printf ( file , " Lakka Version: %s \n " , str ) ;
str [ 0 ] = ' \0 ' ;
}
# endif
filestream_printf ( file , " RetroArch Build Date: %s \n " , __DATE__ ) ;
# ifdef HAVE_GIT_VERSION
filestream_printf ( file , " RetroArch Git Commit: %s \n " , retroarch_git_version ) ;
# endif
filestream_printf ( file , " \n " ) ;
cpu_model = frontend_driver_get_cpu_model_name ( ) ;
if ( ! string_is_empty ( cpu_model ) )
filestream_printf ( file , " CPU Model Name: %s \n " , cpu_model ) ;
retroarch_get_capabilities ( RARCH_CAPABILITIES_CPU , str , sizeof ( str ) ) ;
filestream_printf ( file , " CPU Capabilities: %s \n " , str ) ;
str [ 0 ] = ' \0 ' ;
rarch_get_cpu_architecture_string ( str , sizeof ( str ) ) ;
filestream_printf ( file , " CPU Architecture: %s \n " , str ) ;
filestream_printf ( file , " CPU Cores: %u \n " , cpu_features_get_core_amount ( ) ) ;
{
uint64_t memory_used = frontend_driver_get_used_memory ( ) ;
uint64_t memory_total = frontend_driver_get_total_memory ( ) ;
filestream_printf ( file , " Memory: % " PRIu64 " /% " PRIu64 " MB \n " , memory_used / 1024 / 1024 , memory_total / 1024 / 1024 ) ;
}
filestream_printf ( file , " GPU Device: %s \n " , ! string_is_empty ( video_driver_get_gpu_device_string ( ) ) ?
video_driver_get_gpu_device_string ( ) : " n/a " ) ;
filestream_printf ( file , " GPU API/Driver Version: %s \n " , ! string_is_empty ( video_driver_get_gpu_api_version_string ( ) ) ?
video_driver_get_gpu_api_version_string ( ) : " n/a " ) ;
filestream_printf ( file , " \n " ) ;
video_context_driver_get_video_size ( & mode_info ) ;
filestream_printf ( file , " Window Resolution: %u x %u \n " , mode_info . width , mode_info . height ) ;
{
float width = 0 , height = 0 , refresh = 0.0f ;
2019-03-13 17:00:52 +01:00
gfx_ctx_metrics_t metrics ;
metrics . type = DISPLAY_METRIC_PIXEL_WIDTH ;
2019-03-07 19:17:54 -05:00
metrics . value = & width ;
2019-03-13 17:00:52 +01:00
2019-03-07 19:17:54 -05:00
video_context_driver_get_metrics ( & metrics ) ;
metrics . type = DISPLAY_METRIC_PIXEL_HEIGHT ;
metrics . value = & height ;
video_context_driver_get_metrics ( & metrics ) ;
video_context_driver_get_refresh_rate ( & refresh ) ;
filestream_printf ( file , " Monitor Resolution: %d x %d @ %.2f Hz (configured for %.2f Hz) \n " , ( int ) width , ( int ) height , refresh , settings - > floats . video_refresh_rate ) ;
}
filestream_printf ( file , " \n " ) ;
str [ 0 ] = ' \0 ' ;
retroarch_get_capabilities ( RARCH_CAPABILITIES_COMPILER , str , sizeof ( str ) ) ;
filestream_printf ( file , " %s \n " , str ) ;
str [ 0 ] = ' \0 ' ;
filestream_printf ( file , " Frontend Identifier: %s \n " , frontend - > ident ) ;
if ( frontend - > get_name )
{
frontend - > get_name ( str , sizeof ( str ) ) ;
filestream_printf ( file , " Frontend Name: %s \n " , str ) ;
str [ 0 ] = ' \0 ' ;
}
if ( frontend - > get_os )
{
int major = 0 , minor = 0 ;
const char * warning = " " ;
frontend - > get_os ( str , sizeof ( str ) , & major , & minor ) ;
if ( strstr ( str , " Build 16299 " ) )
warning = " (WARNING: Fall Creator's Update detected... OpenGL performance may be low) " ;
filestream_printf ( file , " Frontend OS: %s (v%d.%d)%s \n " , str , major , minor , warning ) ;
str [ 0 ] = ' \0 ' ;
}
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Input Devices (autoconfig is %s): \n " , settings - > bools . input_autodetect_enable ? " enabled " : " disabled " ) ;
for ( i = 0 ; i < 4 ; i + + )
{
if ( input_is_autoconfigured ( i ) )
{
unsigned retro_id ;
2019-04-22 04:41:16 +02:00
unsigned rebind = 0 ;
unsigned device = settings - > uints . input_libretro_device [ i ] ;
2019-03-07 19:17:54 -05:00
2019-04-22 04:41:16 +02:00
device & = RETRO_DEVICE_MASK ;
2019-03-07 19:17:54 -05:00
if ( device = = RETRO_DEVICE_JOYPAD | | device = = RETRO_DEVICE_ANALOG )
{
for ( retro_id = 0 ; retro_id < RARCH_ANALOG_BIND_LIST_END ; retro_id + + )
{
char descriptor [ 300 ] ;
2019-04-22 04:41:16 +02:00
const struct retro_keybind * keybind = & input_config_binds [ i ] [ retro_id ] ;
const struct retro_keybind * auto_bind = ( const struct retro_keybind * )
2019-03-07 19:17:54 -05:00
input_config_get_bind_auto ( i , retro_id ) ;
input_config_get_bind_string ( descriptor ,
keybind , auto_bind , sizeof ( descriptor ) ) ;
2019-04-22 04:41:16 +02:00
if ( ! strstr ( descriptor , " Auto " )
& & auto_bind
& & ! auto_bind - > valid
& & ( auto_bind - > joykey ! = 0xFFFF )
& & ! string_is_empty ( auto_bind - > joykey_label ) )
2019-03-07 19:17:54 -05:00
rebind + + ;
}
}
if ( rebind )
filestream_printf ( file , " - Port #%d autoconfigured (WARNING: %u keys rebinded): \n " , i , rebind ) ;
else
filestream_printf ( file , " - Port #%d autoconfigured: \n " , i ) ;
filestream_printf ( file , " - Device name: %s (#%d) \n " ,
input_config_get_device_name ( i ) ,
input_autoconfigure_get_device_name_index ( i ) ) ;
filestream_printf ( file , " - Display name: %s \n " ,
input_config_get_device_display_name ( i ) ?
input_config_get_device_display_name ( i ) : " N/A " ) ;
filestream_printf ( file , " - Config path: %s \n " ,
input_config_get_device_display_name ( i ) ?
input_config_get_device_config_path ( i ) : " N/A " ) ;
filestream_printf ( file , " - VID/PID: %d/%d (0x%04X/0x%04X) \n " ,
input_config_get_vid ( i ) , input_config_get_pid ( i ) ,
input_config_get_vid ( i ) , input_config_get_pid ( i ) ) ;
}
else
filestream_printf ( file , " - Port #%d not autoconfigured \n " , i ) ;
}
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Drivers: \n " ) ;
{
gfx_ctx_ident_t ident_info = { 0 } ;
const input_driver_t * input_driver ;
const input_device_driver_t * joypad_driver ;
2019-03-27 02:37:34 +01:00
const char * driver ;
# ifdef HAVE_MENU
driver = menu_driver_ident ( ) ;
2019-03-07 19:17:54 -05:00
if ( string_is_equal ( driver , settings - > arrays . menu_driver ) )
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Menu: %s \n " ,
! string_is_empty ( driver ) ? driver : " n/a " ) ;
2019-03-07 19:17:54 -05:00
else
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Menu: %s (configured for %s) \n " ,
! string_is_empty ( driver )
? driver
: " n/a " ,
! string_is_empty ( settings - > arrays . menu_driver )
? settings - > arrays . menu_driver
: " n/a " ) ;
2019-03-27 02:37:34 +01:00
# endif
2019-03-07 19:17:54 -05:00
driver =
# ifdef HAVE_THREADS
2019-06-17 15:10:22 +02:00
( video_driver_is_threaded_internal ( ) ) ?
2019-03-07 19:17:54 -05:00
video_thread_get_ident ( ) :
# endif
video_driver_get_ident ( ) ;
if ( string_is_equal ( driver , settings - > arrays . video_driver ) )
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Video: %s \n " ,
! string_is_empty ( driver )
? driver
: " n/a " ) ;
2019-03-07 19:17:54 -05:00
else
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Video: %s (configured for %s) \n " ,
! string_is_empty ( driver )
? driver
: " n/a " ,
! string_is_empty ( settings - > arrays . video_driver )
? settings - > arrays . video_driver
: " n/a " ) ;
2019-03-07 19:17:54 -05:00
video_context_driver_get_ident ( & ident_info ) ;
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Video Context: %s \n " ,
ident_info . ident ? ident_info . ident : " n/a " ) ;
2019-03-07 19:17:54 -05:00
driver = audio_driver_get_ident ( ) ;
if ( string_is_equal ( driver , settings - > arrays . audio_driver ) )
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Audio: %s \n " ,
! string_is_empty ( driver ) ? driver : " n/a " ) ;
2019-03-07 19:17:54 -05:00
else
2019-04-22 04:41:16 +02:00
filestream_printf ( file , " - Audio: %s (configured for %s) \n " ,
! string_is_empty ( driver ) ? driver : " n/a " ,
! string_is_empty ( settings - > arrays . audio_driver ) ? settings - > arrays . audio_driver : " n/a " ) ;
2019-03-07 19:17:54 -05:00
input_driver = input_get_ptr ( ) ;
if ( input_driver & & string_is_equal ( input_driver - > ident , settings - > arrays . input_driver ) )
filestream_printf ( file , " - Input: %s \n " , ! string_is_empty ( input_driver - > ident ) ? input_driver - > ident : " n/a " ) ;
else
filestream_printf ( file , " - Input: %s (configured for %s) \n " , ! string_is_empty ( input_driver - > ident ) ? input_driver - > ident : " n/a " , ! string_is_empty ( settings - > arrays . input_driver ) ? settings - > arrays . input_driver : " n/a " ) ;
joypad_driver = ( input_driver - > get_joypad_driver ? input_driver - > get_joypad_driver ( input_driver_get_data ( ) ) : NULL ) ;
if ( joypad_driver & & string_is_equal ( joypad_driver - > ident , settings - > arrays . input_joypad_driver ) )
filestream_printf ( file , " - Joypad: %s \n " , ! string_is_empty ( joypad_driver - > ident ) ? joypad_driver - > ident : " n/a " ) ;
else
2019-06-02 20:25:11 -04:00
filestream_printf ( file , " - Joypad: %s (configured for %s) \n " , ! string_is_empty ( joypad_driver - > ident ) ? joypad_driver - > ident : " n/a " , ! string_is_empty ( settings - > arrays . input_joypad_driver ) ? settings - > arrays . input_joypad_driver : " n/a " ) ;
2019-03-07 19:17:54 -05:00
}
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Configuration related settings: \n " ) ;
filestream_printf ( file , " - Save on exit: %s \n " , settings - > bools . config_save_on_exit ? " yes " : " no " ) ;
filestream_printf ( file , " - Load content-specific core options automatically: %s \n " , settings - > bools . game_specific_options ? " yes " : " no " ) ;
filestream_printf ( file , " - Load override files automatically: %s \n " , settings - > bools . auto_overrides_enable ? " yes " : " no " ) ;
filestream_printf ( file , " - Load remap files automatically: %s \n " , settings - > bools . auto_remaps_enable ? " yes " : " no " ) ;
filestream_printf ( file , " - Sort saves in folders: %s \n " , settings - > bools . sort_savefiles_enable ? " yes " : " no " ) ;
filestream_printf ( file , " - Sort states in folders: %s \n " , settings - > bools . sort_savestates_enable ? " yes " : " no " ) ;
filestream_printf ( file , " - Write saves in content dir: %s \n " , settings - > bools . savefiles_in_content_dir ? " yes " : " no " ) ;
filestream_printf ( file , " - Write savestates in content dir: %s \n " , settings - > bools . savestates_in_content_dir ? " yes " : " no " ) ;
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Auto load state: %s \n " , settings - > bools . savestate_auto_load ? " yes (WARNING: not compatible with all cores) " : " no " ) ;
filestream_printf ( file , " Auto save state: %s \n " , settings - > bools . savestate_auto_save ? " yes " : " no " ) ;
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Buildbot cores URL: %s \n " , settings - > paths . network_buildbot_url ) ;
filestream_printf ( file , " Auto-extract downloaded archives: %s \n " , settings - > bools . network_buildbot_auto_extract_archive ? " yes " : " no " ) ;
{
size_t count = 0 ;
core_info_list_t * core_info_list = NULL ;
struct string_list * list = NULL ;
const char * ext = file_path_str ( FILE_PATH_RDB_EXTENSION ) ;
/* remove dot */
if ( ! string_is_empty ( ext ) & & ext [ 0 ] = = ' . ' & & strlen ( ext ) > 1 )
ext + + ;
core_info_get_list ( & core_info_list ) ;
if ( core_info_list )
count = core_info_list - > count ;
filestream_printf ( file , " Core info: %u entries \n " , count ) ;
count = 0 ;
list = dir_list_new ( settings - > paths . path_content_database , ext , false , true , false , true ) ;
if ( list )
{
count = list - > size ;
string_list_free ( list ) ;
}
filestream_printf ( file , " Databases: %u entries \n " , count ) ;
}
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Performance and latency-sensitive features (may have a large impact depending on the core): \n " ) ;
filestream_printf ( file , " - Video: \n " ) ;
filestream_printf ( file , " - Runahead: %s \n " , settings - > bools . run_ahead_enabled ? " yes (WARNING: not compatible with all cores) " : " no " ) ;
filestream_printf ( file , " - Rewind: %s \n " , settings - > bools . rewind_enable ? " yes (WARNING: not compatible with all cores) " : " no " ) ;
filestream_printf ( file , " - Hard GPU Sync: %s \n " , settings - > bools . video_hard_sync ? " yes " : " no " ) ;
filestream_printf ( file , " - Frame Delay: %u frames \n " , settings - > uints . video_frame_delay ) ;
filestream_printf ( file , " - Max Swapchain Images: %u \n " , settings - > uints . video_max_swapchain_images ) ;
filestream_printf ( file , " - Max Run Speed: %.1f x \n " , settings - > floats . fastforward_ratio ) ;
filestream_printf ( file , " - Sync to exact content framerate: %s \n " , settings - > bools . vrr_runloop_enable ? " yes (note: designed for G-Sync/FreeSync displays only) " : " no " ) ;
filestream_printf ( file , " - Fullscreen: %s \n " , settings - > bools . video_fullscreen ? " yes " : " no " ) ;
filestream_printf ( file , " - Windowed Fullscreen: %s \n " , settings - > bools . video_windowed_fullscreen ? " yes " : " no " ) ;
filestream_printf ( file , " - Threaded Video: %s \n " , settings - > bools . video_threaded ? " yes " : " no " ) ;
filestream_printf ( file , " - Vsync: %s \n " , settings - > bools . video_vsync ? " yes " : " no " ) ;
filestream_printf ( file , " - Vsync Swap Interval: %u frames \n " , settings - > uints . video_swap_interval ) ;
filestream_printf ( file , " - Black Frame Insertion: %s \n " , settings - > bools . video_black_frame_insertion ? " yes " : " no " ) ;
filestream_printf ( file , " - Bilinear Filtering: %s \n " , settings - > bools . video_smooth ? " yes " : " no " ) ;
filestream_printf ( file , " - Video CPU Filter: %s \n " , ! string_is_empty ( settings - > paths . path_softfilter_plugin ) ? settings - > paths . path_softfilter_plugin : " n/a " ) ;
filestream_printf ( file , " - CRT SwitchRes: %s \n " , ( settings - > uints . crt_switch_resolution > CRT_SWITCH_NONE ) ? " yes " : " no " ) ;
filestream_printf ( file , " - Video Shared Context: %s \n " , settings - > bools . video_shared_context ? " yes " : " no " ) ;
{
video_shader_ctx_t shader_info = { 0 } ;
video_shader_driver_get_current_shader ( & shader_info ) ;
if ( shader_info . data )
{
if ( string_is_equal ( shader_info . data - > path , settings - > paths . path_shader ) )
filestream_printf ( file , " - Video Shader: %s \n " , ! string_is_empty ( settings - > paths . path_shader ) ? settings - > paths . path_shader : " n/a " ) ;
else
filestream_printf ( file , " - Video Shader: %s (configured for %s) \n " , ! string_is_empty ( shader_info . data - > path ) ? shader_info . data - > path : " n/a " , ! string_is_empty ( settings - > paths . path_shader ) ? settings - > paths . path_shader : " n/a " ) ;
}
else
filestream_printf ( file , " - Video Shader: n/a \n " ) ;
}
filestream_printf ( file , " - Audio: \n " ) ;
filestream_printf ( file , " - Audio Enabled: %s \n " , settings - > bools . audio_enable ? " yes " : " no (WARNING: content framerate will be incorrect) " ) ;
filestream_printf ( file , " - Audio Sync: %s \n " , settings - > bools . audio_sync ? " yes " : " no (WARNING: content framerate will be incorrect) " ) ;
{
const char * s = NULL ;
switch ( settings - > uints . audio_resampler_quality )
{
case RESAMPLER_QUALITY_DONTCARE :
s = msg_hash_to_str ( MENU_ENUM_LABEL_VALUE_DONT_CARE ) ;
break ;
case RESAMPLER_QUALITY_LOWEST :
s = msg_hash_to_str ( MSG_RESAMPLER_QUALITY_LOWEST ) ;
break ;
case RESAMPLER_QUALITY_LOWER :
s = msg_hash_to_str ( MSG_RESAMPLER_QUALITY_LOWER ) ;
break ;
case RESAMPLER_QUALITY_HIGHER :
s = msg_hash_to_str ( MSG_RESAMPLER_QUALITY_HIGHER ) ;
break ;
case RESAMPLER_QUALITY_HIGHEST :
s = msg_hash_to_str ( MSG_RESAMPLER_QUALITY_HIGHEST ) ;
break ;
case RESAMPLER_QUALITY_NORMAL :
s = msg_hash_to_str ( MSG_RESAMPLER_QUALITY_NORMAL ) ;
break ;
}
filestream_printf ( file , " - Resampler Quality: %s \n " , ! string_is_empty ( s ) ? s : " n/a " ) ;
}
filestream_printf ( file , " - Audio Latency: %u ms \n " , settings - > uints . audio_latency ) ;
filestream_printf ( file , " - Dynamic Rate Control (DRC): %.3f \n " , * audio_get_float_ptr ( AUDIO_ACTION_RATE_CONTROL_DELTA ) ) ;
filestream_printf ( file , " - Max Timing Skew: %.2f \n " , settings - > floats . audio_max_timing_skew ) ;
filestream_printf ( file , " - Output Rate: %u Hz \n " , settings - > uints . audio_out_rate ) ;
filestream_printf ( file , " - DSP Plugin: %s \n " , ! string_is_empty ( settings - > paths . path_audio_dsp_plugin ) ? settings - > paths . path_audio_dsp_plugin : " n/a " ) ;
2019-03-09 12:57:26 -05:00
{
core_info_list_t * core_info_list = NULL ;
2019-04-22 04:41:16 +02:00
bool found = false ;
2019-03-09 12:57:26 -05:00
filestream_printf ( file , " \n " ) ;
filestream_printf ( file , " Firmware files found: \n " ) ;
core_info_get_list ( & core_info_list ) ;
if ( core_info_list )
{
2019-03-11 17:07:49 +01:00
unsigned i ;
2019-03-09 12:57:26 -05:00
for ( i = 0 ; i < core_info_list - > count ; i + + )
{
core_info_t * info = & core_info_list - > list [ i ] ;
if ( ! info )
continue ;
if ( info - > firmware_count )
{
2019-03-11 17:07:49 +01:00
unsigned j ;
2019-03-09 12:57:26 -05:00
bool core_found = false ;
for ( j = 0 ; j < info - > firmware_count ; j + + )
{
core_info_firmware_t * firmware = & info - > firmware [ j ] ;
char path [ PATH_MAX_LENGTH ] ;
if ( ! firmware )
continue ;
path [ 0 ] = ' \0 ' ;
fill_pathname_join (
path ,
settings - > paths . directory_system ,
firmware - > path ,
sizeof ( path ) ) ;
if ( filestream_exists ( path ) )
{
found = true ;
if ( ! core_found )
{
core_found = true ;
filestream_printf ( file , " - %s: \n " , ! string_is_empty ( info - > core_name ) ? info - > core_name : path_basename ( info - > path ) ) ;
}
filestream_printf ( file , " - %s (%s) \n " , firmware - > path , firmware - > optional ? " optional " : " required " ) ;
}
}
}
}
}
if ( ! found )
filestream_printf ( file , " - n/a \n " ) ;
}
2019-03-07 19:17:54 -05:00
filestream_close ( file ) ;
RARCH_LOG ( " Wrote debug info to %s \n " , debug_filepath ) ;
msg_hash_set_uint ( MSG_HASH_USER_LANGUAGE , lang ) ;
return true ;
error :
return false ;
}
2019-03-11 16:58:43 +01:00
# ifdef HAVE_NETWORKING
2019-03-07 19:17:54 -05:00
static void send_debug_info_cb ( retro_task_t * task ,
void * task_data , void * user_data , const char * error )
{
if ( task_data )
{
http_transfer_data_t * data = ( http_transfer_data_t * ) task_data ;
if ( ! data | | data - > len = = 0 )
{
RARCH_LOG ( " %s \n " , msg_hash_to_str ( MSG_FAILED_TO_SEND_DEBUG_INFO ) ) ;
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAILED_TO_SEND_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_ERROR ) ;
free ( task_data ) ;
return ;
}
/* don't use string_is_equal() here instead of the memcmp() because the data isn't NULL-terminated */
if ( ! string_is_empty ( data - > data ) & & data - > len > = 2 & & ! memcmp ( data - > data , " OK " , 2 ) )
{
char buf [ 32 ] = { 0 } ;
struct string_list * list ;
memcpy ( buf , data - > data , data - > len ) ;
list = string_split ( buf , " " ) ;
if ( list & & list - > size > 1 )
{
unsigned id = 0 ;
char msg [ PATH_MAX_LENGTH ] ;
msg [ 0 ] = ' \0 ' ;
sscanf ( list - > elems [ 1 ] . data , " %u " , & id ) ;
snprintf ( msg , sizeof ( msg ) , msg_hash_to_str ( MSG_SENT_DEBUG_INFO ) , id ) ;
RARCH_LOG ( " %s \n " , msg ) ;
runloop_msg_queue_push (
msg ,
2 , 600 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
}
if ( list )
string_list_free ( list ) ;
}
else
{
RARCH_LOG ( " %s \n " , msg_hash_to_str ( MSG_FAILED_TO_SEND_DEBUG_INFO ) ) ;
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAILED_TO_SEND_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_ERROR ) ;
}
free ( task_data ) ;
}
else
{
RARCH_LOG ( " %s \n " , msg_hash_to_str ( MSG_FAILED_TO_SEND_DEBUG_INFO ) ) ;
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAILED_TO_SEND_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_ERROR ) ;
}
}
2019-03-11 16:58:43 +01:00
# endif
2019-03-07 19:17:54 -05:00
void rarch_send_debug_info ( void )
{
2019-03-11 16:58:43 +01:00
# ifdef HAVE_NETWORKING
2019-03-07 19:17:54 -05:00
char debug_filepath [ PATH_MAX_LENGTH ] ;
2019-04-22 04:25:43 +02:00
const char * url = " http://lobby.libretro.com/debuginfo/add/ " ;
char * info_buf = NULL ;
const size_t param_buf_size = 65535 ;
char * param_buf = ( char * ) malloc ( param_buf_size ) ;
char * param_buf_tmp = NULL ;
int param_buf_pos = 0 ;
int64_t len = 0 ;
const char * path_config = path_get ( RARCH_PATH_CONFIG ) ;
bool info_written = rarch_write_debug_info ( ) ;
2019-03-07 19:17:54 -05:00
2019-04-22 04:25:43 +02:00
debug_filepath [ 0 ] =
param_buf [ 0 ] = ' \0 ' ;
2019-03-07 19:17:54 -05:00
fill_pathname_resolve_relative (
debug_filepath ,
path_config ,
DEBUG_INFO_FILENAME ,
sizeof ( debug_filepath ) ) ;
if ( info_written )
filestream_read_file ( debug_filepath , ( void * * ) & info_buf , & len ) ;
if ( string_is_empty ( info_buf ) | | len = = 0 | | ! info_written )
{
runloop_msg_queue_push (
msg_hash_to_str ( MSG_FAILED_TO_SAVE_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_ERROR ) ;
goto finish ;
}
RARCH_LOG ( " %s \n " , msg_hash_to_str ( MSG_SENDING_DEBUG_INFO ) ) ;
runloop_msg_queue_push (
msg_hash_to_str ( MSG_SENDING_DEBUG_INFO ) ,
2 , 180 , true ,
NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
param_buf_pos = strlcpy ( param_buf , " info= " , param_buf_size ) ;
param_buf_tmp = param_buf + param_buf_pos ;
net_http_urlencode ( & param_buf_tmp , info_buf ) ;
strlcat ( param_buf , param_buf_tmp , param_buf_size - param_buf_pos ) ;
task_push_http_post_transfer ( url , param_buf , true , NULL , send_debug_info_cb , NULL ) ;
finish :
if ( param_buf )
free ( param_buf ) ;
if ( info_buf )
free ( info_buf ) ;
2019-03-11 16:58:43 +01:00
# endif
2019-03-07 19:17:54 -05:00
}
2019-03-21 16:56:24 +00:00
void rarch_log_file_init ( void )
{
2019-05-31 16:41:17 +02:00
char log_directory [ PATH_MAX_LENGTH ] ;
char log_file_path [ PATH_MAX_LENGTH ] ;
2019-05-12 04:43:36 +02:00
FILE * fp = NULL ;
2019-06-17 16:58:43 +02:00
settings_t * settings = configuration_settings ;
2019-05-12 04:43:36 +02:00
bool log_to_file = settings - > bools . log_to_file ;
bool log_to_file_timestamp = settings - > bools . log_to_file_timestamp ;
bool logging_to_file = is_logging_to_file ( ) ;
2019-05-17 17:19:13 +01:00
2019-05-31 16:41:17 +02:00
log_directory [ 0 ] = ' \0 ' ;
log_file_path [ 0 ] = ' \0 ' ;
2019-03-21 16:56:24 +00:00
2019-03-25 17:22:59 +00:00
/* If this is the first run, generate a timestamped log
* file name ( do this even when not outputting timestamped
* log files , since user may decide to switch at any moment . . . ) */
if ( string_is_empty ( timestamped_log_file_name ) )
{
char format [ 256 ] ;
2019-05-12 04:43:36 +02:00
time_t cur_time = time ( NULL ) ;
const struct tm * tm_ = localtime ( & cur_time ) ;
2019-03-25 17:22:59 +00:00
format [ 0 ] = ' \0 ' ;
2019-05-12 04:43:36 +02:00
strftime ( format , sizeof ( format ) , " retroarch__%Y_%m_%d__%H_%M_%S " , tm_ ) ;
2019-03-25 17:22:59 +00:00
fill_pathname_noext ( timestamped_log_file_name , format ,
2019-04-22 04:25:43 +02:00
file_path_str ( FILE_PATH_EVENT_LOG_EXTENSION ) ,
sizeof ( timestamped_log_file_name ) ) ;
2019-03-25 17:22:59 +00:00
}
2019-03-21 16:56:24 +00:00
/* If nothing has changed, do nothing */
2019-05-12 04:43:36 +02:00
if ( ( ! log_to_file & & ! logging_to_file ) | |
( log_to_file & & logging_to_file ) )
2019-03-21 16:56:24 +00:00
return ;
/* If we are currently logging to file and wish to stop,
* de - initialise existing logger . . . */
2019-05-12 04:43:36 +02:00
if ( ! log_to_file & & logging_to_file )
2019-03-21 16:56:24 +00:00
{
retro_main_log_file_deinit ( ) ;
/* ...and revert to console */
retro_main_log_file_init ( NULL , false ) ;
return ;
}
/* If we reach this point, then we are not currently
* logging to file , and wish to do so */
/* > Check whether we are already logging to console */
2019-04-20 07:04:57 -07:00
fp = ( FILE * ) retro_main_log_file ( ) ;
2019-05-12 04:43:36 +02:00
/* De-initialise existing logger */
2019-03-21 16:56:24 +00:00
if ( fp )
retro_main_log_file_deinit ( ) ;
2019-05-17 17:19:13 +01:00
/* > Get directory/file paths */
if ( log_file_override_active )
2019-03-21 16:56:24 +00:00
{
2019-05-17 17:19:13 +01:00
/* Get log directory */
2019-05-31 16:41:17 +02:00
const char * last_slash = find_last_slash ( log_file_override_path ) ;
2019-05-17 17:19:13 +01:00
if ( last_slash )
2019-03-28 11:27:26 +00:00
{
2019-05-31 16:41:17 +02:00
char tmp_buf [ PATH_MAX_LENGTH ] = { 0 } ;
size_t path_length = last_slash + 1 - log_file_override_path ;
2019-05-17 17:19:13 +01:00
if ( ( path_length > 1 ) & & ( path_length < PATH_MAX_LENGTH ) )
strlcpy ( tmp_buf , log_file_override_path , path_length * sizeof ( char ) ) ;
strlcpy ( log_directory , tmp_buf , sizeof ( log_directory ) ) ;
2019-03-28 11:27:26 +00:00
}
2019-05-17 17:19:13 +01:00
/* Get log file path */
strlcpy ( log_file_path , log_file_override_path , sizeof ( log_file_path ) ) ;
}
else if ( ! string_is_empty ( settings - > paths . log_dir ) )
{
/* Get log directory */
strlcpy ( log_directory , settings - > paths . log_dir , sizeof ( log_directory ) ) ;
/* Get log file path */
fill_pathname_join ( log_file_path , settings - > paths . log_dir ,
2019-05-12 04:43:36 +02:00
log_to_file_timestamp
2019-04-22 04:25:43 +02:00
? timestamped_log_file_name
: file_path_str ( FILE_PATH_DEFAULT_EVENT_LOG ) ,
2019-05-17 17:19:13 +01:00
sizeof ( log_file_path ) ) ;
}
/* > Attempt to initialise log file */
if ( ! string_is_empty ( log_file_path ) )
{
/* Create log directory, if required */
if ( ! string_is_empty ( log_directory ) )
2019-03-21 16:56:24 +00:00
{
2019-05-17 17:19:13 +01:00
if ( ! path_is_directory ( log_directory ) )
{
if ( ! path_mkdir ( log_directory ) )
{
/* Re-enable console logging and output error message */
retro_main_log_file_init ( NULL , false ) ;
RARCH_ERR ( " Failed to create system event log directory: %s \n " , log_directory ) ;
return ;
}
}
2019-03-21 16:56:24 +00:00
}
2019-05-17 17:19:13 +01:00
/* When RetroArch is launched, log file is overwritten.
* On subsequent calls within the same session , it is appended to . */
retro_main_log_file_init ( log_file_path , log_file_created ) ;
if ( is_logging_to_file ( ) )
log_file_created = true ;
return ;
2019-03-21 16:56:24 +00:00
}
2019-03-28 11:27:26 +00:00
/* If we reach this point, then something went wrong...
* Just fall back to console logging */
retro_main_log_file_init ( NULL , false ) ;
RARCH_ERR ( " Failed to initialise system event file logging... \n " ) ;
2019-03-21 16:56:24 +00:00
}
void rarch_log_file_deinit ( void )
{
FILE * fp = NULL ;
/* De-initialise existing logger, if currently logging to file */
if ( is_logging_to_file ( ) )
retro_main_log_file_deinit ( ) ;
/* If logging is currently disabled... */
2019-04-20 07:04:57 -07:00
fp = ( FILE * ) retro_main_log_file ( ) ;
2019-04-22 04:25:43 +02:00
if ( ! fp ) /* ...initialise logging to console */
2019-03-21 16:56:24 +00:00
retro_main_log_file_init ( NULL , false ) ;
}
2019-04-15 23:14:49 -04:00
enum retro_language rarch_get_language_from_iso ( const char * iso639 )
{
unsigned i ;
enum retro_language lang = RETRO_LANGUAGE_ENGLISH ;
struct lang_pair
{
const char * iso639 ;
enum retro_language lang ;
} ;
const struct lang_pair pairs [ ] =
{
{ " en " , RETRO_LANGUAGE_ENGLISH } ,
{ " ja " , RETRO_LANGUAGE_JAPANESE } ,
{ " fr " , RETRO_LANGUAGE_FRENCH } ,
{ " es " , RETRO_LANGUAGE_SPANISH } ,
{ " de " , RETRO_LANGUAGE_GERMAN } ,
{ " it " , RETRO_LANGUAGE_ITALIAN } ,
{ " nl " , RETRO_LANGUAGE_DUTCH } ,
{ " pt_BR " , RETRO_LANGUAGE_PORTUGUESE_BRAZIL } ,
{ " pt_PT " , RETRO_LANGUAGE_PORTUGUESE_PORTUGAL } ,
{ " pt " , RETRO_LANGUAGE_PORTUGUESE_PORTUGAL } ,
{ " ru " , RETRO_LANGUAGE_RUSSIAN } ,
{ " ko " , RETRO_LANGUAGE_KOREAN } ,
{ " zh_CN " , RETRO_LANGUAGE_CHINESE_SIMPLIFIED } ,
{ " zh_SG " , RETRO_LANGUAGE_CHINESE_SIMPLIFIED } ,
{ " zh_HK " , RETRO_LANGUAGE_CHINESE_TRADITIONAL } ,
{ " zh_TW " , RETRO_LANGUAGE_CHINESE_TRADITIONAL } ,
{ " zh " , RETRO_LANGUAGE_CHINESE_SIMPLIFIED } ,
{ " eo " , RETRO_LANGUAGE_ESPERANTO } ,
{ " pl " , RETRO_LANGUAGE_POLISH } ,
{ " vi " , RETRO_LANGUAGE_VIETNAMESE } ,
{ " ar " , RETRO_LANGUAGE_ARABIC } ,
{ " el " , RETRO_LANGUAGE_GREEK } ,
} ;
2019-05-11 08:50:38 -04:00
2019-05-12 04:43:36 +02:00
if ( string_is_empty ( iso639 ) )
2019-05-11 08:50:38 -04:00
return lang ;
2019-04-15 23:14:49 -04:00
2019-05-12 04:43:36 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( pairs ) ; i + + )
2019-04-15 23:14:49 -04:00
{
if ( strcasestr ( iso639 , pairs [ i ] . iso639 ) )
{
lang = pairs [ i ] . lang ;
break ;
}
}
return lang ;
}