From abcfcca1d23fa722558cf1a6c5b04873b5fdbab3 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 10 Jul 2019 09:54:25 +0200 Subject: [PATCH] Merge dynamic.c into retroarch.c --- Makefile.common | 1 - core.h | 12 - driver.h | 5 - dynamic.c | 1871 ----------------------------- dynamic.h | 26 - griffin/griffin.c | 1 - input/input_driver.h | 20 - retroarch.c | 2688 ++++++++++++++++++++++++++++++++++-------- retroarch.h | 16 +- runahead/run_ahead.h | 16 - 10 files changed, 2200 insertions(+), 2456 deletions(-) delete mode 100644 dynamic.c delete mode 100644 runahead/run_ahead.h diff --git a/Makefile.common b/Makefile.common index 915b0a9a62..969806a9b3 100644 --- a/Makefile.common +++ b/Makefile.common @@ -213,7 +213,6 @@ OBJ += frontend/frontend.o \ gfx/video_crt_switch.o \ configuration.o \ $(LIBRETRO_COMM_DIR)/dynamic/dylib.o \ - dynamic.o \ cores/dynamic_dummy.o \ $(LIBRETRO_COMM_DIR)/queues/message_queue.o \ managers/state_manager.o \ diff --git a/core.h b/core.h index 75e5482f9a..db50d33d68 100644 --- a/core.h +++ b/core.h @@ -174,8 +174,6 @@ bool core_run(void); bool core_init(void); -bool core_deinit(void *data); - bool core_unload_game(void); bool core_reset(void); @@ -216,22 +214,12 @@ bool core_set_controller_port_device(retro_ctx_controller_info_t *pad); bool core_has_set_input_descriptor(void); -void core_set_input_descriptors(void); - -void core_unset_input_descriptors(void); - -bool core_uninit_libretro_callbacks(void); - void core_uninit_symbols(void); -void core_set_input_state(retro_ctx_input_state_info_t *info); - bool core_is_symbols_inited(void); bool core_is_inited(void); -bool core_is_game_loaded(void); - void core_free_retro_game_info(struct retro_game_info *dest); RETRO_END_DECLS diff --git a/driver.h b/driver.h index b93f7a4a92..258fec2c25 100644 --- a/driver.h +++ b/driver.h @@ -87,11 +87,6 @@ enum driver_ctl_state * calls audio_monitor_set_refresh_rate(). */ RARCH_DRIVER_CTL_SET_REFRESH_RATE, - /* Update the system Audio/Video information. - * Will reinitialize audio/video drivers. - * Used by RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO. */ - RARCH_DRIVER_CTL_UPDATE_SYSTEM_AV_INFO, - RARCH_DRIVER_CTL_FIND_FIRST, RARCH_DRIVER_CTL_FIND_LAST, diff --git a/dynamic.c b/dynamic.c deleted file mode 100644 index bd5952f789..0000000000 --- a/dynamic.c +++ /dev/null @@ -1,1871 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2016-2019 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#define VFS_FRONTEND -#include - -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_CHEEVOS -#include "cheevos-new/cheevos.h" -#endif - -#if defined(HAVE_OPENGL) -#include "gfx/common/gl_common.h" -#elif defined(HAVE_OPENGL_CORE) -#include "gfx/common/gl_core_common.h" -#endif - -#ifdef HAVE_NETWORKING -#include "network/netplay/netplay.h" -#endif - -#include "dynamic.h" -#include "command.h" - -#include "driver.h" -#include "performance_counters.h" -#include "led/led_driver.h" -#include "midi/midi_driver.h" -#include "input/input_driver.h" - -#include "cores/internal_cores.h" -#include "content.h" -#include "msg_hash.h" -#include "paths.h" -#include "retroarch.h" -#include "configuration.h" -#include "verbosity.h" -#include "tasks/tasks_internal.h" - -#ifdef HAVE_MENU_WIDGETS -#include "menu/widgets/menu_widgets.h" -#endif - -#ifdef HAVE_RUNAHEAD -#include "runahead/copy_load_info.h" -#include "runahead/run_ahead.h" -#endif - -#ifdef HAVE_DYNAMIC -#define SYMBOL(x) do { \ - function_t func = dylib_proc(lib_handle_local, #x); \ - memcpy(¤t_core->x, &func, sizeof(func)); \ - if (current_core->x == NULL) { RARCH_ERR("Failed to load symbol: \"%s\"\n", #x); retroarch_fail(1, "init_libretro_sym()"); } \ -} while (0) - -static dylib_t lib_handle; -#else -#define SYMBOL(x) current_core->x = x -#endif - -#define SYMBOL_DUMMY(x) current_core->x = libretro_dummy_##x - -#ifdef HAVE_FFMPEG -#define SYMBOL_FFMPEG(x) current_core->x = libretro_ffmpeg_##x -#endif - -#ifdef HAVE_MPV -#define SYMBOL_MPV(x) current_core->x = libretro_mpv_##x -#endif - -#ifdef HAVE_IMAGEVIEWER -#define SYMBOL_IMAGEVIEWER(x) current_core->x = libretro_imageviewer_##x -#endif - -#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) -#define SYMBOL_NETRETROPAD(x) current_core->x = libretro_netretropad_##x -#endif - -#if defined(HAVE_VIDEOPROCESSOR) -#define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x -#endif - -#ifdef HAVE_EASTEREGG -#define SYMBOL_GONG(x) current_core->x = libretro_gong_##x -#endif - -#define CORE_SYMBOLS(x) \ - x(retro_init); \ - x(retro_deinit); \ - x(retro_api_version); \ - x(retro_get_system_info); \ - x(retro_get_system_av_info); \ - x(retro_set_environment); \ - x(retro_set_video_refresh); \ - x(retro_set_audio_sample); \ - x(retro_set_audio_sample_batch); \ - x(retro_set_input_poll); \ - x(retro_set_input_state); \ - x(retro_set_controller_port_device); \ - x(retro_reset); \ - x(retro_run); \ - x(retro_serialize_size); \ - x(retro_serialize); \ - x(retro_unserialize); \ - x(retro_cheat_reset); \ - x(retro_cheat_set); \ - x(retro_load_game); \ - x(retro_load_game_special); \ - x(retro_unload_game); \ - x(retro_get_region); \ - x(retro_get_memory_data); \ - x(retro_get_memory_size); - -static bool ignore_environment_cb = false; -static bool core_set_shared_context = false; -static bool *load_no_content_hook = NULL; - -struct retro_subsystem_info subsystem_data[SUBSYSTEM_MAX_SUBSYSTEMS]; -struct retro_subsystem_rom_info subsystem_data_roms[SUBSYSTEM_MAX_SUBSYSTEMS][SUBSYSTEM_MAX_SUBSYSTEM_ROMS]; -unsigned subsystem_current_count; - -const struct retro_subsystem_info *libretro_find_subsystem_info( - const struct retro_subsystem_info *info, unsigned num_info, - const char *ident) -{ - unsigned i; - for (i = 0; i < num_info; i++) - { - if (string_is_equal(info[i].ident, ident)) - return &info[i]; - else if (string_is_equal(info[i].desc, ident)) - return &info[i]; - } - - return NULL; -} - -/** - * libretro_find_controller_description: - * @info : Pointer to controller info handle. - * @id : Identifier of controller to search - * for. - * - * Search for a controller of type @id in @info. - * - * Returns: controller description of found controller on success, - * otherwise NULL. - **/ -const struct retro_controller_description * -libretro_find_controller_description( - const struct retro_controller_info *info, unsigned id) -{ - unsigned i; - - for (i = 0; i < info->num_types; i++) - { - if (info->types[i].id != id) - continue; - - return &info->types[i]; - } - - return NULL; -} - -/** - * libretro_free_system_info: - * @info : Pointer to system info information. - * - * Frees system information. - **/ -void libretro_free_system_info(struct retro_system_info *info) -{ - if (!info) - return; - - free((void*)info->library_name); - free((void*)info->library_version); - free((void*)info->valid_extensions); - memset(info, 0, sizeof(*info)); -} - -static bool environ_cb_get_system_info(unsigned cmd, void *data) -{ - rarch_system_info_t *system = runloop_get_system_info(); - switch (cmd) - { - case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: - *load_no_content_hook = *(const bool*)data; - break; - case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: - { - unsigned i, j, size; - const struct retro_subsystem_info *info = - (const struct retro_subsystem_info*)data; - settings_t *settings = config_get_ptr(); - unsigned log_level = settings->uints.libretro_log_level; - - subsystem_current_count = 0; - - RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); - - for (i = 0; info[i].ident; i++) - { - if (log_level != RETRO_LOG_DEBUG) - continue; - - RARCH_LOG("Subsystem ID: %d\n", i); - RARCH_LOG("Special game type: %s\n", info[i].desc); - RARCH_LOG(" Ident: %s\n", info[i].ident); - RARCH_LOG(" ID: %u\n", info[i].id); - RARCH_LOG(" Content:\n"); - for (j = 0; j < info[i].num_roms; j++) - { - RARCH_LOG(" %s (%s)\n", - info[i].roms[j].desc, info[i].roms[j].required ? - "required" : "optional"); - } - } - - if (log_level == RETRO_LOG_DEBUG) - RARCH_LOG("Subsystems: %d\n", i); - size = i; - - if (log_level == RETRO_LOG_DEBUG) - if (size > SUBSYSTEM_MAX_SUBSYSTEMS) - RARCH_WARN("Subsystems exceed subsystem max, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEMS); - - if (system) - { - for (i = 0; i < size && i < SUBSYSTEM_MAX_SUBSYSTEMS; i++) - { - /* Nasty, but have to do it like this since - * the pointers are const char * - * (if we don't free them, we get a memory leak) */ - if (!string_is_empty(subsystem_data[i].desc)) - free((char *)subsystem_data[i].desc); - if (!string_is_empty(subsystem_data[i].ident)) - free((char *)subsystem_data[i].ident); - subsystem_data[i].desc = strdup(info[i].desc); - subsystem_data[i].ident = strdup(info[i].ident); - subsystem_data[i].id = info[i].id; - subsystem_data[i].num_roms = info[i].num_roms; - - if (log_level == RETRO_LOG_DEBUG) - if (subsystem_data[i].num_roms > SUBSYSTEM_MAX_SUBSYSTEM_ROMS) - RARCH_WARN("Subsystems exceed subsystem max roms, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEM_ROMS); - - for (j = 0; j < subsystem_data[i].num_roms && j < SUBSYSTEM_MAX_SUBSYSTEM_ROMS; j++) - { - /* Nasty, but have to do it like this since - * the pointers are const char * - * (if we don't free them, we get a memory leak) */ - if (!string_is_empty(subsystem_data_roms[i][j].desc)) - free((char *)subsystem_data_roms[i][j].desc); - if (!string_is_empty(subsystem_data_roms[i][j].valid_extensions)) - free((char *)subsystem_data_roms[i][j].valid_extensions); - subsystem_data_roms[i][j].desc = strdup(info[i].roms[j].desc); - subsystem_data_roms[i][j].valid_extensions = strdup(info[i].roms[j].valid_extensions); - subsystem_data_roms[i][j].required = info[i].roms[j].required; - subsystem_data_roms[i][j].block_extract = info[i].roms[j].block_extract; - subsystem_data_roms[i][j].need_fullpath = info[i].roms[j].need_fullpath; - } - subsystem_data[i].roms = subsystem_data_roms[i]; - } - - subsystem_current_count = - size <= SUBSYSTEM_MAX_SUBSYSTEMS - ? size - : SUBSYSTEM_MAX_SUBSYSTEMS; - } - break; - } - default: - return false; - } - - return true; -} - -#ifdef HAVE_DYNAMIC -/** - * libretro_get_environment_info: - * @func : Function pointer for get_environment_info. - * @load_no_content : If true, core should be able to auto-start - * without any content loaded. - * - * Sets environment callback in order to get statically known - * information from it. - * - * Fetched via environment callbacks instead of - * retro_get_system_info(), as this info is part of extensions. - * - * Should only be called once right after core load to - * avoid overwriting the "real" environ callback. - * - * For statically linked cores, pass retro_set_environment as argument. - */ -static void libretro_get_environment_info(void (*func)(retro_environment_t), - bool *load_no_content) -{ - load_no_content_hook = load_no_content; - - /* load_no_content gets set in this callback. */ - func(environ_cb_get_system_info); - - /* It's possible that we just set get_system_info callback - * to the currently running core. - * - * Make sure we reset it to the actual environment callback. - * Ignore any environment callbacks here in case we're running - * on the non-current core. */ - ignore_environment_cb = true; - func(rarch_environment_cb); - ignore_environment_cb = false; -} - -static bool load_dynamic_core(const char *path, char *buf, size_t size) -{ - /* Can't lookup symbols in itself on UWP */ -#if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - if (dylib_proc(NULL, "retro_init")) - { - /* Try to verify that -lretro was not linked in from other modules - * since loading it dynamically and with -l will fail hard. */ - RARCH_ERR("Serious problem. RetroArch wants to load libretro cores" - " dynamically, but it is already linked.\n"); - RARCH_ERR("This could happen if other modules RetroArch depends on " - "link against libretro directly.\n"); - RARCH_ERR("Proceeding could cause a crash. Aborting ...\n"); - retroarch_fail(1, "init_libretro_sym()"); - } -#endif - - /* Need to use absolute path for this setting. It can be - * saved to content history, and a relative path would - * break in that scenario. */ - path_resolve_realpath(buf, size); - if ((lib_handle = dylib_load(path))) - return true; - return false; -} - -static dylib_t libretro_get_system_info_lib(const char *path, - struct retro_system_info *info, bool *load_no_content) -{ - dylib_t lib = dylib_load(path); - void (*proc)(struct retro_system_info*); - - if (!lib) - return NULL; - - proc = (void (*)(struct retro_system_info*)) - dylib_proc(lib, "retro_get_system_info"); - - if (!proc) - { - dylib_close(lib); - return NULL; - } - - proc(info); - - if (load_no_content) - { - void (*set_environ)(retro_environment_t); - *load_no_content = false; - set_environ = (void (*)(retro_environment_t)) - dylib_proc(lib, "retro_set_environment"); - - if (set_environ) - libretro_get_environment_info(set_environ, load_no_content); - } - - return lib; -} -#endif - -static char current_library_name[1024]; -static char current_library_version[1024]; -static char current_valid_extensions[1024]; - -/** - * libretro_get_system_info: - * @path : Path to libretro library. - * @info : Pointer to system info information. - * @load_no_content : If true, core should be able to auto-start - * without any content loaded. - * - * Gets system info from an arbitrary lib. - * The struct returned must be freed as strings are allocated dynamically. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -bool libretro_get_system_info(const char *path, - struct retro_system_info *info, bool *load_no_content) -{ - struct retro_system_info dummy_info; -#ifdef HAVE_DYNAMIC - dylib_t lib; -#endif - - dummy_info.library_name = NULL; - dummy_info.library_version = NULL; - dummy_info.valid_extensions = NULL; - dummy_info.need_fullpath = false; - dummy_info.block_extract = false; - -#ifdef HAVE_DYNAMIC - lib = libretro_get_system_info_lib( - path, &dummy_info, load_no_content); - - if (!lib) - { - RARCH_ERR("%s: \"%s\"\n", - msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), - path); - RARCH_ERR("Error(s): %s\n", dylib_error()); - return false; - } -#else - if (load_no_content) - { - load_no_content_hook = load_no_content; - - /* load_no_content gets set in this callback. */ - retro_set_environment(environ_cb_get_system_info); - - /* It's possible that we just set get_system_info callback - * to the currently running core. - * - * Make sure we reset it to the actual environment callback. - * Ignore any environment callbacks here in case we're running - * on the non-current core. */ - ignore_environment_cb = true; - retro_set_environment(rarch_environment_cb); - ignore_environment_cb = false; - } - - retro_get_system_info(&dummy_info); -#endif - - memcpy(info, &dummy_info, sizeof(*info)); - - current_library_name[0] = '\0'; - current_library_version[0] = '\0'; - current_valid_extensions[0] = '\0'; - - if (!string_is_empty(dummy_info.library_name)) - strlcpy(current_library_name, - dummy_info.library_name, sizeof(current_library_name)); - if (!string_is_empty(dummy_info.library_version)) - strlcpy(current_library_version, - dummy_info.library_version, sizeof(current_library_version)); - if (dummy_info.valid_extensions) - strlcpy(current_valid_extensions, - dummy_info.valid_extensions, sizeof(current_valid_extensions)); - - info->library_name = current_library_name; - info->library_version = current_library_version; - info->valid_extensions = current_valid_extensions; - -#ifdef HAVE_DYNAMIC - dylib_close(lib); -#endif - return true; -} - -/** - * load_symbols: - * @type : Type of core to be loaded. - * If CORE_TYPE_DUMMY, will - * load dummy symbols. - * - * Setup libretro callback symbols. Returns true on success, - * or false if symbols could not be loaded. - **/ -bool init_libretro_sym_custom(enum rarch_core_type type, - struct retro_core_t *current_core, const char *lib_path, void *_lib_handle_p) -{ -#ifdef HAVE_DYNAMIC - /* the library handle for use with the SYMBOL macro */ - dylib_t lib_handle_local; -#endif - - switch (type) - { - case CORE_TYPE_PLAIN: - { -#ifdef HAVE_DYNAMIC -#ifdef HAVE_RUNAHEAD - dylib_t *lib_handle_p = (dylib_t*)_lib_handle_p; - if (!lib_path || !lib_handle_p) -#endif - { - const char *path = path_get(RARCH_PATH_CORE); - - if (string_is_empty(path)) - { - RARCH_ERR("Frontend is built for dynamic libretro cores, but " - "path is not set. Cannot continue.\n"); - retroarch_fail(1, "init_libretro_sym()"); - } - - RARCH_LOG("Loading dynamic libretro core from: \"%s\"\n", - path); - - if (!load_dynamic_core( - path, - path_get_ptr(RARCH_PATH_CORE), - path_get_realsize(RARCH_PATH_CORE) - )) - { - RARCH_ERR("Failed to open libretro core: \"%s\"\n", path); - RARCH_ERR("Error(s): %s\n", dylib_error()); - runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), - 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - return false; - } - lib_handle_local = lib_handle; - } -#ifdef HAVE_RUNAHEAD - else - { - /* for a secondary core, we already have a - * primary library loaded, so we can skip - * some checks and just load the library */ - retro_assert(lib_path != NULL && lib_handle_p != NULL); - lib_handle_local = dylib_load(lib_path); - - if (!lib_handle_local) - return false; - *lib_handle_p = lib_handle_local; - } -#endif -#endif - - CORE_SYMBOLS(SYMBOL); - } - break; - case CORE_TYPE_DUMMY: - CORE_SYMBOLS(SYMBOL_DUMMY); - break; - case CORE_TYPE_FFMPEG: -#ifdef HAVE_FFMPEG - CORE_SYMBOLS(SYMBOL_FFMPEG); -#endif - break; - case CORE_TYPE_MPV: -#ifdef HAVE_MPV - CORE_SYMBOLS(SYMBOL_MPV); -#endif - break; - case CORE_TYPE_IMAGEVIEWER: -#ifdef HAVE_IMAGEVIEWER - CORE_SYMBOLS(SYMBOL_IMAGEVIEWER); -#endif - break; - case CORE_TYPE_NETRETROPAD: -#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) - CORE_SYMBOLS(SYMBOL_NETRETROPAD); -#endif - break; - case CORE_TYPE_VIDEO_PROCESSOR: -#if defined(HAVE_VIDEOPROCESSOR) - CORE_SYMBOLS(SYMBOL_VIDEOPROCESSOR); -#endif - break; - case CORE_TYPE_GONG: -#ifdef HAVE_EASTEREGG - CORE_SYMBOLS(SYMBOL_GONG); -#endif - break; - } - - return true; -} - -/** - * init_libretro_sym: - * @type : Type of core to be loaded. - * If CORE_TYPE_DUMMY, will - * load dummy symbols. - * - * Initializes libretro symbols and - * setups environment callback functions. Returns true on success, - * or false if symbols could not be loaded. - **/ -bool init_libretro_sym(enum rarch_core_type type, struct retro_core_t *current_core) -{ - /* Load symbols */ - if (!init_libretro_sym_custom(type, current_core, NULL, NULL)) - return false; - -#ifdef HAVE_RUNAHEAD - /* remember last core type created, so creating a - * secondary core will know what core type to use. */ - set_last_core_type(type); -#endif - return true; -} - -bool libretro_get_shared_context(void) -{ - return core_set_shared_context; -} - -/** - * uninit_libretro_sym: - * - * Frees libretro core. - * - * Frees all core options, - * associated state, and - * unbind all libretro callback symbols. - **/ -void uninit_libretro_sym(struct retro_core_t *current_core) -{ -#ifdef HAVE_DYNAMIC - if (lib_handle) - dylib_close(lib_handle); - lib_handle = NULL; -#endif - - memset(current_core, 0, sizeof(struct retro_core_t)); - - core_set_shared_context = false; - - rarch_ctl(RARCH_CTL_CORE_OPTIONS_DEINIT, NULL); - rarch_ctl(RARCH_CTL_SYSTEM_INFO_FREE, NULL); - rarch_ctl(RARCH_CTL_FRAME_TIME_FREE, NULL); - rarch_ctl(RARCH_CTL_CAMERA_UNSET_ACTIVE, NULL); - rarch_ctl(RARCH_CTL_LOCATION_UNSET_ACTIVE, NULL); - - /* Performance counters no longer valid. */ - performance_counters_clear(); -} - -static void rarch_log_libretro(enum retro_log_level level, - const char *fmt, ...) -{ - va_list vp; - settings_t *settings = config_get_ptr(); - - if ((unsigned)level < settings->uints.libretro_log_level) - return; - - if (!verbosity_is_enabled()) - return; - - va_start(vp, fmt); - - switch (level) - { - case RETRO_LOG_DEBUG: - RARCH_LOG_V("[libretro DEBUG]", fmt, vp); - break; - - case RETRO_LOG_INFO: - RARCH_LOG_OUTPUT_V("[libretro INFO]", fmt, vp); - break; - - case RETRO_LOG_WARN: - RARCH_WARN_V("[libretro WARN]", fmt, vp); - break; - - case RETRO_LOG_ERROR: - RARCH_ERR_V("[libretro ERROR]", fmt, vp); - break; - - default: - break; - } - - va_end(vp); -} - -static size_t mmap_add_bits_down(size_t n) -{ - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n |= n >> 16; - - /* double shift to avoid warnings on 32bit (it's dead code, but compilers suck) */ - if (sizeof(size_t) > 4) - n |= n >> 16 >> 16; - - return n; -} - -static size_t mmap_inflate(size_t addr, size_t mask) -{ - while (mask) - { - size_t tmp = (mask - 1) & ~mask; - - /* to put in an 1 bit instead, OR in tmp+1 */ - addr = ((addr & ~tmp) << 1) | (addr & tmp); - mask = mask & (mask - 1); - } - - return addr; -} - -static size_t mmap_reduce(size_t addr, size_t mask) -{ - while (mask) - { - size_t tmp = (mask - 1) & ~mask; - addr = (addr & tmp) | ((addr >> 1) & ~tmp); - mask = (mask & (mask - 1)) >> 1; - } - - return addr; -} - -static size_t mmap_highest_bit(size_t n) -{ - n = mmap_add_bits_down(n); - return n ^ (n >> 1); -} - -static bool mmap_preprocess_descriptors(rarch_memory_descriptor_t *first, unsigned count) -{ - size_t top_addr = 1; - rarch_memory_descriptor_t *desc = NULL; - const rarch_memory_descriptor_t *end = first + count; - - for (desc = first; desc < end; desc++) - { - if (desc->core.select != 0) - top_addr |= desc->core.select; - else - top_addr |= desc->core.start + desc->core.len - 1; - } - - top_addr = mmap_add_bits_down(top_addr); - - for (desc = first; desc < end; desc++) - { - if (desc->core.select == 0) - { - if (desc->core.len == 0) - return false; - - if ((desc->core.len & (desc->core.len - 1)) != 0) - return false; - - desc->core.select = top_addr & ~mmap_inflate(mmap_add_bits_down(desc->core.len - 1), - desc->core.disconnect); - } - - if (desc->core.len == 0) - desc->core.len = mmap_add_bits_down(mmap_reduce(top_addr & ~desc->core.select, - desc->core.disconnect)) + 1; - - if (desc->core.start & ~desc->core.select) - return false; - - while (mmap_reduce(top_addr & ~desc->core.select, desc->core.disconnect) >> 1 > desc->core.len - 1) - desc->core.disconnect |= mmap_highest_bit(top_addr & ~desc->core.select & ~desc->core.disconnect); - - desc->disconnect_mask = mmap_add_bits_down(desc->core.len - 1); - desc->core.disconnect &= desc->disconnect_mask; - - while ((~desc->disconnect_mask) >> 1 & desc->core.disconnect) - { - desc->disconnect_mask >>= 1; - desc->core.disconnect &= desc->disconnect_mask; - } - } - - return true; -} - -static bool dynamic_request_hw_context(enum retro_hw_context_type type, - unsigned minor, unsigned major) -{ - switch (type) - { - case RETRO_HW_CONTEXT_NONE: - RARCH_LOG("Requesting no HW context.\n"); - break; - - case RETRO_HW_CONTEXT_VULKAN: -#ifdef HAVE_VULKAN - RARCH_LOG("Requesting Vulkan context.\n"); - break; -#else - RARCH_ERR("Requesting Vulkan context, but RetroArch is not compiled against Vulkan. Cannot use HW context.\n"); - return false; -#endif - -#if defined(HAVE_OPENGLES) - -#if (defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3)) - case RETRO_HW_CONTEXT_OPENGLES2: - case RETRO_HW_CONTEXT_OPENGLES3: - RARCH_LOG("Requesting OpenGLES%u context.\n", - type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); - break; - -#if defined(HAVE_OPENGLES3) - case RETRO_HW_CONTEXT_OPENGLES_VERSION: - RARCH_LOG("Requesting OpenGLES%u.%u context.\n", - major, minor); - break; -#endif - -#endif - case RETRO_HW_CONTEXT_OPENGL: - case RETRO_HW_CONTEXT_OPENGL_CORE: - RARCH_ERR("Requesting OpenGL context, but RetroArch " - "is compiled against OpenGLES. Cannot use HW context.\n"); - return false; - -#elif defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE) - case RETRO_HW_CONTEXT_OPENGLES2: - case RETRO_HW_CONTEXT_OPENGLES3: - RARCH_ERR("Requesting OpenGLES%u context, but RetroArch " - "is compiled against OpenGL. Cannot use HW context.\n", - type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); - return false; - - case RETRO_HW_CONTEXT_OPENGLES_VERSION: - RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch " - "is compiled against OpenGL. Cannot use HW context.\n", - major, minor); - return false; - - case RETRO_HW_CONTEXT_OPENGL: - RARCH_LOG("Requesting OpenGL context.\n"); - break; - - case RETRO_HW_CONTEXT_OPENGL_CORE: - /* TODO/FIXME - we should do a check here to see if - * the requested core GL version is supported */ - RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", - major, minor); - break; -#endif - -#if defined(HAVE_D3D9) || defined(HAVE_D3D11) - case RETRO_HW_CONTEXT_DIRECT3D: - switch (major) - { -#ifdef HAVE_D3D9 - case 9: - RARCH_LOG("Requesting D3D9 context.\n"); - break; -#endif -#ifdef HAVE_D3D11 - case 11: - RARCH_LOG("Requesting D3D11 context.\n"); - break; -#endif - default: - RARCH_LOG("Requesting unknown context.\n"); - return false; - } - break; -#endif - - default: - RARCH_LOG("Requesting unknown context.\n"); - return false; - } - - return true; -} - -static bool dynamic_verify_hw_context(enum retro_hw_context_type type, - unsigned minor, unsigned major) -{ - const char *video_ident = video_driver_get_ident(); - - switch (type) - { - case RETRO_HW_CONTEXT_VULKAN: - if (!string_is_equal(video_ident, "vulkan")) - return false; - break; - case RETRO_HW_CONTEXT_OPENGLES2: - case RETRO_HW_CONTEXT_OPENGLES3: - case RETRO_HW_CONTEXT_OPENGLES_VERSION: - case RETRO_HW_CONTEXT_OPENGL: - case RETRO_HW_CONTEXT_OPENGL_CORE: - if (!string_is_equal(video_ident, "gl") && - !string_is_equal(video_ident, "glcore")) - { - return false; - } - break; - case RETRO_HW_CONTEXT_DIRECT3D: - if (!(string_is_equal(video_ident, "d3d11") && major == 11)) - return false; - break; - default: - break; - } - - return true; -} - -static void core_performance_counter_start(struct retro_perf_counter *perf) -{ - if (rarch_ctl(RARCH_CTL_IS_PERFCNT_ENABLE, NULL)) - { - perf->call_cnt++; - perf->start = cpu_features_get_perf_counter(); - } -} - -static void core_performance_counter_stop(struct retro_perf_counter *perf) -{ - if (rarch_ctl(RARCH_CTL_IS_PERFCNT_ENABLE, NULL)) - perf->total += cpu_features_get_perf_counter() - perf->start; -} - -bool rarch_clear_all_thread_waits(unsigned clear_threads, void *data) -{ - if ( clear_threads > 0) - audio_driver_start(false) ; - else - audio_driver_stop() ; - - return true ; -} - -/** - * rarch_environment_cb: - * @cmd : Identifier of command. - * @data : Pointer to data. - * - * Environment callback function implementation. - * - * Returns: true (1) if environment callback command could - * be performed, otherwise false (0). - **/ -bool rarch_environment_cb(unsigned cmd, void *data) -{ - unsigned p; - settings_t *settings = config_get_ptr(); - rarch_system_info_t *system = runloop_get_system_info(); - - if (ignore_environment_cb) - return false; - - switch (cmd) - { - case RETRO_ENVIRONMENT_GET_OVERSCAN: - *(bool*)data = !settings->bools.video_crop_overscan; - RARCH_LOG("Environ GET_OVERSCAN: %u\n", - (unsigned)!settings->bools.video_crop_overscan); - break; - - case RETRO_ENVIRONMENT_GET_CAN_DUPE: - *(bool*)data = true; - RARCH_LOG("Environ GET_CAN_DUPE: true\n"); - break; - - case RETRO_ENVIRONMENT_GET_VARIABLE: - if (!rarch_ctl(RARCH_CTL_CORE_OPTIONS_GET, data)) - { - struct retro_variable *var = (struct retro_variable*)data; - - if (var) - { - RARCH_LOG("Environ GET_VARIABLE %s: not implemented.\n", var->key); - var->value = NULL; - } - } - - break; - - case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE: - *(bool*)data = rarch_ctl(RARCH_CTL_IS_CORE_OPTION_UPDATED, NULL); - break; - - case RETRO_ENVIRONMENT_SET_VARIABLES: - RARCH_LOG("Environ SET_VARIABLES.\n"); - - rarch_ctl(RARCH_CTL_CORE_OPTIONS_DEINIT, NULL); - rarch_ctl(RARCH_CTL_CORE_OPTIONS_INIT, data); - - break; - - case RETRO_ENVIRONMENT_SET_MESSAGE: - { - const struct retro_message *msg = (const struct retro_message*)data; - RARCH_LOG("Environ SET_MESSAGE: %s\n", msg->msg); -#ifdef HAVE_MENU_WIDGETS - if (!menu_widgets_set_libretro_message(msg->msg, roundf((float)msg->frames / 60.0f * 1000.0f))) -#endif - runloop_msg_queue_push(msg->msg, 3, msg->frames, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - break; - } - - case RETRO_ENVIRONMENT_SET_ROTATION: - { - unsigned rotation = *(const unsigned*)data; - RARCH_LOG("Environ SET_ROTATION: %u\n", rotation); - if (!settings->bools.video_allow_rotate) - break; - - if (system) - system->rotation = rotation; - - if (!video_driver_set_rotation(rotation)) - return false; - break; - } - - case RETRO_ENVIRONMENT_SHUTDOWN: - RARCH_LOG("Environ SHUTDOWN.\n"); - - /* This case occurs when a core (internally) requests - * a shutdown event. Must save runtime log file here, - * since normal command.c CMD_EVENT_CORE_DEINIT event - * will not occur until after the current content has - * been cleared (causing log to be skipped) */ - rarch_ctl(RARCH_CTL_CONTENT_RUNTIME_LOG_DEINIT, NULL); - - rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); - rarch_ctl(RARCH_CTL_SET_CORE_SHUTDOWN, NULL); - break; - - case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: - if (system) - { - system->performance_level = *(const unsigned*)data; - RARCH_LOG("Environ PERFORMANCE_LEVEL: %u.\n", - system->performance_level); - } - break; - - case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: - if (string_is_empty(settings->paths.directory_system) || settings->bools.systemfiles_in_content_dir) - { - const char *fullpath = path_get(RARCH_PATH_CONTENT); - if (!string_is_empty(fullpath)) - { - size_t path_size = PATH_MAX_LENGTH * sizeof(char); - char *temp_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); - - temp_path[0] = '\0'; - - if (string_is_empty(settings->paths.directory_system)) - RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", - fullpath); - fill_pathname_basedir(temp_path, fullpath, path_size); - dir_set(RARCH_DIR_SYSTEM, temp_path); - free(temp_path); - } - - *(const char**)data = dir_get_ptr(RARCH_DIR_SYSTEM); - RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", - dir_get(RARCH_DIR_SYSTEM)); - } - else - { - *(const char**)data = settings->paths.directory_system; - RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", - settings->paths.directory_system); - } - - break; - - case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: - *(const char**)data = dir_get(RARCH_DIR_CURRENT_SAVEFILE); - break; - - case RETRO_ENVIRONMENT_GET_USERNAME: - *(const char**)data = *settings->paths.username ? - settings->paths.username : NULL; - RARCH_LOG("Environ GET_USERNAME: \"%s\".\n", - settings->paths.username); - break; - - case RETRO_ENVIRONMENT_GET_LANGUAGE: -#ifdef HAVE_LANGEXTRA - { - unsigned user_lang = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE); - *(unsigned *)data = user_lang; - RARCH_LOG("Environ GET_LANGUAGE: \"%u\".\n", user_lang); - } -#endif - break; - - case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: - { - enum retro_pixel_format pix_fmt = - *(const enum retro_pixel_format*)data; - - switch (pix_fmt) - { - case RETRO_PIXEL_FORMAT_0RGB1555: - RARCH_LOG("Environ SET_PIXEL_FORMAT: 0RGB1555.\n"); - break; - - case RETRO_PIXEL_FORMAT_RGB565: - RARCH_LOG("Environ SET_PIXEL_FORMAT: RGB565.\n"); - break; - case RETRO_PIXEL_FORMAT_XRGB8888: - RARCH_LOG("Environ SET_PIXEL_FORMAT: XRGB8888.\n"); - break; - default: - return false; - } - - video_driver_set_pixel_format(pix_fmt); - break; - } - - case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: - { - static const char *libretro_btn_desc[] = { - "B (bottom)", "Y (left)", "Select", "Start", - "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right", - "A (right)", "X (up)", - "L", "R", "L2", "R2", "L3", "R3", - }; - - if (system) - { - unsigned retro_id; - const struct retro_input_descriptor *desc = NULL; - memset((void*)&system->input_desc_btn, 0, - sizeof(system->input_desc_btn)); - - desc = (const struct retro_input_descriptor*)data; - - for (; desc->description; desc++) - { - unsigned retro_port = desc->port; - - retro_id = desc->id; - - if (desc->port >= MAX_USERS) - continue; - - /* Ignore all others for now. */ - if (desc->device != RETRO_DEVICE_JOYPAD && - desc->device != RETRO_DEVICE_ANALOG) - continue; - - if (desc->id >= RARCH_FIRST_CUSTOM_BIND) - continue; - - if (desc->device == RETRO_DEVICE_ANALOG) - { - switch (retro_id) - { - case RETRO_DEVICE_ID_ANALOG_X: - switch (desc->index) - { - case RETRO_DEVICE_INDEX_ANALOG_LEFT: - system->input_desc_btn[retro_port] - [RARCH_ANALOG_LEFT_X_PLUS] = desc->description; - system->input_desc_btn[retro_port] - [RARCH_ANALOG_LEFT_X_MINUS] = desc->description; - break; - case RETRO_DEVICE_INDEX_ANALOG_RIGHT: - system->input_desc_btn[retro_port] - [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description; - system->input_desc_btn[retro_port] - [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description; - break; - } - break; - case RETRO_DEVICE_ID_ANALOG_Y: - switch (desc->index) - { - case RETRO_DEVICE_INDEX_ANALOG_LEFT: - system->input_desc_btn[retro_port] - [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description; - system->input_desc_btn[retro_port] - [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description; - break; - case RETRO_DEVICE_INDEX_ANALOG_RIGHT: - system->input_desc_btn[retro_port] - [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description; - system->input_desc_btn[retro_port] - [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description; - break; - } - break; - } - } - else - system->input_desc_btn[retro_port] - [retro_id] = desc->description; - } - - RARCH_LOG("Environ SET_INPUT_DESCRIPTORS:\n"); - - { - settings_t *settings = config_get_ptr(); - unsigned log_level = settings->uints.libretro_log_level; - - if (log_level == RETRO_LOG_DEBUG) - { - unsigned max_users = *(input_driver_get_uint(INPUT_ACTION_MAX_USERS)); - - for (p = 0; p < max_users; p++) - { - for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++) - { - const char *description = system->input_desc_btn[p][retro_id]; - - if (!description) - continue; - - RARCH_LOG("\tRetroPad, User %u, Button \"%s\" => \"%s\"\n", - p + 1, libretro_btn_desc[retro_id], description); - } - } - } - } - - core_set_input_descriptors(); - } - - break; - } - - case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: - { - retro_keyboard_event_t *frontend_key_event = NULL; - retro_keyboard_event_t *key_event = NULL; - const struct retro_keyboard_callback *info = - (const struct retro_keyboard_callback*)data; - - rarch_ctl(RARCH_CTL_FRONTEND_KEY_EVENT_GET, &frontend_key_event); - rarch_ctl(RARCH_CTL_KEY_EVENT_GET, &key_event); - - RARCH_LOG("Environ SET_KEYBOARD_CALLBACK.\n"); - if (key_event) - *key_event = info->callback; - - if (frontend_key_event && key_event) - *frontend_key_event = *key_event; - break; - } - - case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: - RARCH_LOG("Environ SET_DISK_CONTROL_INTERFACE.\n"); - if (system) - system->disk_control_cb = - *(const struct retro_disk_control_callback*)data; - break; - - case RETRO_ENVIRONMENT_SET_HW_RENDER: - case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: - { - struct retro_hw_render_callback *cb = - (struct retro_hw_render_callback*)data; - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); - - RARCH_LOG("Environ SET_HW_RENDER.\n"); - - if (!dynamic_request_hw_context(cb->context_type, cb->version_minor, cb->version_major)) - return false; - - if (!dynamic_verify_hw_context(cb->context_type, cb->version_minor, cb->version_major)) - return false; - -#if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE) - if (!gl_set_core_context(cb->context_type)) { } -#endif - - cb->get_current_framebuffer = video_driver_get_current_framebuffer; - cb->get_proc_address = video_driver_get_proc_address; - - /* Old ABI. Don't copy garbage. */ - if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) - { - memcpy(hwr, - cb, offsetof(struct retro_hw_render_callback, stencil)); - memset((uint8_t*)hwr + offsetof(struct retro_hw_render_callback, stencil), - 0, sizeof(*cb) - offsetof(struct retro_hw_render_callback, stencil)); - } - else - memcpy(hwr, cb, sizeof(*cb)); - break; - } - - case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: - { - bool state = *(const bool*)data; - RARCH_LOG("Environ SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no"); - - if (state) - content_set_does_not_need_content(); - else - content_unset_does_not_need_content(); - break; - } - - case RETRO_ENVIRONMENT_SET_SAVE_STATE_IN_BACKGROUND: - { - bool state = *(const bool*)data; - RARCH_LOG("Environ SET_SAVE_STATE_IN_BACKGROUND: %s.\n", state ? "yes" : "no"); - - set_save_state_in_background(state) ; - - break; - } - - case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: - { - const char **path = (const char**)data; -#ifdef HAVE_DYNAMIC - *path = path_get(RARCH_PATH_CORE); -#else - *path = NULL; -#endif - break; - } - - case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK: -#ifdef HAVE_THREADS - { - RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n"); -#ifdef HAVE_NETWORKING - if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) - return false; -#endif - if (recording_driver_get_data_ptr()) /* A/V sync is a must. */ - return false; - audio_driver_set_callback(data); - } -#endif - break; - - case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK: - { - RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n"); - rarch_ctl(RARCH_CTL_SET_FRAME_TIME, data); - break; - } - - case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE: - { - struct retro_rumble_interface *iface = - (struct retro_rumble_interface*)data; - - RARCH_LOG("Environ GET_RUMBLE_INTERFACE.\n"); - iface->set_rumble_state = input_driver_set_rumble_state; - break; - } - - case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: - { - uint64_t *mask = (uint64_t*)data; - - RARCH_LOG("Environ GET_INPUT_DEVICE_CAPABILITIES.\n"); - if (input_driver_has_capabilities()) - *mask = input_driver_get_capabilities(); - else - return false; - break; - } - - case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE: - { - struct retro_sensor_interface *iface = - (struct retro_sensor_interface*)data; - - RARCH_LOG("Environ GET_SENSOR_INTERFACE.\n"); - iface->set_sensor_state = input_sensor_set_state; - iface->get_sensor_input = input_sensor_get_input; - break; - } - case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE: - { - struct retro_camera_callback *cb = - (struct retro_camera_callback*)data; - - RARCH_LOG("Environ GET_CAMERA_INTERFACE.\n"); - cb->start = driver_camera_start; - cb->stop = driver_camera_stop; - - rarch_ctl(RARCH_CTL_CAMERA_SET_CB, cb); - - if (cb->caps != 0) - rarch_ctl(RARCH_CTL_CAMERA_SET_ACTIVE, NULL); - else - rarch_ctl(RARCH_CTL_CAMERA_UNSET_ACTIVE, NULL); - break; - } - - case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE: - { - struct retro_location_callback *cb = - (struct retro_location_callback*)data; - - RARCH_LOG("Environ GET_LOCATION_INTERFACE.\n"); - cb->start = driver_location_start; - cb->stop = driver_location_stop; - cb->get_position = driver_location_get_position; - cb->set_interval = driver_location_set_interval; - - if (system) - system->location_cb = *cb; - - rarch_ctl(RARCH_CTL_LOCATION_UNSET_ACTIVE, NULL); - break; - } - - case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: - { - struct retro_log_callback *cb = (struct retro_log_callback*)data; - - RARCH_LOG("Environ GET_LOG_INTERFACE.\n"); - cb->log = rarch_log_libretro; - break; - } - - case RETRO_ENVIRONMENT_GET_PERF_INTERFACE: - { - struct retro_perf_callback *cb = (struct retro_perf_callback*)data; - - RARCH_LOG("Environ GET_PERF_INTERFACE.\n"); - cb->get_time_usec = cpu_features_get_time_usec; - cb->get_cpu_features = cpu_features_get; - cb->get_perf_counter = cpu_features_get_perf_counter; - - cb->perf_register = performance_counter_register; - cb->perf_start = core_performance_counter_start; - cb->perf_stop = core_performance_counter_stop; - cb->perf_log = retro_perf_log; - break; - } - - case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY: - { - const char **dir = (const char**)data; - - *dir = *settings->paths.directory_core_assets ? - settings->paths.directory_core_assets : NULL; - RARCH_LOG("Environ CORE_ASSETS_DIRECTORY: \"%s\".\n", - settings->paths.directory_core_assets); - break; - } - - case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: - { - RARCH_LOG("Environ SET_SYSTEM_AV_INFO.\n"); - return driver_ctl(RARCH_DRIVER_CTL_UPDATE_SYSTEM_AV_INFO, - (void**)&data); - } - - case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: - { - unsigned i; - const struct retro_subsystem_info *info = - (const struct retro_subsystem_info*)data; - settings_t *settings = config_get_ptr(); - unsigned log_level = settings->uints.libretro_log_level; - - if (log_level == RETRO_LOG_DEBUG) - RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); - - for (i = 0; info[i].ident; i++) - { - unsigned j; - if (log_level != RETRO_LOG_DEBUG) - continue; - - RARCH_LOG("Special game type: %s\n", info[i].desc); - RARCH_LOG(" Ident: %s\n", info[i].ident); - RARCH_LOG(" ID: %u\n", info[i].id); - RARCH_LOG(" Content:\n"); - for (j = 0; j < info[i].num_roms; j++) - { - RARCH_LOG(" %s (%s)\n", - info[i].roms[j].desc, info[i].roms[j].required ? - "required" : "optional"); - } - } - - if (system) - { - struct retro_subsystem_info *info_ptr = NULL; - free(system->subsystem.data); - system->subsystem.data = NULL; - system->subsystem.size = 0; - - info_ptr = (struct retro_subsystem_info*) - malloc(i * sizeof(*info_ptr)); - - if (!info_ptr) - return false; - - system->subsystem.data = info_ptr; - - memcpy(system->subsystem.data, info, - i * sizeof(*system->subsystem.data)); - system->subsystem.size = i; - } - break; - } - - case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO: - { - unsigned i, j; - const struct retro_controller_info *info = - (const struct retro_controller_info*)data; - settings_t *settings = config_get_ptr(); - unsigned log_level = settings->uints.libretro_log_level; - - RARCH_LOG("Environ SET_CONTROLLER_INFO.\n"); - - for (i = 0; info[i].types; i++) - { - if (log_level != RETRO_LOG_DEBUG) - continue; - - RARCH_LOG("Controller port: %u\n", i + 1); - for (j = 0; j < info[i].num_types; j++) - RARCH_LOG(" %s (ID: %u)\n", info[i].types[j].desc, - info[i].types[j].id); - } - - if (system) - { - struct retro_controller_info *info_ptr = NULL; - - free(system->ports.data); - system->ports.data = NULL; - system->ports.size = 0; - - info_ptr = (struct retro_controller_info*)calloc(i, sizeof(*info_ptr)); - if (!info_ptr) - return false; - - system->ports.data = info_ptr; - memcpy(system->ports.data, info, - i * sizeof(*system->ports.data)); - system->ports.size = i; - } - break; - } - - case RETRO_ENVIRONMENT_SET_MEMORY_MAPS: - { - if (system) - { - unsigned i; - const struct retro_memory_map *mmaps = - (const struct retro_memory_map*)data; - rarch_memory_descriptor_t *descriptors = NULL; - - RARCH_LOG("Environ SET_MEMORY_MAPS.\n"); - free((void*)system->mmaps.descriptors); - system->mmaps.descriptors = 0; - system->mmaps.num_descriptors = 0; - descriptors = (rarch_memory_descriptor_t*) - calloc(mmaps->num_descriptors, - sizeof(*descriptors)); - - if (!descriptors) - return false; - - system->mmaps.descriptors = descriptors; - system->mmaps.num_descriptors = mmaps->num_descriptors; - - for (i = 0; i < mmaps->num_descriptors; i++) - system->mmaps.descriptors[i].core = mmaps->descriptors[i]; - - mmap_preprocess_descriptors(descriptors, mmaps->num_descriptors); - - if (sizeof(void *) == 8) - RARCH_LOG(" ndx flags ptr offset start select disconn len addrspace\n"); - else - RARCH_LOG(" ndx flags ptr offset start select disconn len addrspace\n"); - - for (i = 0; i < system->mmaps.num_descriptors; i++) - { - const rarch_memory_descriptor_t *desc = - &system->mmaps.descriptors[i]; - char flags[7]; - - flags[0] = 'M'; - if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_8) == RETRO_MEMDESC_MINSIZE_8) - flags[1] = '8'; - else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_4) == RETRO_MEMDESC_MINSIZE_4) - flags[1] = '4'; - else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_2) == RETRO_MEMDESC_MINSIZE_2) - flags[1] = '2'; - else - flags[1] = '1'; - - flags[2] = 'A'; - if ((desc->core.flags & RETRO_MEMDESC_ALIGN_8) == RETRO_MEMDESC_ALIGN_8) - flags[3] = '8'; - else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_4) == RETRO_MEMDESC_ALIGN_4) - flags[3] = '4'; - else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_2) == RETRO_MEMDESC_ALIGN_2) - flags[3] = '2'; - else - flags[3] = '1'; - - flags[4] = (desc->core.flags & RETRO_MEMDESC_BIGENDIAN) ? 'B' : 'b'; - flags[5] = (desc->core.flags & RETRO_MEMDESC_CONST) ? 'C' : 'c'; - flags[6] = 0; - - RARCH_LOG(" %03u %s %p %08X %08X %08X %08X %08X %s\n", - i + 1, flags, desc->core.ptr, desc->core.offset, desc->core.start, - desc->core.select, desc->core.disconnect, desc->core.len, - desc->core.addrspace ? desc->core.addrspace : ""); - } - } - else - { - RARCH_WARN("Environ SET_MEMORY_MAPS, but system pointer not initialized..\n"); - } - - break; - } - - case RETRO_ENVIRONMENT_SET_GEOMETRY: - { - const struct retro_game_geometry *in_geom = NULL; - struct retro_game_geometry *geom = NULL; - struct retro_system_av_info *av_info = - video_viewport_get_system_av_info(); - - if (av_info) - geom = (struct retro_game_geometry*)&av_info->geometry; - - if (!geom) - return false; - - in_geom = (const struct retro_game_geometry*)data; - - RARCH_LOG("Environ SET_GEOMETRY.\n"); - - /* Can potentially be called every frame, - * don't do anything unless required. */ - if ( (geom->base_width != in_geom->base_width) || - (geom->base_height != in_geom->base_height) || - (geom->aspect_ratio != in_geom->aspect_ratio)) - { - geom->base_width = in_geom->base_width; - geom->base_height = in_geom->base_height; - geom->aspect_ratio = in_geom->aspect_ratio; - - RARCH_LOG("SET_GEOMETRY: %ux%u, aspect: %.3f.\n", - geom->base_width, geom->base_height, geom->aspect_ratio); - - /* Forces recomputation of aspect ratios if - * using core-dependent aspect ratios. */ - command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL); - - /* TODO: Figure out what to do, if anything, with recording. */ - } - break; - } - - case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER: - return video_driver_get_current_software_framebuffer( - (struct retro_framebuffer*)data); - - case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE: - return video_driver_get_hw_render_interface( - (const struct retro_hw_render_interface**)data); - - case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS: -#ifdef HAVE_CHEEVOS - { - bool state = *(const bool*)data; - RARCH_LOG("Environ SET_SUPPORT_ACHIEVEMENTS: %s.\n", state ? "yes" : "no"); - rcheevos_set_support_cheevos(state); - } -#endif - break; - - case RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE: - { - const struct retro_hw_render_context_negotiation_interface *iface = - (const struct retro_hw_render_context_negotiation_interface*)data; - RARCH_LOG("Environ SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE.\n"); - video_driver_set_context_negotiation_interface(iface); - break; - } - - case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: - { - uint64_t *quirks = (uint64_t *) data; - core_set_serialization_quirks(*quirks); - break; - } - - case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT: - { - core_set_shared_context = true; - break; - } - - case RETRO_ENVIRONMENT_GET_VFS_INTERFACE: - { - const uint32_t supported_vfs_version = 3; - static struct retro_vfs_interface vfs_iface = - { - /* VFS API v1 */ - retro_vfs_file_get_path_impl, - retro_vfs_file_open_impl, - retro_vfs_file_close_impl, - retro_vfs_file_size_impl, - retro_vfs_file_tell_impl, - retro_vfs_file_seek_impl, - retro_vfs_file_read_impl, - retro_vfs_file_write_impl, - retro_vfs_file_flush_impl, - retro_vfs_file_remove_impl, - retro_vfs_file_rename_impl, - /* VFS API v2 */ - retro_vfs_file_truncate_impl, - /* VFS API v3 */ - retro_vfs_stat_impl, - retro_vfs_mkdir_impl, - retro_vfs_opendir_impl, - retro_vfs_readdir_impl, - retro_vfs_dirent_get_name_impl, - retro_vfs_dirent_is_dir_impl, - retro_vfs_closedir_impl - }; - - struct retro_vfs_interface_info *vfs_iface_info = (struct retro_vfs_interface_info *) data; - if (vfs_iface_info->required_interface_version <= supported_vfs_version) - { - RARCH_LOG("Core requested VFS version >= v%d, providing v%d\n", vfs_iface_info->required_interface_version, supported_vfs_version); - vfs_iface_info->required_interface_version = supported_vfs_version; - vfs_iface_info->iface = &vfs_iface; - system->supports_vfs = true; - } - else - { - RARCH_WARN("Core requested VFS version v%d which is higher than what we support (v%d)\n", vfs_iface_info->required_interface_version, supported_vfs_version); - return false; - } - - break; - } - - case RETRO_ENVIRONMENT_GET_LED_INTERFACE: - { - struct retro_led_interface *ledintf = - (struct retro_led_interface *)data; - if (ledintf) - ledintf->set_led_state = led_driver_set_led; - } - break; - - case RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE: - { - int result = 0; - if (!audio_driver_is_suspended() && audio_driver_is_active()) - result |= 2; - if (video_driver_is_active() && !video_driver_is_stub_frame()) - result |= 1; -#ifdef HAVE_RUNAHEAD - if (want_fast_savestate()) - result |= 4; - if (get_hard_disable_audio()) - result |= 8; -#endif -#ifdef HAVE_NETWORKING - if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_REPLAYING, NULL)) - result &= ~(1|2); - if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) - result |= 4; -#endif - if (data != NULL) - { - int* result_p = (int*)data; - *result_p = result; - } - break; - } - - case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE: - { - struct retro_midi_interface *midi_interface = - (struct retro_midi_interface *)data; - - if (midi_interface) - { - midi_interface->input_enabled = midi_driver_input_enabled; - midi_interface->output_enabled = midi_driver_output_enabled; - midi_interface->read = midi_driver_read; - midi_interface->write = midi_driver_write; - midi_interface->flush = midi_driver_flush; - } - break; - } - - case RETRO_ENVIRONMENT_GET_FASTFORWARDING: - { - extern bool runloop_fastmotion; - *(bool *)data = runloop_fastmotion; - break; - } - - case RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB: - { - *(retro_environment_t *)data = rarch_clear_all_thread_waits; - break; - } - - case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS: - /* Just falldown, the function will return true */ - break; - - case RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE: - { - /* Try to use the polled refresh rate first. */ - float target_refresh_rate = video_driver_get_refresh_rate(); - - /* If the above function failed [possibly because it is not - * implemented], use the refresh rate set in the config instead. */ - if (target_refresh_rate == 0.0 && settings) - target_refresh_rate = settings->floats.video_refresh_rate; - - *(float *)data = target_refresh_rate; - break; - } - - default: - RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); - return false; - } - - return true; -} diff --git a/dynamic.h b/dynamic.h index 04e3f81589..7e8e2d787a 100644 --- a/dynamic.h +++ b/dynamic.h @@ -120,32 +120,6 @@ struct retro_core_t bool libretro_get_shared_context(void); -/** - * init_libretro_sym: - * @type : Type of core to be loaded. - * If CORE_TYPE_DUMMY, will - * load dummy symbols. - * - * Initializes libretro symbols and - * setups environment callback functions. Returns true on success, - * or false if symbols could not be loaded. - **/ -bool init_libretro_sym(enum rarch_core_type type, - struct retro_core_t *core); - -bool init_libretro_sym_custom(enum rarch_core_type type, struct retro_core_t *current_core, const char *lib_path, void *lib_handle_p); - -/** - * uninit_libretro_sym: - * - * Frees libretro core. - * - * Frees all core options, - * associated state, and - * unbind all libretro callback symbols. - **/ -void uninit_libretro_sym(struct retro_core_t *core); - /* Arbitrary twenty subsystems limite */ #define SUBSYSTEM_MAX_SUBSYSTEMS 20 /* Arbitrary 10 roms for each subsystem limit */ diff --git a/griffin/griffin.c b/griffin/griffin.c index eb42e2ea64..dd1091a229 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -918,7 +918,6 @@ FILTERS DYNAMIC ============================================================ */ #include "../libretro-common/dynamic/dylib.c" -#include "../dynamic.c" #include "../gfx/video_filter.c" #include "../libretro-common/audio/dsp_filter.c" diff --git a/input/input_driver.h b/input/input_driver.h index 90a87838cf..31d620c50f 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -244,22 +244,6 @@ bool input_sensor_set_state(unsigned port, float input_sensor_get_input(unsigned port, unsigned id); -/** - * input_state: - * @port : user number. - * @device : device identifier of user. - * @idx : index value of user. - * @id : identifier of key pressed by user. - * - * Input state callback function. - * - * Returns: Non-zero if the given key (identified by @id) - * was pressed by the user - * (assigned to @port). - **/ -int16_t input_state(unsigned port, unsigned device, - unsigned idx, unsigned id); - void *input_driver_get_data(void); void input_get_state_for_port( @@ -269,10 +253,6 @@ const input_driver_t *input_get_ptr(void); void *input_get_data(void); -void **input_driver_get_data_ptr(void); - -bool input_driver_has_capabilities(void); - void input_driver_set_flushing_input(void); void input_driver_unset_hotkey_block(void); diff --git a/retroarch.c b/retroarch.c index 7b2d193c5e..1bf791642f 100644 --- a/retroarch.c +++ b/retroarch.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,11 @@ #include #include #include +#include +#define VFS_FRONTEND +#include + +#include #include #include @@ -74,7 +80,6 @@ #include #include #include -#include #include #include @@ -128,9 +133,16 @@ #include #endif +#if defined(HAVE_OPENGL) +#include "gfx/common/gl_common.h" +#elif defined(HAVE_OPENGL_CORE) +#include "gfx/common/gl_core_common.h" +#endif + #include "autosave.h" #include "command.h" #include "config.features.h" +#include "cores/internal_cores.h" #include "content.h" #include "core_type.h" #include "core_info.h" @@ -172,7 +184,6 @@ #include "runahead/copy_load_info.h" #include "runahead/mylist.h" #include "runahead/mem_util.h" -#include "runahead/run_ahead.h" #endif #include "audio/audio_thread_wrapper.h" @@ -794,7 +805,7 @@ 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_fastmotion = false; static bool runloop_shutdown_initiated = false; static bool runloop_core_shutdown_initiated = false; static bool runloop_perfcnt_enable = false; @@ -1583,12 +1594,12 @@ static const void *hid_data = NULL; #if defined(HAVE_RUNAHEAD) #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB) -#include /* Forward declarations */ static bool secondary_core_create(void); static int16_t input_state_get_last(unsigned port, unsigned device, unsigned index, unsigned id); + extern retro_ctx_load_content_info_t *load_content_info; extern enum rarch_core_type last_core_type; @@ -1602,7 +1613,21 @@ static char *secondary_library_path = NULL; #endif #endif +static bool core_uninit_libretro_callbacks(void); +static bool core_is_game_loaded(void); +static int16_t input_state(unsigned port, unsigned device, + unsigned idx, unsigned id); +static bool driver_update_system_av_info( + const struct retro_system_av_info *info); + /* GLOBAL POINTER GETTERS */ +#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(); +} + struct retro_system_av_info *video_viewport_get_system_av_info(void) { return &video_driver_av_info; @@ -1641,6 +1666,2119 @@ void *video_driver_get_ptr(bool force_nonthreaded_data) return video_driver_get_ptr_internal(force_nonthreaded_data); } +/* CORE OPTIONS */ +static bool core_option_manager_parse_variable( + core_option_manager_t *opt, size_t idx, + const struct retro_variable *var) +{ + const char *val_start = NULL; + char *value = NULL; + char *desc_end = NULL; + char *config_val = NULL; + struct core_option *option = (struct core_option*)&opt->opts[idx]; + + if (!string_is_empty(var->key)) + option->key = strdup(var->key); + if (!string_is_empty(var->value)) + value = strdup(var->value); + + if (!string_is_empty(value)) + desc_end = strstr(value, "; "); + + if (!desc_end) + goto error; + + *desc_end = '\0'; + + if (!string_is_empty(value)) + option->desc = strdup(value); + + val_start = desc_end + 2; + option->vals = string_split(val_start, "|"); + + if (!option->vals) + goto error; + + if (config_get_string(opt->conf, option->key, &config_val)) + { + size_t i; + + for (i = 0; i < option->vals->size; i++) + { + if (string_is_equal(option->vals->elems[i].data, config_val)) + { + option->index = i; + break; + } + } + + free(config_val); + } + + free(value); + + return true; + +error: + free(value); + return false; +} + +/** + * core_option_manager_free: + * @opt : options manager handle + * + * Frees core option manager handle. + **/ +static void core_option_manager_free(core_option_manager_t *opt) +{ + size_t i; + + if (!opt) + return; + + for (i = 0; i < opt->size; i++) + { + if (opt->opts[i].desc) + free(opt->opts[i].desc); + if (opt->opts[i].key) + free(opt->opts[i].key); + + if (opt->opts[i].vals) + string_list_free(opt->opts[i].vals); + + opt->opts[i].desc = NULL; + opt->opts[i].key = NULL; + opt->opts[i].vals = NULL; + } + + if (opt->conf) + config_file_free(opt->conf); + free(opt->opts); + free(opt); +} + +static void core_option_manager_get(core_option_manager_t *opt, + struct retro_variable *var) +{ + size_t i; + +#ifdef HAVE_RUNAHEAD + if (opt->updated) + has_variable_update = true; +#endif + + opt->updated = false; + + for (i = 0; i < opt->size; i++) + { + if (string_is_empty(opt->opts[i].key)) + continue; + + if (string_is_equal(opt->opts[i].key, var->key)) + { + var->value = opt->opts[i].vals->elems[opt->opts[i].index].data; + return; + } + } + + var->value = NULL; +} + +/** + * core_option_manager_new: + * @conf_path : Filesystem path to write core option config file to. + * @vars : Pointer to variable array handle. + * + * Creates and initializes a core manager handle. + * + * Returns: handle to new core manager handle, otherwise NULL. + **/ +static core_option_manager_t *core_option_manager_new(const char *conf_path, + const struct retro_variable *vars) +{ + const struct retro_variable *var; + size_t size = 0; + core_option_manager_t *opt = (core_option_manager_t*) + calloc(1, sizeof(*opt)); + + if (!opt) + return NULL; + + if (!string_is_empty(conf_path)) + opt->conf = config_file_new(conf_path); + if (!opt->conf) + opt->conf = config_file_new(NULL); + + strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path)); + + if (!opt->conf) + goto error; + + for (var = vars; var->key && var->value; var++) + size++; + + if (size == 0) + goto error; + + opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts)); + if (!opt->opts) + goto error; + + opt->size = size; + size = 0; + + for (var = vars; var->key && var->value; size++, var++) + { + if (!core_option_manager_parse_variable(opt, size, var)) + goto error; + } + + return opt; + +error: + core_option_manager_free(opt); + return NULL; +} + +/** + * core_option_manager_flush: + * @opt : options manager handle + * + * Writes core option key-pair values to file. + * + * Returns: true (1) if core option values could be + * successfully saved to disk, otherwise false (0). + **/ +static bool core_option_manager_flush(core_option_manager_t *opt) +{ + size_t i; + + for (i = 0; i < opt->size; i++) + { + struct core_option *option = (struct core_option*)&opt->opts[i]; + + if (option) + config_set_string(opt->conf, option->key, + opt->opts[i].vals->elems[opt->opts[i].index].data); + } + + RARCH_LOG("Saved core options file to \"%s\"\n", opt->conf_path); + return config_file_write(opt->conf, opt->conf_path, true); +} + +/** + * core_option_manager_flush_game_specific: + * @opt : options manager handle + * @path : path for the core options file + * + * Writes core option key-pair values to a custom file. + * + * Returns: true (1) if core option values could be + * successfully saved to disk, otherwise false (0). + **/ +static bool core_option_manager_flush_game_specific( + core_option_manager_t *opt, const char* path) +{ + size_t i; + for (i = 0; i < opt->size; i++) + { + struct core_option *option = (struct core_option*)&opt->opts[i]; + + if (option) + config_set_string(opt->conf, option->key, + opt->opts[i].vals->elems[opt->opts[i].index].data); + } + + return config_file_write(opt->conf, path, true); +} + +/** + * core_option_manager_get_desc: + * @opt : options manager handle + * @index : index identifier of the option + * + * Gets description for an option. + * + * Returns: Description for an option. + **/ +const char *core_option_manager_get_desc( + core_option_manager_t *opt, size_t idx) +{ + if (!opt) + return NULL; + return opt->opts[idx].desc; +} + +/** + * core_option_manager_get_val: + * @opt : options manager handle + * @index : index identifier of the option + * + * Gets value for an option. + * + * Returns: Value for an option. + **/ +const char *core_option_manager_get_val(core_option_manager_t *opt, size_t idx) +{ + struct core_option *option = NULL; + if (!opt) + return NULL; + option = (struct core_option*)&opt->opts[idx]; + return option->vals->elems[option->index].data; +} + +void core_option_manager_set_val(core_option_manager_t *opt, + size_t idx, size_t val_idx) +{ + struct core_option *option= NULL; + + if (!opt) + return; + + option = (struct core_option*)&opt->opts[idx]; + option->index = val_idx % option->vals->size; + + opt->updated = true; +} + +/** + * core_option_manager_set_default: + * @opt : pointer to core option manager object. + * @idx : index of core option to be reset to defaults. + * + * Reset core option specified by @idx and sets default value for option. + **/ +void core_option_manager_set_default(core_option_manager_t *opt, size_t idx) +{ + if (!opt) + return; + + opt->opts[idx].index = 0; + opt->updated = true; +} + + +/* DYNAMIC LIBRETRO CORE */ + +#ifdef HAVE_DYNAMIC +#define SYMBOL(x) do { \ + function_t func = dylib_proc(lib_handle_local, #x); \ + memcpy(¤t_core->x, &func, sizeof(func)); \ + if (current_core->x == NULL) { RARCH_ERR("Failed to load symbol: \"%s\"\n", #x); retroarch_fail(1, "init_libretro_symbols()"); } \ +} while (0) + +static dylib_t lib_handle; +#else +#define SYMBOL(x) current_core->x = x +#endif + +#define SYMBOL_DUMMY(x) current_core->x = libretro_dummy_##x + +#ifdef HAVE_FFMPEG +#define SYMBOL_FFMPEG(x) current_core->x = libretro_ffmpeg_##x +#endif + +#ifdef HAVE_MPV +#define SYMBOL_MPV(x) current_core->x = libretro_mpv_##x +#endif + +#ifdef HAVE_IMAGEVIEWER +#define SYMBOL_IMAGEVIEWER(x) current_core->x = libretro_imageviewer_##x +#endif + +#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) +#define SYMBOL_NETRETROPAD(x) current_core->x = libretro_netretropad_##x +#endif + +#if defined(HAVE_VIDEOPROCESSOR) +#define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x +#endif + +#ifdef HAVE_EASTEREGG +#define SYMBOL_GONG(x) current_core->x = libretro_gong_##x +#endif + +#define CORE_SYMBOLS(x) \ + x(retro_init); \ + x(retro_deinit); \ + x(retro_api_version); \ + x(retro_get_system_info); \ + x(retro_get_system_av_info); \ + x(retro_set_environment); \ + x(retro_set_video_refresh); \ + x(retro_set_audio_sample); \ + x(retro_set_audio_sample_batch); \ + x(retro_set_input_poll); \ + x(retro_set_input_state); \ + x(retro_set_controller_port_device); \ + x(retro_reset); \ + x(retro_run); \ + x(retro_serialize_size); \ + x(retro_serialize); \ + x(retro_unserialize); \ + x(retro_cheat_reset); \ + x(retro_cheat_set); \ + x(retro_load_game); \ + x(retro_load_game_special); \ + x(retro_unload_game); \ + x(retro_get_region); \ + x(retro_get_memory_data); \ + x(retro_get_memory_size); + +static bool ignore_environment_cb = false; +static bool core_set_shared_context = false; +static bool *load_no_content_hook = NULL; + +struct retro_subsystem_info subsystem_data[SUBSYSTEM_MAX_SUBSYSTEMS]; +struct retro_subsystem_rom_info subsystem_data_roms[SUBSYSTEM_MAX_SUBSYSTEMS][SUBSYSTEM_MAX_SUBSYSTEM_ROMS]; +unsigned subsystem_current_count; + +const struct retro_subsystem_info *libretro_find_subsystem_info( + const struct retro_subsystem_info *info, unsigned num_info, + const char *ident) +{ + unsigned i; + for (i = 0; i < num_info; i++) + { + if (string_is_equal(info[i].ident, ident)) + return &info[i]; + else if (string_is_equal(info[i].desc, ident)) + return &info[i]; + } + + return NULL; +} + +/** + * libretro_find_controller_description: + * @info : Pointer to controller info handle. + * @id : Identifier of controller to search + * for. + * + * Search for a controller of type @id in @info. + * + * Returns: controller description of found controller on success, + * otherwise NULL. + **/ +const struct retro_controller_description * +libretro_find_controller_description( + const struct retro_controller_info *info, unsigned id) +{ + unsigned i; + + for (i = 0; i < info->num_types; i++) + { + if (info->types[i].id != id) + continue; + + return &info->types[i]; + } + + return NULL; +} + +/** + * libretro_free_system_info: + * @info : Pointer to system info information. + * + * Frees system information. + **/ +void libretro_free_system_info(struct retro_system_info *info) +{ + if (!info) + return; + + free((void*)info->library_name); + free((void*)info->library_version); + free((void*)info->valid_extensions); + memset(info, 0, sizeof(*info)); +} + +static bool environ_cb_get_system_info(unsigned cmd, void *data) +{ + rarch_system_info_t *system = &runloop_system; + switch (cmd) + { + case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: + *load_no_content_hook = *(const bool*)data; + break; + case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: + { + unsigned i, j, size; + const struct retro_subsystem_info *info = + (const struct retro_subsystem_info*)data; + settings_t *settings = configuration_settings; + unsigned log_level = settings->uints.libretro_log_level; + + subsystem_current_count = 0; + + RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); + + for (i = 0; info[i].ident; i++) + { + if (log_level != RETRO_LOG_DEBUG) + continue; + + RARCH_LOG("Subsystem ID: %d\n", i); + RARCH_LOG("Special game type: %s\n", info[i].desc); + RARCH_LOG(" Ident: %s\n", info[i].ident); + RARCH_LOG(" ID: %u\n", info[i].id); + RARCH_LOG(" Content:\n"); + for (j = 0; j < info[i].num_roms; j++) + { + RARCH_LOG(" %s (%s)\n", + info[i].roms[j].desc, info[i].roms[j].required ? + "required" : "optional"); + } + } + + if (log_level == RETRO_LOG_DEBUG) + RARCH_LOG("Subsystems: %d\n", i); + size = i; + + if (log_level == RETRO_LOG_DEBUG) + if (size > SUBSYSTEM_MAX_SUBSYSTEMS) + RARCH_WARN("Subsystems exceed subsystem max, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEMS); + + if (system) + { + for (i = 0; i < size && i < SUBSYSTEM_MAX_SUBSYSTEMS; i++) + { + /* Nasty, but have to do it like this since + * the pointers are const char * + * (if we don't free them, we get a memory leak) */ + if (!string_is_empty(subsystem_data[i].desc)) + free((char *)subsystem_data[i].desc); + if (!string_is_empty(subsystem_data[i].ident)) + free((char *)subsystem_data[i].ident); + subsystem_data[i].desc = strdup(info[i].desc); + subsystem_data[i].ident = strdup(info[i].ident); + subsystem_data[i].id = info[i].id; + subsystem_data[i].num_roms = info[i].num_roms; + + if (log_level == RETRO_LOG_DEBUG) + if (subsystem_data[i].num_roms > SUBSYSTEM_MAX_SUBSYSTEM_ROMS) + RARCH_WARN("Subsystems exceed subsystem max roms, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEM_ROMS); + + for (j = 0; j < subsystem_data[i].num_roms && j < SUBSYSTEM_MAX_SUBSYSTEM_ROMS; j++) + { + /* Nasty, but have to do it like this since + * the pointers are const char * + * (if we don't free them, we get a memory leak) */ + if (!string_is_empty(subsystem_data_roms[i][j].desc)) + free((char *)subsystem_data_roms[i][j].desc); + if (!string_is_empty(subsystem_data_roms[i][j].valid_extensions)) + free((char *)subsystem_data_roms[i][j].valid_extensions); + subsystem_data_roms[i][j].desc = strdup(info[i].roms[j].desc); + subsystem_data_roms[i][j].valid_extensions = strdup(info[i].roms[j].valid_extensions); + subsystem_data_roms[i][j].required = info[i].roms[j].required; + subsystem_data_roms[i][j].block_extract = info[i].roms[j].block_extract; + subsystem_data_roms[i][j].need_fullpath = info[i].roms[j].need_fullpath; + } + subsystem_data[i].roms = subsystem_data_roms[i]; + } + + subsystem_current_count = + size <= SUBSYSTEM_MAX_SUBSYSTEMS + ? size + : SUBSYSTEM_MAX_SUBSYSTEMS; + } + break; + } + default: + return false; + } + + return true; +} + +static bool dynamic_request_hw_context(enum retro_hw_context_type type, + unsigned minor, unsigned major) +{ + switch (type) + { + case RETRO_HW_CONTEXT_NONE: + RARCH_LOG("Requesting no HW context.\n"); + break; + + case RETRO_HW_CONTEXT_VULKAN: +#ifdef HAVE_VULKAN + RARCH_LOG("Requesting Vulkan context.\n"); + break; +#else + RARCH_ERR("Requesting Vulkan context, but RetroArch is not compiled against Vulkan. Cannot use HW context.\n"); + return false; +#endif + +#if defined(HAVE_OPENGLES) + +#if (defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3)) + case RETRO_HW_CONTEXT_OPENGLES2: + case RETRO_HW_CONTEXT_OPENGLES3: + RARCH_LOG("Requesting OpenGLES%u context.\n", + type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); + break; + +#if defined(HAVE_OPENGLES3) + case RETRO_HW_CONTEXT_OPENGLES_VERSION: + RARCH_LOG("Requesting OpenGLES%u.%u context.\n", + major, minor); + break; +#endif + +#endif + case RETRO_HW_CONTEXT_OPENGL: + case RETRO_HW_CONTEXT_OPENGL_CORE: + RARCH_ERR("Requesting OpenGL context, but RetroArch " + "is compiled against OpenGLES. Cannot use HW context.\n"); + return false; + +#elif defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE) + case RETRO_HW_CONTEXT_OPENGLES2: + case RETRO_HW_CONTEXT_OPENGLES3: + RARCH_ERR("Requesting OpenGLES%u context, but RetroArch " + "is compiled against OpenGL. Cannot use HW context.\n", + type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); + return false; + + case RETRO_HW_CONTEXT_OPENGLES_VERSION: + RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch " + "is compiled against OpenGL. Cannot use HW context.\n", + major, minor); + return false; + + case RETRO_HW_CONTEXT_OPENGL: + RARCH_LOG("Requesting OpenGL context.\n"); + break; + + case RETRO_HW_CONTEXT_OPENGL_CORE: + /* TODO/FIXME - we should do a check here to see if + * the requested core GL version is supported */ + RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", + major, minor); + break; +#endif + +#if defined(HAVE_D3D9) || defined(HAVE_D3D11) + case RETRO_HW_CONTEXT_DIRECT3D: + switch (major) + { +#ifdef HAVE_D3D9 + case 9: + RARCH_LOG("Requesting D3D9 context.\n"); + break; +#endif +#ifdef HAVE_D3D11 + case 11: + RARCH_LOG("Requesting D3D11 context.\n"); + break; +#endif + default: + RARCH_LOG("Requesting unknown context.\n"); + return false; + } + break; +#endif + + default: + RARCH_LOG("Requesting unknown context.\n"); + return false; + } + + return true; +} + +static bool dynamic_verify_hw_context(enum retro_hw_context_type type, + unsigned minor, unsigned major) +{ + const char *video_ident = (current_video) ? current_video->ident : NULL; + + switch (type) + { + case RETRO_HW_CONTEXT_VULKAN: + if (!string_is_equal(video_ident, "vulkan")) + return false; + break; + case RETRO_HW_CONTEXT_OPENGLES2: + case RETRO_HW_CONTEXT_OPENGLES3: + case RETRO_HW_CONTEXT_OPENGLES_VERSION: + case RETRO_HW_CONTEXT_OPENGL: + case RETRO_HW_CONTEXT_OPENGL_CORE: + if (!string_is_equal(video_ident, "gl") && + !string_is_equal(video_ident, "glcore")) + { + return false; + } + break; + case RETRO_HW_CONTEXT_DIRECT3D: + if (!(string_is_equal(video_ident, "d3d11") && major == 11)) + return false; + break; + default: + break; + } + + return true; +} + +static void rarch_log_libretro(enum retro_log_level level, + const char *fmt, ...) +{ + va_list vp; + settings_t *settings = configuration_settings; + + if ((unsigned)level < settings->uints.libretro_log_level) + return; + + if (!verbosity_is_enabled()) + return; + + va_start(vp, fmt); + + switch (level) + { + case RETRO_LOG_DEBUG: + RARCH_LOG_V("[libretro DEBUG]", fmt, vp); + break; + + case RETRO_LOG_INFO: + RARCH_LOG_OUTPUT_V("[libretro INFO]", fmt, vp); + break; + + case RETRO_LOG_WARN: + RARCH_WARN_V("[libretro WARN]", fmt, vp); + break; + + case RETRO_LOG_ERROR: + RARCH_ERR_V("[libretro ERROR]", fmt, vp); + break; + + default: + break; + } + + va_end(vp); +} + +static void core_performance_counter_start(struct retro_perf_counter *perf) +{ + if (rarch_ctl(RARCH_CTL_IS_PERFCNT_ENABLE, NULL)) + { + perf->call_cnt++; + perf->start = cpu_features_get_perf_counter(); + } +} + +static void core_performance_counter_stop(struct retro_perf_counter *perf) +{ + if (rarch_ctl(RARCH_CTL_IS_PERFCNT_ENABLE, NULL)) + perf->total += cpu_features_get_perf_counter() - perf->start; +} + +static size_t mmap_add_bits_down(size_t n) +{ + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + + /* double shift to avoid warnings on 32bit (it's dead code, but compilers suck) */ + if (sizeof(size_t) > 4) + n |= n >> 16 >> 16; + + return n; +} + +static size_t mmap_inflate(size_t addr, size_t mask) +{ + while (mask) + { + size_t tmp = (mask - 1) & ~mask; + + /* to put in an 1 bit instead, OR in tmp+1 */ + addr = ((addr & ~tmp) << 1) | (addr & tmp); + mask = mask & (mask - 1); + } + + return addr; +} + +static size_t mmap_reduce(size_t addr, size_t mask) +{ + while (mask) + { + size_t tmp = (mask - 1) & ~mask; + addr = (addr & tmp) | ((addr >> 1) & ~tmp); + mask = (mask & (mask - 1)) >> 1; + } + + return addr; +} + +static size_t mmap_highest_bit(size_t n) +{ + n = mmap_add_bits_down(n); + return n ^ (n >> 1); +} + + +static bool mmap_preprocess_descriptors(rarch_memory_descriptor_t *first, unsigned count) +{ + size_t top_addr = 1; + rarch_memory_descriptor_t *desc = NULL; + const rarch_memory_descriptor_t *end = first + count; + + for (desc = first; desc < end; desc++) + { + if (desc->core.select != 0) + top_addr |= desc->core.select; + else + top_addr |= desc->core.start + desc->core.len - 1; + } + + top_addr = mmap_add_bits_down(top_addr); + + for (desc = first; desc < end; desc++) + { + if (desc->core.select == 0) + { + if (desc->core.len == 0) + return false; + + if ((desc->core.len & (desc->core.len - 1)) != 0) + return false; + + desc->core.select = top_addr & ~mmap_inflate(mmap_add_bits_down(desc->core.len - 1), + desc->core.disconnect); + } + + if (desc->core.len == 0) + desc->core.len = mmap_add_bits_down(mmap_reduce(top_addr & ~desc->core.select, + desc->core.disconnect)) + 1; + + if (desc->core.start & ~desc->core.select) + return false; + + while (mmap_reduce(top_addr & ~desc->core.select, desc->core.disconnect) >> 1 > desc->core.len - 1) + desc->core.disconnect |= mmap_highest_bit(top_addr & ~desc->core.select & ~desc->core.disconnect); + + desc->disconnect_mask = mmap_add_bits_down(desc->core.len - 1); + desc->core.disconnect &= desc->disconnect_mask; + + while ((~desc->disconnect_mask) >> 1 & desc->core.disconnect) + { + desc->disconnect_mask >>= 1; + desc->core.disconnect &= desc->disconnect_mask; + } + } + + return true; +} + +static bool rarch_clear_all_thread_waits(unsigned clear_threads, void *data) +{ + if ( clear_threads > 0) + audio_driver_start(false) ; + else + audio_driver_stop() ; + + return true; +} + + + +/** + * rarch_environment_cb: + * @cmd : Identifier of command. + * @data : Pointer to data. + * + * Environment callback function implementation. + * + * Returns: true (1) if environment callback command could + * be performed, otherwise false (0). + **/ +bool rarch_environment_cb(unsigned cmd, void *data) +{ + unsigned p; + settings_t *settings = configuration_settings; + rarch_system_info_t *system = &runloop_system; + + if (ignore_environment_cb) + return false; + + switch (cmd) + { + case RETRO_ENVIRONMENT_GET_OVERSCAN: + *(bool*)data = !settings->bools.video_crop_overscan; + RARCH_LOG("Environ GET_OVERSCAN: %u\n", + (unsigned)!settings->bools.video_crop_overscan); + break; + + case RETRO_ENVIRONMENT_GET_CAN_DUPE: + *(bool*)data = true; + RARCH_LOG("Environ GET_CAN_DUPE: true\n"); + break; + + case RETRO_ENVIRONMENT_GET_VARIABLE: + { + unsigned log_level = settings->uints.libretro_log_level; + struct retro_variable *var = (struct retro_variable*)data; + + if (!runloop_core_options || !var) + { + if (var) + { + RARCH_LOG("Environ GET_VARIABLE %s: not implemented.\n", + var->key); + var->value = NULL; + } + return true; + } + core_option_manager_get(runloop_core_options, var); + + 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)); + } + } + + break; + + case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE: + if (runloop_core_options) + *(bool*)data = runloop_core_options->updated; + else + *(bool*)data = false; + break; + + case RETRO_ENVIRONMENT_SET_VARIABLES: + RARCH_LOG("Environ SET_VARIABLES.\n"); + + rarch_ctl(RARCH_CTL_CORE_OPTIONS_DEINIT, NULL); + rarch_ctl(RARCH_CTL_CORE_OPTIONS_INIT, data); + + break; + + case RETRO_ENVIRONMENT_SET_MESSAGE: + { + const struct retro_message *msg = (const struct retro_message*)data; + RARCH_LOG("Environ SET_MESSAGE: %s\n", msg->msg); +#ifdef HAVE_MENU_WIDGETS + if (!menu_widgets_set_libretro_message(msg->msg, roundf((float)msg->frames / 60.0f * 1000.0f))) +#endif + runloop_msg_queue_push(msg->msg, 3, msg->frames, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + break; + } + + case RETRO_ENVIRONMENT_SET_ROTATION: + { + unsigned rotation = *(const unsigned*)data; + RARCH_LOG("Environ SET_ROTATION: %u\n", rotation); + if (!settings->bools.video_allow_rotate) + break; + + if (system) + system->rotation = rotation; + + if (!video_driver_set_rotation(rotation)) + return false; + break; + } + + case RETRO_ENVIRONMENT_SHUTDOWN: + RARCH_LOG("Environ SHUTDOWN.\n"); + + /* This case occurs when a core (internally) requests + * a shutdown event. Must save runtime log file here, + * since normal command.c CMD_EVENT_CORE_DEINIT event + * will not occur until after the current content has + * been cleared (causing log to be skipped) */ + rarch_ctl(RARCH_CTL_CONTENT_RUNTIME_LOG_DEINIT, NULL); + + rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); + rarch_ctl(RARCH_CTL_SET_CORE_SHUTDOWN, NULL); + break; + + case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: + if (system) + { + system->performance_level = *(const unsigned*)data; + RARCH_LOG("Environ PERFORMANCE_LEVEL: %u.\n", + system->performance_level); + } + break; + + case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: + if (string_is_empty(settings->paths.directory_system) || settings->bools.systemfiles_in_content_dir) + { + const char *fullpath = path_get(RARCH_PATH_CONTENT); + if (!string_is_empty(fullpath)) + { + size_t path_size = PATH_MAX_LENGTH * sizeof(char); + char *temp_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + + temp_path[0] = '\0'; + + if (string_is_empty(settings->paths.directory_system)) + RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", + fullpath); + fill_pathname_basedir(temp_path, fullpath, path_size); + dir_set(RARCH_DIR_SYSTEM, temp_path); + free(temp_path); + } + + *(const char**)data = dir_get_ptr(RARCH_DIR_SYSTEM); + RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", + dir_get(RARCH_DIR_SYSTEM)); + } + else + { + *(const char**)data = settings->paths.directory_system; + RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", + settings->paths.directory_system); + } + + break; + + case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: + *(const char**)data = dir_get(RARCH_DIR_CURRENT_SAVEFILE); + break; + + case RETRO_ENVIRONMENT_GET_USERNAME: + *(const char**)data = *settings->paths.username ? + settings->paths.username : NULL; + RARCH_LOG("Environ GET_USERNAME: \"%s\".\n", + settings->paths.username); + break; + + case RETRO_ENVIRONMENT_GET_LANGUAGE: +#ifdef HAVE_LANGEXTRA + { + unsigned user_lang = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE); + *(unsigned *)data = user_lang; + RARCH_LOG("Environ GET_LANGUAGE: \"%u\".\n", user_lang); + } +#endif + break; + + case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: + { + enum retro_pixel_format pix_fmt = + *(const enum retro_pixel_format*)data; + + switch (pix_fmt) + { + case RETRO_PIXEL_FORMAT_0RGB1555: + RARCH_LOG("Environ SET_PIXEL_FORMAT: 0RGB1555.\n"); + break; + + case RETRO_PIXEL_FORMAT_RGB565: + RARCH_LOG("Environ SET_PIXEL_FORMAT: RGB565.\n"); + break; + case RETRO_PIXEL_FORMAT_XRGB8888: + RARCH_LOG("Environ SET_PIXEL_FORMAT: XRGB8888.\n"); + break; + default: + return false; + } + + video_driver_set_pixel_format(pix_fmt); + break; + } + + case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: + { + static const char *libretro_btn_desc[] = { + "B (bottom)", "Y (left)", "Select", "Start", + "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right", + "A (right)", "X (up)", + "L", "R", "L2", "R2", "L3", "R3", + }; + + if (system) + { + unsigned retro_id; + const struct retro_input_descriptor *desc = NULL; + memset((void*)&system->input_desc_btn, 0, + sizeof(system->input_desc_btn)); + + desc = (const struct retro_input_descriptor*)data; + + for (; desc->description; desc++) + { + unsigned retro_port = desc->port; + + retro_id = desc->id; + + if (desc->port >= MAX_USERS) + continue; + + /* Ignore all others for now. */ + if ( + desc->device != RETRO_DEVICE_JOYPAD && + desc->device != RETRO_DEVICE_ANALOG) + continue; + + if (desc->id >= RARCH_FIRST_CUSTOM_BIND) + continue; + + if (desc->device == RETRO_DEVICE_ANALOG) + { + switch (retro_id) + { + case RETRO_DEVICE_ID_ANALOG_X: + switch (desc->index) + { + case RETRO_DEVICE_INDEX_ANALOG_LEFT: + system->input_desc_btn[retro_port] + [RARCH_ANALOG_LEFT_X_PLUS] = desc->description; + system->input_desc_btn[retro_port] + [RARCH_ANALOG_LEFT_X_MINUS] = desc->description; + break; + case RETRO_DEVICE_INDEX_ANALOG_RIGHT: + system->input_desc_btn[retro_port] + [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description; + system->input_desc_btn[retro_port] + [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description; + break; + } + break; + case RETRO_DEVICE_ID_ANALOG_Y: + switch (desc->index) + { + case RETRO_DEVICE_INDEX_ANALOG_LEFT: + system->input_desc_btn[retro_port] + [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description; + system->input_desc_btn[retro_port] + [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description; + break; + case RETRO_DEVICE_INDEX_ANALOG_RIGHT: + system->input_desc_btn[retro_port] + [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description; + system->input_desc_btn[retro_port] + [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description; + break; + } + break; + } + } + else + system->input_desc_btn[retro_port] + [retro_id] = desc->description; + } + + RARCH_LOG("Environ SET_INPUT_DESCRIPTORS:\n"); + + { + unsigned log_level = settings->uints.libretro_log_level; + + if (log_level == RETRO_LOG_DEBUG) + { + for (p = 0; p < input_driver_max_users; p++) + { + for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++) + { + const char *description = system->input_desc_btn[p][retro_id]; + + if (!description) + continue; + + RARCH_LOG("\tRetroPad, User %u, Button \"%s\" => \"%s\"\n", + p + 1, libretro_btn_desc[retro_id], description); + } + } + } + } + + current_core.has_set_input_descriptors = true; + } + + break; + } + + case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: + { + retro_keyboard_event_t *frontend_key_event = NULL; + retro_keyboard_event_t *key_event = NULL; + const struct retro_keyboard_callback *info = + (const struct retro_keyboard_callback*)data; + + rarch_ctl(RARCH_CTL_FRONTEND_KEY_EVENT_GET, &frontend_key_event); + rarch_ctl(RARCH_CTL_KEY_EVENT_GET, &key_event); + + RARCH_LOG("Environ SET_KEYBOARD_CALLBACK.\n"); + if (key_event) + *key_event = info->callback; + + if (frontend_key_event && key_event) + *frontend_key_event = *key_event; + break; + } + + case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: + RARCH_LOG("Environ SET_DISK_CONTROL_INTERFACE.\n"); + if (system) + system->disk_control_cb = + *(const struct retro_disk_control_callback*)data; + break; + + case RETRO_ENVIRONMENT_SET_HW_RENDER: + case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: + { + struct retro_hw_render_callback *cb = + (struct retro_hw_render_callback*)data; + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context_internal(); + + RARCH_LOG("Environ SET_HW_RENDER.\n"); + + if (!dynamic_request_hw_context( + cb->context_type, cb->version_minor, cb->version_major)) + return false; + + if (!dynamic_verify_hw_context( + cb->context_type, cb->version_minor, cb->version_major)) + return false; + +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE) + if (!gl_set_core_context(cb->context_type)) { } +#endif + + cb->get_current_framebuffer = video_driver_get_current_framebuffer; + cb->get_proc_address = video_driver_get_proc_address; + + /* Old ABI. Don't copy garbage. */ + if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) + { + memcpy(hwr, + cb, offsetof(struct retro_hw_render_callback, stencil)); + memset((uint8_t*)hwr + offsetof(struct retro_hw_render_callback, stencil), + 0, sizeof(*cb) - offsetof(struct retro_hw_render_callback, stencil)); + } + else + memcpy(hwr, cb, sizeof(*cb)); + break; + } + + case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: + { + bool state = *(const bool*)data; + RARCH_LOG("Environ SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no"); + + if (state) + content_set_does_not_need_content(); + else + content_unset_does_not_need_content(); + break; + } + + case RETRO_ENVIRONMENT_SET_SAVE_STATE_IN_BACKGROUND: + { + bool state = *(const bool*)data; + RARCH_LOG("Environ SET_SAVE_STATE_IN_BACKGROUND: %s.\n", state ? "yes" : "no"); + + set_save_state_in_background(state) ; + + break; + } + + case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: + { + const char **path = (const char**)data; +#ifdef HAVE_DYNAMIC + *path = path_get(RARCH_PATH_CORE); +#else + *path = NULL; +#endif + break; + } + + case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK: +#ifdef HAVE_THREADS + { + const struct retro_audio_callback *cb = (const struct retro_audio_callback*)data; + RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n"); +#ifdef HAVE_NETWORKING + if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) + return false; +#endif + if (recording_data) /* A/V sync is a must. */ + return false; + if (cb) + audio_callback = *cb; + } +#endif + break; + + case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK: + { + const struct retro_frame_time_callback *info = + (const struct retro_frame_time_callback*)data; + + RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n"); +#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; + break; + } + + case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE: + { + struct retro_rumble_interface *iface = + (struct retro_rumble_interface*)data; + + RARCH_LOG("Environ GET_RUMBLE_INTERFACE.\n"); + iface->set_rumble_state = input_driver_set_rumble_state; + break; + } + + case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: + { + uint64_t *mask = (uint64_t*)data; + + RARCH_LOG("Environ GET_INPUT_DEVICE_CAPABILITIES.\n"); + if (!current_input->get_capabilities || !current_input_data) + return false; + else + *mask = input_driver_get_capabilities(); + break; + } + + case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE: + { + struct retro_sensor_interface *iface = + (struct retro_sensor_interface*)data; + + RARCH_LOG("Environ GET_SENSOR_INTERFACE.\n"); + iface->set_sensor_state = input_sensor_set_state; + iface->get_sensor_input = input_sensor_get_input; + break; + } + case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE: + { + struct retro_camera_callback *cb = + (struct retro_camera_callback*)data; + + RARCH_LOG("Environ GET_CAMERA_INTERFACE.\n"); + cb->start = driver_camera_start; + cb->stop = driver_camera_stop; + + rarch_ctl(RARCH_CTL_CAMERA_SET_CB, cb); + + if (cb->caps != 0) + rarch_ctl(RARCH_CTL_CAMERA_SET_ACTIVE, NULL); + else + rarch_ctl(RARCH_CTL_CAMERA_UNSET_ACTIVE, NULL); + break; + } + + case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE: + { + struct retro_location_callback *cb = + (struct retro_location_callback*)data; + + RARCH_LOG("Environ GET_LOCATION_INTERFACE.\n"); + cb->start = driver_location_start; + cb->stop = driver_location_stop; + cb->get_position = driver_location_get_position; + cb->set_interval = driver_location_set_interval; + + if (system) + system->location_cb = *cb; + + rarch_ctl(RARCH_CTL_LOCATION_UNSET_ACTIVE, NULL); + break; + } + + case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: + { + struct retro_log_callback *cb = (struct retro_log_callback*)data; + + RARCH_LOG("Environ GET_LOG_INTERFACE.\n"); + cb->log = rarch_log_libretro; + break; + } + + case RETRO_ENVIRONMENT_GET_PERF_INTERFACE: + { + struct retro_perf_callback *cb = (struct retro_perf_callback*)data; + + RARCH_LOG("Environ GET_PERF_INTERFACE.\n"); + cb->get_time_usec = cpu_features_get_time_usec; + cb->get_cpu_features = cpu_features_get; + cb->get_perf_counter = cpu_features_get_perf_counter; + + cb->perf_register = performance_counter_register; + cb->perf_start = core_performance_counter_start; + cb->perf_stop = core_performance_counter_stop; + cb->perf_log = retro_perf_log; + break; + } + + case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY: + { + const char **dir = (const char**)data; + + *dir = *settings->paths.directory_core_assets ? + settings->paths.directory_core_assets : NULL; + RARCH_LOG("Environ CORE_ASSETS_DIRECTORY: \"%s\".\n", + settings->paths.directory_core_assets); + break; + } + + case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: + /** + * Update the system Audio/Video information. + * Will reinitialize audio/video drivers. + * Used by RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO. + **/ + { + const struct retro_system_av_info **info = (const struct retro_system_av_info**)&data; + if (info) + { + RARCH_LOG("Environ SET_SYSTEM_AV_INFO.\n"); + return driver_update_system_av_info(*info); + } + return false; + } + + case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: + { + unsigned i; + const struct retro_subsystem_info *info = + (const struct retro_subsystem_info*)data; + unsigned log_level = settings->uints.libretro_log_level; + + if (log_level == RETRO_LOG_DEBUG) + RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); + + for (i = 0; info[i].ident; i++) + { + unsigned j; + if (log_level != RETRO_LOG_DEBUG) + continue; + + RARCH_LOG("Special game type: %s\n", info[i].desc); + RARCH_LOG(" Ident: %s\n", info[i].ident); + RARCH_LOG(" ID: %u\n", info[i].id); + RARCH_LOG(" Content:\n"); + for (j = 0; j < info[i].num_roms; j++) + { + RARCH_LOG(" %s (%s)\n", + info[i].roms[j].desc, info[i].roms[j].required ? + "required" : "optional"); + } + } + + if (system) + { + struct retro_subsystem_info *info_ptr = NULL; + free(system->subsystem.data); + system->subsystem.data = NULL; + system->subsystem.size = 0; + + info_ptr = (struct retro_subsystem_info*) + malloc(i * sizeof(*info_ptr)); + + if (!info_ptr) + return false; + + system->subsystem.data = info_ptr; + + memcpy(system->subsystem.data, info, + i * sizeof(*system->subsystem.data)); + system->subsystem.size = i; + } + break; + } + + case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO: + { + unsigned i, j; + const struct retro_controller_info *info = + (const struct retro_controller_info*)data; + unsigned log_level = settings->uints.libretro_log_level; + + RARCH_LOG("Environ SET_CONTROLLER_INFO.\n"); + + for (i = 0; info[i].types; i++) + { + if (log_level != RETRO_LOG_DEBUG) + continue; + + RARCH_LOG("Controller port: %u\n", i + 1); + for (j = 0; j < info[i].num_types; j++) + RARCH_LOG(" %s (ID: %u)\n", info[i].types[j].desc, + info[i].types[j].id); + } + + if (system) + { + struct retro_controller_info *info_ptr = NULL; + + free(system->ports.data); + system->ports.data = NULL; + system->ports.size = 0; + + info_ptr = (struct retro_controller_info*)calloc(i, sizeof(*info_ptr)); + if (!info_ptr) + return false; + + system->ports.data = info_ptr; + memcpy(system->ports.data, info, + i * sizeof(*system->ports.data)); + system->ports.size = i; + } + break; + } + + case RETRO_ENVIRONMENT_SET_MEMORY_MAPS: + { + if (system) + { + unsigned i; + const struct retro_memory_map *mmaps = + (const struct retro_memory_map*)data; + rarch_memory_descriptor_t *descriptors = NULL; + + RARCH_LOG("Environ SET_MEMORY_MAPS.\n"); + free((void*)system->mmaps.descriptors); + system->mmaps.descriptors = 0; + system->mmaps.num_descriptors = 0; + descriptors = (rarch_memory_descriptor_t*) + calloc(mmaps->num_descriptors, + sizeof(*descriptors)); + + if (!descriptors) + return false; + + system->mmaps.descriptors = descriptors; + system->mmaps.num_descriptors = mmaps->num_descriptors; + + for (i = 0; i < mmaps->num_descriptors; i++) + system->mmaps.descriptors[i].core = mmaps->descriptors[i]; + + mmap_preprocess_descriptors(descriptors, mmaps->num_descriptors); + + if (sizeof(void *) == 8) + RARCH_LOG(" ndx flags ptr offset start select disconn len addrspace\n"); + else + RARCH_LOG(" ndx flags ptr offset start select disconn len addrspace\n"); + + for (i = 0; i < system->mmaps.num_descriptors; i++) + { + const rarch_memory_descriptor_t *desc = + &system->mmaps.descriptors[i]; + char flags[7]; + + flags[0] = 'M'; + if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_8) == RETRO_MEMDESC_MINSIZE_8) + flags[1] = '8'; + else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_4) == RETRO_MEMDESC_MINSIZE_4) + flags[1] = '4'; + else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_2) == RETRO_MEMDESC_MINSIZE_2) + flags[1] = '2'; + else + flags[1] = '1'; + + flags[2] = 'A'; + if ((desc->core.flags & RETRO_MEMDESC_ALIGN_8) == RETRO_MEMDESC_ALIGN_8) + flags[3] = '8'; + else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_4) == RETRO_MEMDESC_ALIGN_4) + flags[3] = '4'; + else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_2) == RETRO_MEMDESC_ALIGN_2) + flags[3] = '2'; + else + flags[3] = '1'; + + flags[4] = (desc->core.flags & RETRO_MEMDESC_BIGENDIAN) ? 'B' : 'b'; + flags[5] = (desc->core.flags & RETRO_MEMDESC_CONST) ? 'C' : 'c'; + flags[6] = 0; + + RARCH_LOG(" %03u %s %p %08X %08X %08X %08X %08X %s\n", + i + 1, flags, desc->core.ptr, desc->core.offset, desc->core.start, + desc->core.select, desc->core.disconnect, desc->core.len, + desc->core.addrspace ? desc->core.addrspace : ""); + } + } + else + { + RARCH_WARN("Environ SET_MEMORY_MAPS, but system pointer not initialized..\n"); + } + + break; + } + + case RETRO_ENVIRONMENT_SET_GEOMETRY: + { + const struct retro_game_geometry *in_geom = NULL; + struct retro_system_av_info *av_info = &video_driver_av_info; + struct retro_game_geometry *geom = (struct retro_game_geometry*)&av_info->geometry; + + if (!geom) + return false; + + in_geom = (const struct retro_game_geometry*)data; + + RARCH_LOG("Environ SET_GEOMETRY.\n"); + + /* Can potentially be called every frame, + * don't do anything unless required. */ + if ( (geom->base_width != in_geom->base_width) || + (geom->base_height != in_geom->base_height) || + (geom->aspect_ratio != in_geom->aspect_ratio)) + { + geom->base_width = in_geom->base_width; + geom->base_height = in_geom->base_height; + geom->aspect_ratio = in_geom->aspect_ratio; + + RARCH_LOG("SET_GEOMETRY: %ux%u, aspect: %.3f.\n", + geom->base_width, geom->base_height, geom->aspect_ratio); + + /* Forces recomputation of aspect ratios if + * using core-dependent aspect ratios. */ + command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL); + + /* TODO: Figure out what to do, if anything, with recording. */ + } + break; + } + + case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER: + return video_driver_get_current_software_framebuffer( + (struct retro_framebuffer*)data); + + case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE: + return video_driver_get_hw_render_interface( + (const struct retro_hw_render_interface**)data); + + case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS: +#ifdef HAVE_CHEEVOS + { + bool state = *(const bool*)data; + RARCH_LOG("Environ SET_SUPPORT_ACHIEVEMENTS: %s.\n", state ? "yes" : "no"); + rcheevos_set_support_cheevos(state); + } +#endif + break; + + case RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE: + { + const struct retro_hw_render_context_negotiation_interface *iface = + (const struct retro_hw_render_context_negotiation_interface*)data; + RARCH_LOG("Environ SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE.\n"); + video_driver_set_context_negotiation_interface(iface); + break; + } + + case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: + { + uint64_t *quirks = (uint64_t *) data; + core_set_serialization_quirks(*quirks); + break; + } + + case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT: + core_set_shared_context = true; + break; + + case RETRO_ENVIRONMENT_GET_VFS_INTERFACE: + { + const uint32_t supported_vfs_version = 3; + static struct retro_vfs_interface vfs_iface = + { + /* VFS API v1 */ + retro_vfs_file_get_path_impl, + retro_vfs_file_open_impl, + retro_vfs_file_close_impl, + retro_vfs_file_size_impl, + retro_vfs_file_tell_impl, + retro_vfs_file_seek_impl, + retro_vfs_file_read_impl, + retro_vfs_file_write_impl, + retro_vfs_file_flush_impl, + retro_vfs_file_remove_impl, + retro_vfs_file_rename_impl, + /* VFS API v2 */ + retro_vfs_file_truncate_impl, + /* VFS API v3 */ + retro_vfs_stat_impl, + retro_vfs_mkdir_impl, + retro_vfs_opendir_impl, + retro_vfs_readdir_impl, + retro_vfs_dirent_get_name_impl, + retro_vfs_dirent_is_dir_impl, + retro_vfs_closedir_impl + }; + + struct retro_vfs_interface_info *vfs_iface_info = (struct retro_vfs_interface_info *) data; + if (vfs_iface_info->required_interface_version <= supported_vfs_version) + { + RARCH_LOG("Core requested VFS version >= v%d, providing v%d\n", vfs_iface_info->required_interface_version, supported_vfs_version); + vfs_iface_info->required_interface_version = supported_vfs_version; + vfs_iface_info->iface = &vfs_iface; + system->supports_vfs = true; + } + else + { + RARCH_WARN("Core requested VFS version v%d which is higher than what we support (v%d)\n", vfs_iface_info->required_interface_version, supported_vfs_version); + return false; + } + + break; + } + + case RETRO_ENVIRONMENT_GET_LED_INTERFACE: + { + struct retro_led_interface *ledintf = + (struct retro_led_interface *)data; + if (ledintf) + ledintf->set_led_state = led_driver_set_led; + } + break; + + case RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE: + { + int result = 0; + if (!audio_suspended && audio_driver_active) + result |= 2; + if (video_driver_active && !(current_video->frame == video_null.frame)) + result |= 1; +#ifdef HAVE_RUNAHEAD + if (request_fast_savestate) + result |= 4; + if (hard_disable_audio) + result |= 8; +#endif +#ifdef HAVE_NETWORKING + if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_REPLAYING, NULL)) + result &= ~(1|2); + if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) + result |= 4; +#endif + if (data != NULL) + { + int* result_p = (int*)data; + *result_p = result; + } + break; + } + + case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE: + { + struct retro_midi_interface *midi_interface = + (struct retro_midi_interface *)data; + + if (midi_interface) + { + midi_interface->input_enabled = midi_driver_input_enabled; + midi_interface->output_enabled = midi_driver_output_enabled; + midi_interface->read = midi_driver_read; + midi_interface->write = midi_driver_write; + midi_interface->flush = midi_driver_flush; + } + break; + } + + case RETRO_ENVIRONMENT_GET_FASTFORWARDING: + *(bool *)data = runloop_fastmotion; + break; + + case RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB: + *(retro_environment_t *)data = rarch_clear_all_thread_waits; + break; + + case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS: + /* Just falldown, the function will return true */ + break; + + case RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE: + { + /* Try to use the polled refresh rate first. */ + float target_refresh_rate = video_driver_get_refresh_rate(); + + /* If the above function failed [possibly because it is not + * implemented], use the refresh rate set in the config instead. */ + if (target_refresh_rate == 0.0 && settings) + target_refresh_rate = settings->floats.video_refresh_rate; + + *(float *)data = target_refresh_rate; + break; + } + + default: + RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); + return false; + } + + return true; +} + +#ifdef HAVE_DYNAMIC +/** + * libretro_get_environment_info: + * @func : Function pointer for get_environment_info. + * @load_no_content : If true, core should be able to auto-start + * without any content loaded. + * + * Sets environment callback in order to get statically known + * information from it. + * + * Fetched via environment callbacks instead of + * retro_get_system_info(), as this info is part of extensions. + * + * Should only be called once right after core load to + * avoid overwriting the "real" environ callback. + * + * For statically linked cores, pass retro_set_environment as argument. + */ +static void libretro_get_environment_info(void (*func)(retro_environment_t), + bool *load_no_content) +{ + load_no_content_hook = load_no_content; + + /* load_no_content gets set in this callback. */ + func(environ_cb_get_system_info); + + /* It's possible that we just set get_system_info callback + * to the currently running core. + * + * Make sure we reset it to the actual environment callback. + * Ignore any environment callbacks here in case we're running + * on the non-current core. */ + ignore_environment_cb = true; + func(rarch_environment_cb); + ignore_environment_cb = false; +} + +static bool load_dynamic_core(const char *path, char *buf, size_t size) +{ + /* Can't lookup symbols in itself on UWP */ +#if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + if (dylib_proc(NULL, "retro_init")) + { + /* Try to verify that -lretro was not linked in from other modules + * since loading it dynamically and with -l will fail hard. */ + RARCH_ERR("Serious problem. RetroArch wants to load libretro cores" + " dynamically, but it is already linked.\n"); + RARCH_ERR("This could happen if other modules RetroArch depends on " + "link against libretro directly.\n"); + RARCH_ERR("Proceeding could cause a crash. Aborting ...\n"); + retroarch_fail(1, "init_libretro_symbols()"); + } +#endif + + /* Need to use absolute path for this setting. It can be + * saved to content history, and a relative path would + * break in that scenario. */ + path_resolve_realpath(buf, size); + if ((lib_handle = dylib_load(path))) + return true; + return false; +} + +static dylib_t libretro_get_system_info_lib(const char *path, + struct retro_system_info *info, bool *load_no_content) +{ + dylib_t lib = dylib_load(path); + void (*proc)(struct retro_system_info*); + + if (!lib) + return NULL; + + proc = (void (*)(struct retro_system_info*)) + dylib_proc(lib, "retro_get_system_info"); + + if (!proc) + { + dylib_close(lib); + return NULL; + } + + proc(info); + + if (load_no_content) + { + void (*set_environ)(retro_environment_t); + *load_no_content = false; + set_environ = (void (*)(retro_environment_t)) + dylib_proc(lib, "retro_set_environment"); + + if (set_environ) + libretro_get_environment_info(set_environ, load_no_content); + } + + return lib; +} +#endif + +static char current_library_name[1024]; +static char current_library_version[1024]; +static char current_valid_extensions[1024]; + +/** + * libretro_get_system_info: + * @path : Path to libretro library. + * @info : Pointer to system info information. + * @load_no_content : If true, core should be able to auto-start + * without any content loaded. + * + * Gets system info from an arbitrary lib. + * The struct returned must be freed as strings are allocated dynamically. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool libretro_get_system_info(const char *path, + struct retro_system_info *info, bool *load_no_content) +{ + struct retro_system_info dummy_info; +#ifdef HAVE_DYNAMIC + dylib_t lib; +#endif + + dummy_info.library_name = NULL; + dummy_info.library_version = NULL; + dummy_info.valid_extensions = NULL; + dummy_info.need_fullpath = false; + dummy_info.block_extract = false; + +#ifdef HAVE_DYNAMIC + lib = libretro_get_system_info_lib( + path, &dummy_info, load_no_content); + + if (!lib) + { + RARCH_ERR("%s: \"%s\"\n", + msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), + path); + RARCH_ERR("Error(s): %s\n", dylib_error()); + return false; + } +#else + if (load_no_content) + { + load_no_content_hook = load_no_content; + + /* load_no_content gets set in this callback. */ + retro_set_environment(environ_cb_get_system_info); + + /* It's possible that we just set get_system_info callback + * to the currently running core. + * + * Make sure we reset it to the actual environment callback. + * Ignore any environment callbacks here in case we're running + * on the non-current core. */ + ignore_environment_cb = true; + retro_set_environment(rarch_environment_cb); + ignore_environment_cb = false; + } + + retro_get_system_info(&dummy_info); +#endif + + memcpy(info, &dummy_info, sizeof(*info)); + + current_library_name[0] = '\0'; + current_library_version[0] = '\0'; + current_valid_extensions[0] = '\0'; + + if (!string_is_empty(dummy_info.library_name)) + strlcpy(current_library_name, + dummy_info.library_name, sizeof(current_library_name)); + if (!string_is_empty(dummy_info.library_version)) + strlcpy(current_library_version, + dummy_info.library_version, sizeof(current_library_version)); + if (dummy_info.valid_extensions) + strlcpy(current_valid_extensions, + dummy_info.valid_extensions, sizeof(current_valid_extensions)); + + info->library_name = current_library_name; + info->library_version = current_library_version; + info->valid_extensions = current_valid_extensions; + +#ifdef HAVE_DYNAMIC + dylib_close(lib); +#endif + return true; +} + +/** + * load_symbols: + * @type : Type of core to be loaded. + * If CORE_TYPE_DUMMY, will + * load dummy symbols. + * + * Setup libretro callback symbols. Returns true on success, + * or false if symbols could not be loaded. + **/ +static bool init_libretro_symbols_custom(enum rarch_core_type type, + struct retro_core_t *current_core, const char *lib_path, void *_lib_handle_p) +{ +#ifdef HAVE_DYNAMIC + /* the library handle for use with the SYMBOL macro */ + dylib_t lib_handle_local; +#endif + + switch (type) + { + case CORE_TYPE_PLAIN: + { +#ifdef HAVE_DYNAMIC +#ifdef HAVE_RUNAHEAD + dylib_t *lib_handle_p = (dylib_t*)_lib_handle_p; + if (!lib_path || !lib_handle_p) +#endif + { + const char *path = path_get(RARCH_PATH_CORE); + + if (string_is_empty(path)) + { + RARCH_ERR("Frontend is built for dynamic libretro cores, but " + "path is not set. Cannot continue.\n"); + retroarch_fail(1, "init_libretro_symbols()"); + } + + RARCH_LOG("Loading dynamic libretro core from: \"%s\"\n", + path); + + if (!load_dynamic_core( + path, + path_get_ptr(RARCH_PATH_CORE), + path_get_realsize(RARCH_PATH_CORE) + )) + { + RARCH_ERR("Failed to open libretro core: \"%s\"\n", path); + RARCH_ERR("Error(s): %s\n", dylib_error()); + runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), + 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + return false; + } + lib_handle_local = lib_handle; + } +#ifdef HAVE_RUNAHEAD + else + { + /* for a secondary core, we already have a + * primary library loaded, so we can skip + * some checks and just load the library */ + retro_assert(lib_path != NULL && lib_handle_p != NULL); + lib_handle_local = dylib_load(lib_path); + + if (!lib_handle_local) + return false; + *lib_handle_p = lib_handle_local; + } +#endif +#endif + + CORE_SYMBOLS(SYMBOL); + } + break; + case CORE_TYPE_DUMMY: + CORE_SYMBOLS(SYMBOL_DUMMY); + break; + case CORE_TYPE_FFMPEG: +#ifdef HAVE_FFMPEG + CORE_SYMBOLS(SYMBOL_FFMPEG); +#endif + break; + case CORE_TYPE_MPV: +#ifdef HAVE_MPV + CORE_SYMBOLS(SYMBOL_MPV); +#endif + break; + case CORE_TYPE_IMAGEVIEWER: +#ifdef HAVE_IMAGEVIEWER + CORE_SYMBOLS(SYMBOL_IMAGEVIEWER); +#endif + break; + case CORE_TYPE_NETRETROPAD: +#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD) + CORE_SYMBOLS(SYMBOL_NETRETROPAD); +#endif + break; + case CORE_TYPE_VIDEO_PROCESSOR: +#if defined(HAVE_VIDEOPROCESSOR) + CORE_SYMBOLS(SYMBOL_VIDEOPROCESSOR); +#endif + break; + case CORE_TYPE_GONG: +#ifdef HAVE_EASTEREGG + CORE_SYMBOLS(SYMBOL_GONG); +#endif + break; + } + + return true; +} + +/** + * init_libretro_symbols: + * @type : Type of core to be loaded. + * If CORE_TYPE_DUMMY, will + * load dummy symbols. + * + * Initializes libretro symbols and + * setups environment callback functions. Returns true on success, + * or false if symbols could not be loaded. + **/ +static bool init_libretro_symbols(enum rarch_core_type type, struct retro_core_t *current_core) +{ + /* Load symbols */ + if (!init_libretro_symbols_custom(type, current_core, NULL, NULL)) + return false; + +#ifdef HAVE_RUNAHEAD + /* remember last core type created, so creating a + * secondary core will know what core type to use. */ + set_last_core_type(type); +#endif + return true; +} + +bool libretro_get_shared_context(void) +{ + return core_set_shared_context; +} + +/** + * uninit_libretro_sym: + * + * Frees libretro core. + * + * Frees all core options, + * associated state, and + * unbind all libretro callback symbols. + **/ +static void uninit_libretro_symbols(struct retro_core_t *current_core) +{ +#ifdef HAVE_DYNAMIC + if (lib_handle) + dylib_close(lib_handle); + lib_handle = NULL; +#endif + + memset(current_core, 0, sizeof(struct retro_core_t)); + + core_set_shared_context = false; + + rarch_ctl(RARCH_CTL_CORE_OPTIONS_DEINIT, NULL); + rarch_ctl(RARCH_CTL_SYSTEM_INFO_FREE, NULL); + rarch_ctl(RARCH_CTL_FRAME_TIME_FREE, NULL); + rarch_ctl(RARCH_CTL_CAMERA_UNSET_ACTIVE, NULL); + rarch_ctl(RARCH_CTL_LOCATION_UNSET_ACTIVE, NULL); + + /* Performance counters no longer valid. */ + performance_counters_clear(); +} #if defined(HAVE_RUNAHEAD) /* RUNAHEAD - SECONDARY CORE */ @@ -1701,11 +3839,6 @@ static void clear_controller_port_map(void) port_map[port] = -1; } -static void secondary_core_set_variable_update(void) -{ - has_variable_update = true; -} - static char *get_temp_directory_alloc(void) { char *path = NULL; @@ -1912,14 +4045,16 @@ static bool secondary_core_create(void) return false; /* Load Core */ - if (init_libretro_sym_custom( + if (init_libretro_symbols_custom( CORE_TYPE_PLAIN, &secondary_core, secondary_library_path, &secondary_module)) { secondary_core.symbols_inited = true; secondary_core.retro_set_environment( rarch_environment_secondary_core_hook); - secondary_core_set_variable_update(); +#ifdef HAVE_RUNAHEAD + has_variable_update = true; +#endif secondary_core.retro_init(); @@ -2034,10 +4169,6 @@ static void remember_controller_port_device(long port, long device) { } -static void secondary_core_set_variable_update(void) -{ -} - static void clear_controller_port_map(void) { } @@ -2045,298 +4176,6 @@ static void clear_controller_port_map(void) #endif -/* CORE OPTIONS */ -static bool core_option_manager_parse_variable( - core_option_manager_t *opt, size_t idx, - const struct retro_variable *var) -{ - const char *val_start = NULL; - char *value = NULL; - char *desc_end = NULL; - char *config_val = NULL; - struct core_option *option = (struct core_option*)&opt->opts[idx]; - - if (!string_is_empty(var->key)) - option->key = strdup(var->key); - if (!string_is_empty(var->value)) - value = strdup(var->value); - - if (!string_is_empty(value)) - desc_end = strstr(value, "; "); - - if (!desc_end) - goto error; - - *desc_end = '\0'; - - if (!string_is_empty(value)) - option->desc = strdup(value); - - val_start = desc_end + 2; - option->vals = string_split(val_start, "|"); - - if (!option->vals) - goto error; - - if (config_get_string(opt->conf, option->key, &config_val)) - { - size_t i; - - for (i = 0; i < option->vals->size; i++) - { - if (string_is_equal(option->vals->elems[i].data, config_val)) - { - option->index = i; - break; - } - } - - free(config_val); - } - - free(value); - - return true; - -error: - free(value); - return false; -} - -/** - * core_option_manager_free: - * @opt : options manager handle - * - * Frees core option manager handle. - **/ -static void core_option_manager_free(core_option_manager_t *opt) -{ - size_t i; - - if (!opt) - return; - - for (i = 0; i < opt->size; i++) - { - if (opt->opts[i].desc) - free(opt->opts[i].desc); - if (opt->opts[i].key) - free(opt->opts[i].key); - - if (opt->opts[i].vals) - string_list_free(opt->opts[i].vals); - - opt->opts[i].desc = NULL; - opt->opts[i].key = NULL; - opt->opts[i].vals = NULL; - } - - if (opt->conf) - config_file_free(opt->conf); - free(opt->opts); - free(opt); -} - -static void core_option_manager_get(core_option_manager_t *opt, - struct retro_variable *var) -{ - size_t i; - -#ifdef HAVE_RUNAHEAD - if (opt->updated) - secondary_core_set_variable_update(); -#endif - - opt->updated = false; - - for (i = 0; i < opt->size; i++) - { - if (string_is_empty(opt->opts[i].key)) - continue; - - if (string_is_equal(opt->opts[i].key, var->key)) - { - var->value = opt->opts[i].vals->elems[opt->opts[i].index].data; - return; - } - } - - var->value = NULL; -} - -/** - * core_option_manager_new: - * @conf_path : Filesystem path to write core option config file to. - * @vars : Pointer to variable array handle. - * - * Creates and initializes a core manager handle. - * - * Returns: handle to new core manager handle, otherwise NULL. - **/ -static core_option_manager_t *core_option_manager_new(const char *conf_path, - const struct retro_variable *vars) -{ - const struct retro_variable *var; - size_t size = 0; - core_option_manager_t *opt = (core_option_manager_t*) - calloc(1, sizeof(*opt)); - - if (!opt) - return NULL; - - if (!string_is_empty(conf_path)) - opt->conf = config_file_new(conf_path); - if (!opt->conf) - opt->conf = config_file_new(NULL); - - strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path)); - - if (!opt->conf) - goto error; - - for (var = vars; var->key && var->value; var++) - size++; - - if (size == 0) - goto error; - - opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts)); - if (!opt->opts) - goto error; - - opt->size = size; - size = 0; - - for (var = vars; var->key && var->value; size++, var++) - { - if (!core_option_manager_parse_variable(opt, size, var)) - goto error; - } - - return opt; - -error: - core_option_manager_free(opt); - return NULL; -} - -/** - * core_option_manager_flush: - * @opt : options manager handle - * - * Writes core option key-pair values to file. - * - * Returns: true (1) if core option values could be - * successfully saved to disk, otherwise false (0). - **/ -static bool core_option_manager_flush(core_option_manager_t *opt) -{ - size_t i; - - for (i = 0; i < opt->size; i++) - { - struct core_option *option = (struct core_option*)&opt->opts[i]; - - if (option) - config_set_string(opt->conf, option->key, - opt->opts[i].vals->elems[opt->opts[i].index].data); - } - - RARCH_LOG("Saved core options file to \"%s\"\n", opt->conf_path); - return config_file_write(opt->conf, opt->conf_path, true); -} - -/** - * core_option_manager_flush_game_specific: - * @opt : options manager handle - * @path : path for the core options file - * - * Writes core option key-pair values to a custom file. - * - * Returns: true (1) if core option values could be - * successfully saved to disk, otherwise false (0). - **/ -static bool core_option_manager_flush_game_specific( - core_option_manager_t *opt, const char* path) -{ - size_t i; - for (i = 0; i < opt->size; i++) - { - struct core_option *option = (struct core_option*)&opt->opts[i]; - - if (option) - config_set_string(opt->conf, option->key, - opt->opts[i].vals->elems[opt->opts[i].index].data); - } - - return config_file_write(opt->conf, path, true); -} - -/** - * core_option_manager_get_desc: - * @opt : options manager handle - * @index : index identifier of the option - * - * Gets description for an option. - * - * Returns: Description for an option. - **/ -const char *core_option_manager_get_desc( - core_option_manager_t *opt, size_t idx) -{ - if (!opt) - return NULL; - return opt->opts[idx].desc; -} - -/** - * core_option_manager_get_val: - * @opt : options manager handle - * @index : index identifier of the option - * - * Gets value for an option. - * - * Returns: Value for an option. - **/ -const char *core_option_manager_get_val(core_option_manager_t *opt, size_t idx) -{ - struct core_option *option = NULL; - if (!opt) - return NULL; - option = (struct core_option*)&opt->opts[idx]; - return option->vals->elems[option->index].data; -} - -void core_option_manager_set_val(core_option_manager_t *opt, - size_t idx, size_t val_idx) -{ - struct core_option *option= NULL; - - if (!opt) - return; - - option = (struct core_option*)&opt->opts[idx]; - option->index = val_idx % option->vals->size; - - opt->updated = true; -} - -/** - * core_option_manager_set_default: - * @opt : pointer to core option manager object. - * @idx : index of core option to be reset to defaults. - * - * Reset core option specified by @idx and sets default value for option. - **/ -void core_option_manager_set_default(core_option_manager_t *opt, size_t idx) -{ - if (!opt) - return; - - opt->opts[idx].index = 0; - opt->updated = true; -} - /* MESSAGE QUEUE */ static void retroarch_msg_queue_deinit(void) { @@ -3264,11 +5103,6 @@ bool recording_init(void) return true; } -void *recording_driver_get_data_ptr(void) -{ - return recording_data; -} - void recording_driver_update_streaming_url(void) { settings_t *settings = configuration_settings; @@ -4839,7 +6673,7 @@ float input_sensor_get_input(unsigned port, unsigned id) * * Input polling callback function. **/ -static void input_poll(void) +static void input_driver_poll(void) { size_t i; settings_t *settings = configuration_settings; @@ -5268,7 +7102,7 @@ static int16_t input_state_device( * Returns: Non-zero if the given key (identified by @id) * was pressed by the user (assigned to @port). **/ -int16_t input_state(unsigned port, unsigned device, +static int16_t input_state(unsigned port, unsigned device, unsigned idx, unsigned id) { rarch_joypad_info_t joypad_info; @@ -6611,18 +8445,6 @@ void *input_driver_get_data(void) return current_input_data; } -void **input_driver_get_data_ptr(void) -{ - return (void**)¤t_input_data; -} - -bool input_driver_has_capabilities(void) -{ - if (!current_input->get_capabilities || !current_input_data) - return false; - return true; -} - static bool input_driver_init(void) { if (current_input) @@ -10361,16 +12183,6 @@ void audio_driver_mixer_remove_stream(unsigned i) } } -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) @@ -10497,16 +12309,6 @@ void audio_driver_frame_is_reverse(void) runloop_slowmotion); } -bool audio_driver_is_suspended(void) -{ - return audio_suspended; -} - -bool audio_driver_is_active(void) -{ - return audio_driver_active; -} - static void audio_driver_destroy(void) { audio_driver_active = false; @@ -11000,13 +12802,6 @@ static void video_driver_free_internal(void) video_driver_monitor_compute_fps_statistics(); } -#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(); -} - static bool video_driver_pixel_converter_init(unsigned size) { struct retro_hw_render_callback *hwr = @@ -11189,7 +12984,7 @@ static bool video_driver_init_internal(bool *video_is_threaded) if (!video_init_thread((const video_driver_t**)¤t_video, &video_driver_data, - ¤t_input, input_driver_get_data_ptr(), + ¤t_input, (void**)¤t_input_data, current_video, video)) { RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n"); @@ -11200,7 +12995,7 @@ static bool video_driver_init_internal(bool *video_is_threaded) #endif video_driver_data = current_video->init( &video, ¤t_input, - input_driver_get_data_ptr()); + (void**)¤t_input_data); if (!video_driver_data) { @@ -11647,11 +13442,6 @@ void video_driver_unset_stub_frame(void) frame_bak = NULL; } -bool video_driver_is_stub_frame(void) -{ - return current_video->frame == video_null.frame; -} - bool video_driver_supports_viewport_read(void) { return current_video->read_viewport && current_video->viewport_info; @@ -12181,11 +13971,6 @@ bool video_driver_is_video_cache_context_ack(void) return video_driver_cache_context_ack; } -bool video_driver_is_active(void) -{ - return video_driver_active; -} - bool video_driver_get_current_software_framebuffer( struct retro_framebuffer *fb) { @@ -13296,28 +15081,28 @@ enum gfx_ctx_api video_context_driver_get_api(void) if (ctx_api == GFX_CTX_NONE) { - const char *video_driver = video_driver_get_ident(); - if (string_is_equal(video_driver, "d3d9")) + const char *video_ident = (current_video) ? current_video->ident : NULL; + if (string_is_equal(video_ident, "d3d9")) return GFX_CTX_DIRECT3D9_API; - else if (string_is_equal(video_driver, "d3d10")) + else if (string_is_equal(video_ident, "d3d10")) return GFX_CTX_DIRECT3D10_API; - else if (string_is_equal(video_driver, "d3d11")) + else if (string_is_equal(video_ident, "d3d11")) return GFX_CTX_DIRECT3D11_API; - else if (string_is_equal(video_driver, "d3d12")) + else if (string_is_equal(video_ident, "d3d12")) return GFX_CTX_DIRECT3D12_API; - else if (string_is_equal(video_driver, "gx2")) + else if (string_is_equal(video_ident, "gx2")) return GFX_CTX_GX2_API; - else if (string_is_equal(video_driver, "gx")) + else if (string_is_equal(video_ident, "gx")) return GFX_CTX_GX_API; - else if (string_is_equal(video_driver, "gl")) + else if (string_is_equal(video_ident, "gl")) return GFX_CTX_OPENGL_API; - else if (string_is_equal(video_driver, "gl1")) + else if (string_is_equal(video_ident, "gl1")) return GFX_CTX_OPENGL_API; - else if (string_is_equal(video_driver, "glcore")) + else if (string_is_equal(video_ident, "glcore")) return GFX_CTX_OPENGL_API; - else if (string_is_equal(video_driver, "vulkan")) + else if (string_is_equal(video_ident, "vulkan")) return GFX_CTX_VULKAN_API; - else if (string_is_equal(video_driver, "metal")) + else if (string_is_equal(video_ident, "metal")) return GFX_CTX_METAL_API; return GFX_CTX_NONE; @@ -13948,7 +15733,7 @@ void driver_set_nonblock_state(void) bool enable = input_driver_nonblock_state; /* Only apply non-block-state for video if we're using vsync. */ - if (video_driver_is_active() && video_driver_get_ptr_internal(false)) + if (video_driver_active && video_driver_get_ptr_internal(false)) { settings_t *settings = configuration_settings; bool video_nonblock = enable; @@ -14284,13 +16069,6 @@ bool driver_ctl(enum driver_ctl_state state, void *data) 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; @@ -14674,7 +16452,7 @@ static bool runahead_create(void) request_fast_savestate = false; runahead_save_state_list_init(info.size); - runahead_video_driver_is_active = video_driver_is_active(); + runahead_video_driver_is_active = video_driver_active; if (runahead_save_state_size == 0 || !runahead_save_state_size_known) { @@ -14791,7 +16569,7 @@ static bool runahead_core_run_use_last_input(void) return true; } -static void run_ahead(int runahead_count, bool use_secondary) +static void do_runahead(int runahead_count, bool use_secondary) { int frame_number = 0; bool last_frame = false; @@ -14805,9 +16583,7 @@ static void run_ahead(int runahead_count, bool use_secondary) if (runahead_count <= 0 || !runahead_available) { - core_run(); - runahead_force_input_dirty = true; - return; + goto force_input_dirty; } if (!runahead_save_state_size_known) @@ -14817,9 +16593,7 @@ static void run_ahead(int runahead_count, bool use_secondary) settings_t *settings = configuration_settings; if (!settings->bools.run_ahead_hide_warnings) runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES), 0, 2 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - core_run(); - runahead_force_input_dirty = true; - return; + goto force_input_dirty; } } @@ -14882,9 +16656,7 @@ static void run_ahead(int runahead_count, bool use_secondary) { runahead_secondary_core_available = false; runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - core_run(); - runahead_force_input_dirty = true; - return; + goto force_input_dirty; } /* run main core with video suspended */ @@ -14927,18 +16699,12 @@ static void run_ahead(int runahead_count, bool use_secondary) #endif } runahead_force_input_dirty = false; -} + return; -bool want_fast_savestate(void) -{ - return request_fast_savestate; +force_input_dirty: + core_run(); + runahead_force_input_dirty = true; } - -bool get_hard_disable_audio(void) -{ - return hard_disable_audio; -} - #endif void rarch_core_runtime_tick(void) @@ -15041,7 +16807,7 @@ static void global_free(void) runloop_remaps_game_active = false; runloop_remaps_content_dir_active = false; - core_unset_input_descriptors(); + current_core.has_set_input_descriptors = false; global = &g_extern; path_clear_all(); @@ -15488,7 +17254,7 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) /* Flush out some states that could have been set * by core environment variables. */ - core_unset_input_descriptors(); + current_core.has_set_input_descriptors = false; /* Load the config file now that we know what it is */ if (!rarch_block_config_read) @@ -16663,19 +18429,6 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) break; 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; - } - break; case RARCH_CTL_GET_WINDOWED_SCALE: { unsigned **scale = (unsigned**)data; @@ -16753,10 +18506,6 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) case RARCH_CTL_DATA_DEINIT: task_queue_deinit(); break; - case RARCH_CTL_IS_CORE_OPTION_UPDATED: - if (!runloop_core_options) - return false; - return runloop_core_options->updated; case RARCH_CTL_CORE_OPTION_PREV: /* * Get previous value for core option specified by @idx. @@ -16802,27 +18551,6 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) } } break; - case RARCH_CTL_CORE_OPTIONS_GET: - { - settings_t *settings = configuration_settings; - unsigned log_level = settings->uints.libretro_log_level; - - struct retro_variable *var = (struct retro_variable*)data; - - if (!runloop_core_options || !var) - return false; - - if (runloop_core_options) - core_option_manager_get(runloop_core_options, var); - - 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)); - } - } - break; case RARCH_CTL_CORE_OPTIONS_INIT: { settings_t *settings = configuration_settings; @@ -18570,24 +20298,25 @@ int runloop_iterate(unsigned *sleep_ms) if ((video_frame_delay > 0) && !input_nonblock_state) retro_sleep(video_frame_delay); -#ifdef HAVE_RUNAHEAD { - unsigned run_ahead_num_frames = settings->uints.run_ahead_frames; + bool want_runahead = false; + unsigned run_ahead_num_frames = 0; +#ifdef HAVE_RUNAHEAD + 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 + want_runahead = settings->bools.run_ahead_enabled && run_ahead_num_frames > 0; #ifdef HAVE_NETWORKING - && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) + want_runahead = want_runahead && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL); #endif - ) - run_ahead(run_ahead_num_frames, settings->bools.run_ahead_secondary_instance); +#endif + +#ifdef HAVE_RUNAHEAD + if (want_runahead) + do_runahead(run_ahead_num_frames, settings->bools.run_ahead_secondary_instance); else +#endif core_run(); } -#else - { - core_run(); - } -#endif /* Increment runtime tick counter after each call to * core_run() or run_ahead() */ @@ -19609,7 +21338,7 @@ static void retro_input_poll_null(void) static void core_input_state_poll_maybe(void) { if (current_core.poll_type == POLL_TYPE_NORMAL) - input_poll(); + input_driver_poll(); } static int16_t core_input_state_poll(unsigned port, @@ -19618,18 +21347,13 @@ static int16_t core_input_state_poll(unsigned port, if (current_core.poll_type == POLL_TYPE_LATE) { if (!current_core.input_polled) - input_poll(); + input_driver_poll(); current_core.input_polled = true; } return input_state(port, device, idx, id); } -void core_set_input_state(retro_ctx_input_state_info_t *info) -{ - current_core.retro_set_input_state(info->cb); -} - /** * core_init_libretro_cbs: * @data : pointer to retro_callbacks object @@ -19669,15 +21393,14 @@ bool core_set_default_callbacks(struct retro_callbacks *cbs) cbs->sample_cb = audio_driver_sample; cbs->sample_batch_cb = audio_driver_sample_batch; cbs->state_cb = core_input_state_poll; - cbs->poll_cb = input_poll; + cbs->poll_cb = input_driver_poll; return true; } -bool core_deinit(void *data) +static bool core_uninit_libretro_callbacks(void) { - struct retro_callbacks *cbs = (struct retro_callbacks*)data; - + struct retro_callbacks *cbs = (struct retro_callbacks*)&retro_ctx; if (!cbs) return false; @@ -19692,11 +21415,6 @@ bool core_deinit(void *data) return true; } -bool core_uninit_libretro_callbacks(void) -{ - return core_deinit(&retro_ctx); -} - /** * core_set_rewind_callbacks: * @@ -19788,13 +21506,13 @@ bool core_set_poll_type(unsigned *type) void core_uninit_symbols(void) { - uninit_libretro_sym(¤t_core); + uninit_libretro_symbols(¤t_core); current_core.symbols_inited = false; } bool core_init_symbols(enum rarch_core_type *type) { - if (!type || !init_libretro_sym(*type, ¤t_core)) + if (!type || !init_libretro_symbols(*type, ¤t_core)) return false; if (!current_core.retro_run) @@ -19970,21 +21688,21 @@ bool core_run(void) { /* Paused due to netplay. We must poll and display something so that a * netplay peer pausing doesn't just hang. */ - input_poll(); + input_driver_poll(); video_driver_cached_frame(); return true; } #endif if (early_polling) - input_poll(); + input_driver_poll(); else if (late_polling) current_core.input_polled = false; current_core.retro_run(); if (late_polling && !current_core.input_polled) - input_poll(); + input_driver_poll(); #ifdef HAVE_NETWORKING netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL); @@ -20020,7 +21738,7 @@ bool core_load(unsigned poll_type_behavior) if (!core_init_libretro_cbs(&retro_ctx)) return false; - core_get_system_av_info(video_viewport_get_system_av_info()); + core_get_system_av_info(&video_driver_av_info); return true; } @@ -20038,16 +21756,6 @@ bool core_has_set_input_descriptor(void) return current_core.has_set_input_descriptors; } -void core_set_input_descriptors(void) -{ - current_core.has_set_input_descriptors = true; -} - -void core_unset_input_descriptors(void) -{ - current_core.has_set_input_descriptors = false; -} - bool core_is_inited(void) { return current_core.inited; @@ -20058,7 +21766,7 @@ bool core_is_symbols_inited(void) return current_core.symbols_inited; } -bool core_is_game_loaded(void) +static bool core_is_game_loaded(void) { return current_core.game_loaded; } diff --git a/retroarch.h b/retroarch.h index b267f0fbdb..73ef1dc6ed 100644 --- a/retroarch.h +++ b/retroarch.h @@ -116,7 +116,6 @@ enum rarch_ctl_state RARCH_CTL_FRAME_TIME_FREE, RARCH_CTL_SET_FRAME_TIME_LAST, - RARCH_CTL_SET_FRAME_TIME, RARCH_CTL_IS_IDLE, RARCH_CTL_SET_IDLE, @@ -176,11 +175,9 @@ enum rarch_ctl_state /* Core options */ RARCH_CTL_HAS_CORE_OPTIONS, RARCH_CTL_GET_CORE_OPTION_SIZE, - RARCH_CTL_IS_CORE_OPTION_UPDATED, RARCH_CTL_CORE_OPTIONS_LIST_GET, RARCH_CTL_CORE_OPTION_PREV, RARCH_CTL_CORE_OPTION_NEXT, - RARCH_CTL_CORE_OPTIONS_GET, RARCH_CTL_CORE_OPTIONS_INIT, RARCH_CTL_CORE_OPTIONS_DEINIT, @@ -555,10 +552,6 @@ typedef struct audio_driver size_t (*buffer_size)(void *data); } audio_driver_t; -bool audio_driver_is_suspended(void); - -bool audio_driver_is_active(void); - bool audio_driver_enable_callback(void); bool audio_driver_disable_callback(void); @@ -604,8 +597,6 @@ bool audio_driver_get_devices_list(void **ptr); void audio_driver_setup_rewind(void); -bool audio_driver_set_callback(const void *data); - bool audio_driver_callback(void); bool audio_driver_has_callback(void); @@ -830,8 +821,6 @@ void recording_set_state(bool state); void streaming_set_state(bool state); -void *recording_driver_get_data_ptr(void); - bool recording_is_enabled(void); bool streaming_is_enabled(void); @@ -1632,8 +1621,9 @@ bool video_driver_cached_frame_has_valid_framebuffer(void); void video_driver_set_cached_frame_ptr(const void *data); void video_driver_set_stub_frame(void); void video_driver_unset_stub_frame(void); -bool video_driver_is_stub_frame(void); + bool video_driver_supports_viewport_read(void); + bool video_driver_prefer_viewport_read(void); bool video_driver_supports_read_frame_raw(void); void video_driver_set_viewport_config(void); @@ -1679,8 +1669,6 @@ void video_driver_set_video_cache_context_ack(void); bool video_driver_is_video_cache_context_ack(void); -bool video_driver_is_active(void); - bool video_driver_get_current_software_framebuffer(struct retro_framebuffer *fb); diff --git a/runahead/run_ahead.h b/runahead/run_ahead.h deleted file mode 100644 index d529ab1742..0000000000 --- a/runahead/run_ahead.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __RUN_AHEAD_H__ -#define __RUN_AHEAD_H__ - -#include -#include - -#include - -RETRO_BEGIN_DECLS - -bool want_fast_savestate(void); -bool get_hard_disable_audio(void); - -RETRO_END_DECLS - -#endif