diff --git a/Makefile.common b/Makefile.common
index 817f0fb19b..8f315b3380 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -239,7 +239,6 @@ endif
OBJ += frontend/frontend_driver.o \
retroarch.o \
runloop.o \
- driver.o \
ui/ui_companion_driver.o \
camera/camera_driver.o \
record/record_driver.o \
diff --git a/driver.c b/driver.c
deleted file mode 100644
index 41560ca67b..0000000000
--- a/driver.c
+++ /dev/null
@@ -1,932 +0,0 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
- * Copyright (C) 2011-2021 - Daniel De Matteis
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
-
-#include
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "core_info.h"
-#include "driver.h"
-#include "retroarch.h"
-#include "runloop.h"
-#include "verbosity.h"
-
-#ifdef HAVE_BLUETOOTH
-#include "bluetooth/bluetooth_driver.h"
-#endif
-#ifdef HAVE_NETWORKING
-#ifdef HAVE_WIFI
-#include "network/wifi_driver.h"
-#endif
-#endif
-#include "led/led_driver.h"
-#include "midi_driver.h"
-#include "gfx/video_driver.h"
-#include "gfx/video_display_server.h"
-#include "audio/audio_driver.h"
-#include "camera/camera_driver.h"
-#include "record/record_driver.h"
-#include "location_driver.h"
-
-#ifdef HAVE_GFX_WIDGETS
-#include "gfx/gfx_widgets.h"
-#endif
-
-#ifdef HAVE_MENU
-#include "menu/menu_driver.h"
-#ifdef HAVE_CHEEVOS
-#include "cheevos/cheevos_menu.h"
-#endif
-#endif
-
-static void retro_frame_null(const void *data, unsigned width,
- unsigned height, size_t pitch) { }
-void retro_input_poll_null(void) { }
-
-/**
- * find_driver_nonempty:
- * @label : string of driver type to be found.
- * @i : index of driver.
- * @str : identifier name of the found driver
- * gets written to this string.
- * @len : size of @str.
- *
- * Find driver based on @label.
- *
- * Returns: NULL if no driver based on @label found, otherwise
- * pointer to driver.
- **/
-static const void *find_driver_nonempty(
- const char *label, int i,
- char *s, size_t len)
-{
- if (string_is_equal(label, "camera_driver"))
- {
- if (camera_drivers[i])
- {
- const char *ident = camera_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return camera_drivers[i];
- }
- }
- else if (string_is_equal(label, "location_driver"))
- {
- if (location_drivers[i])
- {
- const char *ident = location_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return location_drivers[i];
- }
- }
-#ifdef HAVE_MENU
- else if (string_is_equal(label, "menu_driver"))
- {
- if (menu_ctx_drivers[i])
- {
- const char *ident = menu_ctx_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return menu_ctx_drivers[i];
- }
- }
-#endif
- else if (string_is_equal(label, "input_driver"))
- {
- if (input_drivers[i])
- {
- const char *ident = input_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return input_drivers[i];
- }
- }
- else if (string_is_equal(label, "input_joypad_driver"))
- {
- if (joypad_drivers[i])
- {
- const char *ident = joypad_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return joypad_drivers[i];
- }
- }
- else if (string_is_equal(label, "video_driver"))
- {
- if (video_drivers[i])
- {
- const char *ident = video_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return video_drivers[i];
- }
- }
- else if (string_is_equal(label, "audio_driver"))
- {
- if (audio_drivers[i])
- {
- const char *ident = audio_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return audio_drivers[i];
- }
- }
- else if (string_is_equal(label, "record_driver"))
- {
- if (record_drivers[i])
- {
- const char *ident = record_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return record_drivers[i];
- }
- }
- else if (string_is_equal(label, "midi_driver"))
- {
- if (midi_driver_find_handle(i))
- {
- const char *ident = midi_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return midi_drivers[i];
- }
- }
- else if (string_is_equal(label, "audio_resampler_driver"))
- {
- if (audio_resampler_driver_find_handle(i))
- {
- const char *ident = audio_resampler_driver_find_ident(i);
-
- strlcpy(s, ident, len);
- return audio_resampler_driver_find_handle(i);
- }
- }
-#ifdef HAVE_BLUETOOTH
- else if (string_is_equal(label, "bluetooth_driver"))
- {
- if (bluetooth_drivers[i])
- {
- const char *ident = bluetooth_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return bluetooth_drivers[i];
- }
- }
-#endif
-#ifdef HAVE_WIFI
- else if (string_is_equal(label, "wifi_driver"))
- {
- if (wifi_drivers[i])
- {
- const char *ident = wifi_drivers[i]->ident;
-
- strlcpy(s, ident, len);
- return wifi_drivers[i];
- }
- }
-#endif
- return NULL;
-}
-
-int driver_find_index(const char *label, const char *drv)
-{
- unsigned i;
- char str[NAME_MAX_LENGTH];
-
- str[0] = '\0';
-
- for (i = 0;
- find_driver_nonempty(label, i, str, sizeof(str)) != NULL; i++)
- {
- if (string_is_empty(str))
- break;
- if (string_is_equal_noncase(drv, str))
- return i;
- }
-
- return -1;
-}
-
-/**
- * driver_find_last:
- * @label : string of driver type to be found.
- * @s : identifier of driver to be found.
- * @len : size of @s.
- *
- * Find last driver in driver array.
- **/
-static void driver_find_last(const char *label, char *s, size_t len)
-{
- unsigned i;
-
- for (i = 0;
- find_driver_nonempty(label, i, s, len) != NULL; i++) { }
-
- if (i)
- i = i - 1;
- else
- i = 0;
-
- find_driver_nonempty(label, i, s, len);
-}
-
-/**
- * driver_find_prev:
- * @label : string of driver type to be found.
- * @s : identifier of driver to be found.
- * @len : size of @s.
- *
- * Find previous driver in driver array.
- **/
-static bool driver_find_prev(const char *label, char *s, size_t len)
-{
- int i = driver_find_index(label, s);
-
- if (i > 0)
- {
- find_driver_nonempty(label, i - 1, s, len);
- return true;
- }
-
- RARCH_WARN(
- "Couldn't find any previous driver (current one: \"%s\").\n", s);
- return false;
-}
-
-/**
- * driver_find_next:
- * @label : string of driver type to be found.
- * @s : identifier of driver to be found.
- * @len : size of @s.
- *
- * Find next driver in driver array.
- **/
-static bool driver_find_next(const char *label, char *s, size_t len)
-{
- int i = driver_find_index(label, s);
-
- if (i >= 0 && string_is_not_equal(s, "null"))
- {
- find_driver_nonempty(label, i + 1, s, len);
- return true;
- }
-
- RARCH_WARN("%s (current one: \"%s\").\n",
- msg_hash_to_str(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER),
- s);
- return false;
-}
-
-static void driver_adjust_system_rates(
- bool vrr_runloop_enable,
- float video_refresh_rate,
- float audio_max_timing_skew,
- bool video_adaptive_vsync,
- unsigned video_swap_interval)
-{
- runloop_state_t *runloop_st = runloop_state_get_ptr();
- video_driver_state_t *video_st = video_state_get_ptr();
- struct retro_system_av_info *av_info = &video_st->av_info;
- const struct retro_system_timing *info =
- (const struct retro_system_timing*)&av_info->timing;
- double input_sample_rate = info->sample_rate;
- double input_fps = info->fps;
-
- /* Update video swap interval if automatic
- * switching is enabled */
- runloop_set_video_swap_interval(
- vrr_runloop_enable,
- video_st->flags & VIDEO_FLAG_CRT_SWITCHING_ACTIVE,
- video_swap_interval,
- audio_max_timing_skew,
- video_refresh_rate,
- input_fps);
- video_swap_interval = runloop_get_video_swap_interval(
- video_swap_interval);
-
- if (input_sample_rate > 0.0)
- {
- audio_driver_state_t *audio_st = audio_state_get_ptr();
- if (vrr_runloop_enable)
- audio_st->input = input_sample_rate;
- else
- audio_st->input =
- audio_driver_monitor_adjust_system_rates(
- input_sample_rate,
- input_fps,
- video_refresh_rate,
- video_swap_interval,
- audio_max_timing_skew);
-
- RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
- audio_st->input);
- }
-
- runloop_st->flags &= ~RUNLOOP_FLAG_FORCE_NONBLOCK;
-
- if (input_fps > 0.0)
- {
- float timing_skew_hz = video_refresh_rate;
-
- if (video_st->flags & VIDEO_FLAG_CRT_SWITCHING_ACTIVE)
- timing_skew_hz = input_fps;
- video_st->core_hz = input_fps;
-
- if (!video_driver_monitor_adjust_system_rates(
- timing_skew_hz,
- video_refresh_rate,
- vrr_runloop_enable,
- audio_max_timing_skew,
- video_swap_interval,
- input_fps))
- {
- /* We won't be able to do VSync reliably
- when game FPS > monitor FPS. */
- runloop_st->flags |= RUNLOOP_FLAG_FORCE_NONBLOCK;
- RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n");
-
- if (VIDEO_DRIVER_GET_PTR_INTERNAL(video_st))
- {
- if (video_st->current_video->set_nonblock_state)
- video_st->current_video->set_nonblock_state(
- video_st->data, true,
- video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC)
- && video_adaptive_vsync,
- video_swap_interval);
- }
- return;
- }
- }
-
- if (VIDEO_DRIVER_GET_PTR_INTERNAL(video_st))
- driver_set_nonblock_state();
-}
-
-/**
- * driver_set_nonblock_state:
- *
- * Sets audio and video drivers to nonblock state (if enabled).
- *
- * If nonblock state is false, sets
- * blocking state for both audio and video drivers instead.
- **/
-void driver_set_nonblock_state(void)
-{
- runloop_state_t *runloop_st = runloop_state_get_ptr();
- input_driver_state_t
- *input_st = input_state_get_ptr();
- audio_driver_state_t
- *audio_st = audio_state_get_ptr();
- video_driver_state_t
- *video_st = video_state_get_ptr();
- bool enable = input_st ?
- (input_st->flags & INP_FLAG_NONBLOCKING) : false;
- settings_t *settings = config_get_ptr();
- bool audio_sync = settings->bools.audio_sync;
- bool video_vsync = settings->bools.video_vsync;
- bool adaptive_vsync = settings->bools.video_adaptive_vsync;
- unsigned swap_interval = runloop_get_video_swap_interval(
- settings->uints.video_swap_interval);
- bool video_driver_active = video_st->flags & VIDEO_FLAG_ACTIVE;
- bool audio_driver_active = audio_st->flags & AUDIO_FLAG_ACTIVE;
- bool runloop_force_nonblock = runloop_st->flags & RUNLOOP_FLAG_FORCE_NONBLOCK;
-
- /* Only apply non-block-state for video if we're using vsync. */
- if (video_driver_active && VIDEO_DRIVER_GET_PTR_INTERNAL(video_st))
- {
- if (video_st->current_video->set_nonblock_state)
- {
- bool video_nonblock = enable;
- if (!video_vsync || runloop_force_nonblock)
- video_nonblock = true;
- video_st->current_video->set_nonblock_state(video_st->data,
- video_nonblock,
- video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
- adaptive_vsync, swap_interval);
- }
- }
-
- if (audio_driver_active && audio_st->context_audio_data)
- audio_st->current_audio->set_nonblock_state(
- audio_st->context_audio_data,
- audio_sync ? enable : true);
-
- audio_st->chunk_size = enable
- ? audio_st->chunk_nonblock_size
- : audio_st->chunk_block_size;
-}
-
-void drivers_init(
- settings_t *settings,
- int flags,
- bool verbosity_enabled)
-{
- runloop_state_t *runloop_st = runloop_state_get_ptr();
- audio_driver_state_t *audio_st = audio_state_get_ptr();
- input_driver_state_t *input_st = input_state_get_ptr();
- video_driver_state_t *video_st = video_state_get_ptr();
-#ifdef HAVE_MENU
- struct menu_state *menu_st = menu_state_get_ptr();
-#endif
- camera_driver_state_t
- *camera_st = camera_state_get_ptr();
- location_driver_state_t
- *location_st = location_state_get_ptr();
- bool video_is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
- gfx_display_t *p_disp = disp_get_ptr();
-#if defined(HAVE_GFX_WIDGETS)
- bool video_font_enable = settings->bools.video_font_enable;
- bool menu_enable_widgets = settings->bools.menu_enable_widgets;
- dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
- /* By default, we want display widgets to persist through driver reinits. */
- p_dispwidget->flags |= DISPGFX_WIDGET_FLAG_PERSISTING;
-#endif
-#ifdef HAVE_MENU
- /* By default, we want the menu to persist through driver reinits. */
- if (menu_st)
- menu_st->flags |= MENU_ST_FLAG_DATA_OWN;
-#endif
-
- if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
- driver_adjust_system_rates(
- settings->bools.vrr_runloop_enable,
- settings->floats.video_refresh_rate,
- settings->floats.audio_max_timing_skew,
- settings->bools.video_adaptive_vsync,
- settings->uints.video_swap_interval
- );
-
- /* Initialize video driver */
- if (flags & DRIVER_VIDEO_MASK)
- {
- struct retro_hw_render_callback *hwr =
- VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(video_st);
-
- video_st->frame_time_count = 0;
-
- video_driver_lock_new();
-#ifdef HAVE_VIDEO_FILTER
- video_driver_filter_free();
-#endif
- video_driver_set_cached_frame_ptr(NULL);
- if (!video_driver_init_internal(&video_is_threaded,
- verbosity_enabled))
- retroarch_fail(1, "video_driver_init_internal()");
-
- if ( !(video_st->flags & VIDEO_FLAG_CACHE_CONTEXT_ACK)
- && hwr->context_reset)
- hwr->context_reset();
- video_st->flags &= ~VIDEO_FLAG_CACHE_CONTEXT_ACK;
- runloop_st->frame_time_last = 0;
- }
-
- /* Initialize audio driver */
- if (flags & DRIVER_AUDIO_MASK)
- {
- audio_driver_init_internal(
- settings,
- audio_st->callback.callback != NULL);
- if ( audio_st->current_audio
- && audio_st->current_audio->device_list_new
- && audio_st->context_audio_data)
- audio_st->devices_list = (struct string_list*)
- audio_st->current_audio->device_list_new(
- audio_st->context_audio_data);
- }
-
- /* Regular display refresh rate startup autoswitch based on content av_info */
- if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
- {
- struct retro_system_av_info *av_info = &video_st->av_info;
- float refresh_rate = av_info->timing.fps;
- unsigned autoswitch_refresh_rate = settings->uints.video_autoswitch_refresh_rate;
- bool exclusive_fullscreen = settings->bools.video_fullscreen && !settings->bools.video_windowed_fullscreen;
- bool windowed_fullscreen = settings->bools.video_fullscreen && settings->bools.video_windowed_fullscreen;
- bool all_fullscreen = settings->bools.video_fullscreen || settings->bools.video_windowed_fullscreen;
-
- if ( refresh_rate > 0.0
- && !settings->uints.crt_switch_resolution
- && !settings->bools.vrr_runloop_enable
- && video_display_server_has_resolution_list()
- && (autoswitch_refresh_rate != AUTOSWITCH_REFRESH_RATE_OFF)
- && (fabs(settings->floats.video_refresh_rate - refresh_rate) > 1))
- {
- if (((autoswitch_refresh_rate == AUTOSWITCH_REFRESH_RATE_EXCLUSIVE_FULLSCREEN) && exclusive_fullscreen) ||
- ((autoswitch_refresh_rate == AUTOSWITCH_REFRESH_RATE_WINDOWED_FULLSCREEN) && windowed_fullscreen) ||
- ((autoswitch_refresh_rate == AUTOSWITCH_REFRESH_RATE_ALL_FULLSCREEN) && all_fullscreen))
- {
- bool video_switch_refresh_rate = false;
-
- video_switch_refresh_rate_maybe(&refresh_rate, &video_switch_refresh_rate);
-
- if (video_switch_refresh_rate && video_display_server_set_refresh_rate(refresh_rate))
- {
- int reinit_flags = DRIVER_AUDIO_MASK;
- video_monitor_set_refresh_rate(refresh_rate);
- /* Audio must reinit after successful rate switch */
- command_event(CMD_EVENT_REINIT, &reinit_flags);
- }
- }
- }
- }
-
- if (flags & DRIVER_CAMERA_MASK)
- {
- /* Only initialize camera driver if we're ever going to use it. */
- if (camera_st->active)
- {
- /* Resource leaks will follow if camera is initialized twice. */
- if (!camera_st->data)
- {
- if (!camera_driver_find_driver("camera driver",
- verbosity_enabled))
- retroarch_fail(1, "find_camera_driver()");
-
- if (camera_st->driver)
- {
- camera_st->data = camera_st->driver->init(
- *settings->arrays.camera_device ?
- settings->arrays.camera_device : NULL,
- camera_st->cb.caps,
- settings->uints.camera_width ?
- settings->uints.camera_width : camera_st->cb.width,
- settings->uints.camera_height ?
- settings->uints.camera_height : camera_st->cb.height);
-
- if (!camera_st->data)
- {
- RARCH_ERR("Failed to initialize camera driver. Will continue without camera.\n");
- camera_st->active = false;
- }
-
- if (camera_st->cb.initialized)
- camera_st->cb.initialized();
- }
- }
- }
- }
-
-#ifdef HAVE_BLUETOOTH
- if (flags & DRIVER_BLUETOOTH_MASK)
- bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_INIT, NULL);
-#endif
-#ifdef HAVE_WIFI
- if ((flags & DRIVER_WIFI_MASK))
- wifi_driver_ctl(RARCH_WIFI_CTL_INIT, NULL);
-#endif
-
- if (flags & DRIVER_LOCATION_MASK)
- {
- /* Only initialize location driver if we're ever going to use it. */
- if (location_st->active)
- if (!init_location(&runloop_state_get_ptr()->system,
- settings, verbosity_is_enabled()))
- location_st->active = false;
- }
-
- core_info_init_current_core();
-
-#if defined(HAVE_GFX_WIDGETS)
- /* Note that we only enable widgets if 'video_font_enable'
- * is true. 'video_font_enable' corresponds to the generic
- * 'On-Screen Notifications' setting, which should serve as
- * a global notifications on/off toggle switch */
- if ( video_font_enable
- && menu_enable_widgets
- && video_driver_has_widgets())
- {
- bool rarch_force_fullscreen = video_st->flags &
- VIDEO_FLAG_FORCE_FULLSCREEN;
- bool video_is_fullscreen = settings->bools.video_fullscreen ||
- rarch_force_fullscreen;
-
- p_dispwidget->active= gfx_widgets_init(
- p_disp,
- anim_get_ptr(),
- settings,
- (uintptr_t)&p_dispwidget->active,
- video_is_threaded,
- video_st->width,
- video_st->height,
- video_is_fullscreen,
- settings->paths.directory_assets,
- settings->paths.path_font);
- }
- else
-#endif
- {
- gfx_display_init_first_driver(p_disp, video_is_threaded);
- }
-
-#ifdef HAVE_MENU
- if (flags & DRIVER_VIDEO_MASK)
- {
- /* Initialize menu driver */
- if (flags & DRIVER_MENU_MASK)
- {
- if (!menu_driver_init(video_is_threaded))
- RARCH_ERR("Unable to init menu driver.\n");
-
-#ifdef HAVE_LIBRETRODB
- menu_explore_context_init();
-#endif
- menu_contentless_cores_context_init();
- }
- }
-
- /* Initialising the menu driver will also initialise
- * core info - if we are not initialising the menu
- * driver, must initialise core info 'by hand' */
- if (!(flags & DRIVER_VIDEO_MASK) ||
- !(flags & DRIVER_MENU_MASK))
- {
- command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
- command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
- }
-
-#else
- /* Qt uses core info, even if the menu is disabled */
- command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
- command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
-#endif
-
- /* Keep non-throttled state as good as possible. */
- if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
- if (input_st && (input_st->flags & INP_FLAG_NONBLOCKING))
- driver_set_nonblock_state();
-
- /* Initialize LED driver */
- if (flags & DRIVER_LED_MASK)
- led_driver_init(settings->arrays.led_driver);
-
- /* Initialize MIDI driver */
- if (flags & DRIVER_MIDI_MASK)
- midi_driver_init(settings);
-
-#ifndef HAVE_LAKKA_SWITCH
-#ifdef HAVE_LAKKA
- cpu_scaling_driver_init();
-#endif
-#endif /* #ifndef HAVE_LAKKA_SWITCH */
-}
-
-void driver_uninit(int flags)
-{
- runloop_state_t *runloop_st = runloop_state_get_ptr();
- video_driver_state_t *video_st = video_state_get_ptr();
- camera_driver_state_t *camera_st = camera_state_get_ptr();
-#if defined(HAVE_GFX_WIDGETS)
- dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
-#endif
-
- core_info_deinit_list();
- core_info_free_current_core();
-
-#if defined(HAVE_GFX_WIDGETS)
- /* This absolutely has to be done before video_driver_free_internal()
- * is called/completes, otherwise certain menu drivers
- * (e.g. Vulkan) will segfault */
- if (p_dispwidget->flags & DISPGFX_WIDGET_FLAG_INITED)
- {
- gfx_widgets_deinit(p_dispwidget->flags & DISPGFX_WIDGET_FLAG_PERSISTING);
- p_dispwidget->active = false;
- }
-#endif
-
-#ifdef HAVE_MENU
- if (flags & DRIVER_MENU_MASK)
- {
-#ifdef HAVE_LIBRETRODB
- menu_explore_context_deinit();
-#endif
- menu_contentless_cores_context_deinit();
-
-#ifdef HAVE_CHEEVOS
- rcheevos_menu_reset_badges();
-#endif
-
- menu_driver_ctl(RARCH_MENU_CTL_DEINIT, NULL);
- }
-#endif
-
- if ((flags & DRIVER_LOCATION_MASK))
- uninit_location(&runloop_st->system);
-
- if ((flags & DRIVER_CAMERA_MASK))
- {
- if (camera_st->data && camera_st->driver)
- {
- if (camera_st->cb.deinitialized)
- camera_st->cb.deinitialized();
-
- if (camera_st->driver->free)
- camera_st->driver->free(camera_st->data);
- }
-
- camera_st->data = NULL;
- }
-
-#ifdef HAVE_BLUETOOTH
- if ((flags & DRIVER_BLUETOOTH_MASK))
- bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DEINIT, NULL);
-#endif
-#ifdef HAVE_WIFI
- if ((flags & DRIVER_WIFI_MASK))
- wifi_driver_ctl(RARCH_WIFI_CTL_DEINIT, NULL);
-#endif
-
- if (flags & DRIVER_LED)
- led_driver_free();
-
- if (flags & DRIVERS_VIDEO_INPUT)
- {
- video_driver_free_internal();
- VIDEO_DRIVER_LOCK_FREE(video_st);
- video_st->data = NULL;
- video_driver_set_cached_frame_ptr(NULL);
- }
-
- if (flags & DRIVER_AUDIO_MASK)
- audio_driver_deinit();
-
- if ((flags & DRIVER_VIDEO_MASK))
- video_st->data = NULL;
-
- if ((flags & DRIVER_INPUT_MASK))
- input_state_get_ptr()->current_data = NULL;
-
- if ((flags & DRIVER_AUDIO_MASK))
- audio_state_get_ptr()->context_audio_data = NULL;
-
- if (flags & DRIVER_MIDI_MASK)
- midi_driver_free();
-
-#ifndef HAVE_LAKKA_SWITCH
-#ifdef HAVE_LAKKA
- cpu_scaling_driver_free();
-#endif
-#endif /* #ifndef HAVE_LAKKA_SWITCH */
-}
-
-void retroarch_deinit_drivers(struct retro_callbacks *cbs)
-{
- input_driver_state_t *input_st = input_state_get_ptr();
- video_driver_state_t *video_st = video_state_get_ptr();
- camera_driver_state_t *camera_st= camera_state_get_ptr();
- location_driver_state_t
- *location_st = location_state_get_ptr();
- runloop_state_t *runloop_st = runloop_state_get_ptr();
-#if defined(HAVE_GFX_WIDGETS)
- /* Tear down display widgets no matter what
- * in case the handle is lost in the threaded
- * video driver in the meantime
- * (breaking video_driver_has_widgets) */
- dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
- if (p_dispwidget->flags & DISPGFX_WIDGET_FLAG_INITED)
- {
- gfx_widgets_deinit(
- p_dispwidget->flags & DISPGFX_WIDGET_FLAG_PERSISTING);
- p_dispwidget->active = false;
- }
-#endif
-
-#if defined(HAVE_CRTSWITCHRES)
- /* Switchres deinit */
- if (video_st->flags & VIDEO_FLAG_CRT_SWITCHING_ACTIVE)
- crt_destroy_modes(&video_st->crt_switch_st);
-#endif
-
- /* Video */
- video_display_server_destroy();
-
- video_st->flags &= ~(VIDEO_FLAG_ACTIVE | VIDEO_FLAG_USE_RGBA |
- VIDEO_FLAG_HDR_SUPPORT | VIDEO_FLAG_CACHE_CONTEXT |
- VIDEO_FLAG_CACHE_CONTEXT_ACK
- );
- video_st->record_gpu_buffer = NULL;
- video_st->current_video = NULL;
- video_driver_set_cached_frame_ptr(NULL);
-
- /* Audio */
- audio_state_get_ptr()->flags &= ~AUDIO_FLAG_ACTIVE;
- audio_state_get_ptr()->current_audio = NULL;
-
- if (input_st)
- {
- /* Input */
- input_st->flags &= ~(INP_FLAG_KB_LINEFEED_ENABLE
- | INP_FLAG_BLOCK_HOTKEY
- | INP_FLAG_BLOCK_LIBRETRO_INPUT
- | INP_FLAG_NONBLOCKING);
-
- memset(&input_st->turbo_btns, 0, sizeof(turbo_buttons_t));
- memset(&input_st->analog_requested, 0,
- sizeof(input_st->analog_requested));
- input_st->current_driver = NULL;
- }
-
-#ifdef HAVE_MENU
- menu_driver_destroy(
- menu_state_get_ptr());
-#endif
- location_st->active = false;
- destroy_location();
-
- /* Camera */
- camera_st->active = false;
- camera_st->driver = NULL;
- camera_st->data = NULL;
-
-#ifdef HAVE_BLUETOOTH
- bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DESTROY, NULL);
-#endif
-#ifdef HAVE_WIFI
- wifi_driver_ctl(RARCH_WIFI_CTL_DESTROY, NULL);
-#endif
-
- cbs->frame_cb = retro_frame_null;
- cbs->poll_cb = retro_input_poll_null;
- cbs->sample_cb = NULL;
- cbs->sample_batch_cb = NULL;
- cbs->state_cb = NULL;
-
- runloop_st->current_core.flags &= ~RETRO_CORE_FLAG_INITED;
-}
-
-bool driver_ctl(enum driver_ctl_state state, void *data)
-{
- driver_ctx_info_t *drv = (driver_ctx_info_t*)data;
-
- switch (state)
- {
- case RARCH_DRIVER_CTL_SET_REFRESH_RATE:
- {
- float *hz = (float*)data;
- audio_driver_state_t
- *audio_st = audio_state_get_ptr();
- settings_t *settings = config_get_ptr();
- unsigned
- audio_output_sample_rate = settings->uints.audio_output_sample_rate;
- bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
- float video_refresh_rate = settings->floats.video_refresh_rate;
- float audio_max_timing_skew = settings->floats.audio_max_timing_skew;
- bool video_adaptive_vsync = settings->bools.video_adaptive_vsync;
- unsigned video_swap_interval = settings->uints.video_swap_interval;
-
- video_monitor_set_refresh_rate(*hz);
-
- /* Sets audio monitor rate to new value. */
- audio_st->source_ratio_original =
- audio_st->source_ratio_current =
- (double)audio_output_sample_rate / audio_st->input;
-
- driver_adjust_system_rates(
- vrr_runloop_enable,
- video_refresh_rate,
- audio_max_timing_skew,
- video_adaptive_vsync,
- video_swap_interval
- );
- }
- break;
- case RARCH_DRIVER_CTL_FIND_FIRST:
- if (!drv)
- return false;
- find_driver_nonempty(drv->label, 0, drv->s, drv->len);
- break;
- case RARCH_DRIVER_CTL_FIND_LAST:
- if (!drv)
- return false;
- driver_find_last(drv->label, drv->s, drv->len);
- break;
- case RARCH_DRIVER_CTL_FIND_PREV:
- if (!drv)
- return false;
- return driver_find_prev(drv->label, drv->s, drv->len);
- case RARCH_DRIVER_CTL_FIND_NEXT:
- if (!drv)
- return false;
- return driver_find_next(drv->label, drv->s, drv->len);
- case RARCH_DRIVER_CTL_NONE:
- default:
- break;
- }
-
- return true;
-}
diff --git a/driver.h b/driver.h
index fc454729c8..8eef1776a7 100644
--- a/driver.h
+++ b/driver.h
@@ -133,8 +133,6 @@ void driver_uninit(int flags);
void retro_input_poll_null(void);
-void retroarch_deinit_drivers(struct retro_callbacks *cbs);
-
RETRO_END_DECLS
#endif
diff --git a/griffin/griffin.c b/griffin/griffin.c
index 3d0525f505..c2de253044 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -1237,7 +1237,6 @@ RETROARCH
#include "../retroarch.c"
#include "../runloop.c"
#include "../command.c"
-#include "../driver.c"
#include "../midi_driver.c"
#include "../location_driver.c"
#include "../ui/ui_companion_driver.c"
diff --git a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj
index e24e3248e2..7fc4f527e0 100644
--- a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj
+++ b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj
@@ -149,7 +149,6 @@
05422E592140C8DB00F09961 /* RetroArch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RetroArch.app; sourceTree = BUILT_PRODUCTS_DIR; };
05422E5B2140CE3500F09961 /* VulkanConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = VulkanConfig.xcconfig; sourceTree = ""; };
05422E5C2140CFC500F09961 /* Metal.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Metal.xcconfig; sourceTree = ""; };
- 0548E2B220F976E10094A083 /* driver.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = driver.c; path = ../../driver.c; sourceTree = ""; };
0548E2B320F976E10094A083 /* dynamic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dynamic.c; path = ../../dynamic.c; sourceTree = ""; };
0548E2B420F976E10094A083 /* dynamic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dynamic.h; path = ../../dynamic.h; sourceTree = ""; };
0548E2B520F976E20094A083 /* driver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = driver.h; path = ../../driver.h; sourceTree = ""; };
diff --git a/retroarch.c b/retroarch.c
index bb6b9c932a..806a7445da 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -179,11 +179,13 @@
#include "ui/ui_companion_driver.h"
#include "verbosity.h"
+#include "gfx/video_driver.h"
#include "gfx/video_display_server.h"
#ifdef HAVE_BLUETOOTH
#include "bluetooth/bluetooth_driver.h"
#endif
#include "misc/cpufreq/cpufreq.h"
+#include "led/led_driver.h"
#include "midi_driver.h"
#include "core.h"
#include "configuration.h"
@@ -332,6 +334,883 @@ static const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED;
static access_state_t access_state_st = {0};
static struct global global_driver_st = {0}; /* retro_time_t alignment */
+static void retro_frame_null(const void *data, unsigned width,
+ unsigned height, size_t pitch) { }
+void retro_input_poll_null(void) { }
+
+/**
+ * find_driver_nonempty:
+ * @label : string of driver type to be found.
+ * @i : index of driver.
+ * @str : identifier name of the found driver
+ * gets written to this string.
+ * @len : size of @str.
+ *
+ * Find driver based on @label.
+ *
+ * Returns: NULL if no driver based on @label found, otherwise
+ * pointer to driver.
+ **/
+static const void *find_driver_nonempty(
+ const char *label, int i,
+ char *s, size_t len)
+{
+ if (string_is_equal(label, "camera_driver"))
+ {
+ if (camera_drivers[i])
+ {
+ const char *ident = camera_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return camera_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "location_driver"))
+ {
+ if (location_drivers[i])
+ {
+ const char *ident = location_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return location_drivers[i];
+ }
+ }
+#ifdef HAVE_MENU
+ else if (string_is_equal(label, "menu_driver"))
+ {
+ if (menu_ctx_drivers[i])
+ {
+ const char *ident = menu_ctx_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return menu_ctx_drivers[i];
+ }
+ }
+#endif
+ else if (string_is_equal(label, "input_driver"))
+ {
+ if (input_drivers[i])
+ {
+ const char *ident = input_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return input_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "input_joypad_driver"))
+ {
+ if (joypad_drivers[i])
+ {
+ const char *ident = joypad_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return joypad_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "video_driver"))
+ {
+ if (video_drivers[i])
+ {
+ const char *ident = video_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return video_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "audio_driver"))
+ {
+ if (audio_drivers[i])
+ {
+ const char *ident = audio_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return audio_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "record_driver"))
+ {
+ if (record_drivers[i])
+ {
+ const char *ident = record_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return record_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "midi_driver"))
+ {
+ if (midi_driver_find_handle(i))
+ {
+ const char *ident = midi_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return midi_drivers[i];
+ }
+ }
+ else if (string_is_equal(label, "audio_resampler_driver"))
+ {
+ if (audio_resampler_driver_find_handle(i))
+ {
+ const char *ident = audio_resampler_driver_find_ident(i);
+
+ strlcpy(s, ident, len);
+ return audio_resampler_driver_find_handle(i);
+ }
+ }
+#ifdef HAVE_BLUETOOTH
+ else if (string_is_equal(label, "bluetooth_driver"))
+ {
+ if (bluetooth_drivers[i])
+ {
+ const char *ident = bluetooth_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return bluetooth_drivers[i];
+ }
+ }
+#endif
+#ifdef HAVE_WIFI
+ else if (string_is_equal(label, "wifi_driver"))
+ {
+ if (wifi_drivers[i])
+ {
+ const char *ident = wifi_drivers[i]->ident;
+
+ strlcpy(s, ident, len);
+ return wifi_drivers[i];
+ }
+ }
+#endif
+ return NULL;
+}
+
+int driver_find_index(const char *label, const char *drv)
+{
+ unsigned i;
+ char str[NAME_MAX_LENGTH];
+
+ str[0] = '\0';
+
+ for (i = 0;
+ find_driver_nonempty(label, i, str, sizeof(str)) != NULL; i++)
+ {
+ if (string_is_empty(str))
+ break;
+ if (string_is_equal_noncase(drv, str))
+ return i;
+ }
+
+ return -1;
+}
+
+/**
+ * driver_find_last:
+ * @label : string of driver type to be found.
+ * @s : identifier of driver to be found.
+ * @len : size of @s.
+ *
+ * Find last driver in driver array.
+ **/
+static void driver_find_last(const char *label, char *s, size_t len)
+{
+ unsigned i;
+
+ for (i = 0;
+ find_driver_nonempty(label, i, s, len) != NULL; i++) { }
+
+ if (i)
+ i = i - 1;
+ else
+ i = 0;
+
+ find_driver_nonempty(label, i, s, len);
+}
+
+/**
+ * driver_find_prev:
+ * @label : string of driver type to be found.
+ * @s : identifier of driver to be found.
+ * @len : size of @s.
+ *
+ * Find previous driver in driver array.
+ **/
+static bool driver_find_prev(const char *label, char *s, size_t len)
+{
+ int i = driver_find_index(label, s);
+
+ if (i > 0)
+ {
+ find_driver_nonempty(label, i - 1, s, len);
+ return true;
+ }
+
+ RARCH_WARN(
+ "Couldn't find any previous driver (current one: \"%s\").\n", s);
+ return false;
+}
+
+/**
+ * driver_find_next:
+ * @label : string of driver type to be found.
+ * @s : identifier of driver to be found.
+ * @len : size of @s.
+ *
+ * Find next driver in driver array.
+ **/
+static bool driver_find_next(const char *label, char *s, size_t len)
+{
+ int i = driver_find_index(label, s);
+
+ if (i >= 0 && string_is_not_equal(s, "null"))
+ {
+ find_driver_nonempty(label, i + 1, s, len);
+ return true;
+ }
+
+ RARCH_WARN("%s (current one: \"%s\").\n",
+ msg_hash_to_str(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER),
+ s);
+ return false;
+}
+
+static void driver_adjust_system_rates(
+ bool vrr_runloop_enable,
+ float video_refresh_rate,
+ float audio_max_timing_skew,
+ bool video_adaptive_vsync,
+ unsigned video_swap_interval)
+{
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ video_driver_state_t *video_st = video_state_get_ptr();
+ struct retro_system_av_info *av_info = &video_st->av_info;
+ const struct retro_system_timing *info =
+ (const struct retro_system_timing*)&av_info->timing;
+ double input_sample_rate = info->sample_rate;
+ double input_fps = info->fps;
+
+ /* Update video swap interval if automatic
+ * switching is enabled */
+ runloop_set_video_swap_interval(
+ vrr_runloop_enable,
+ video_st->flags & VIDEO_FLAG_CRT_SWITCHING_ACTIVE,
+ video_swap_interval,
+ audio_max_timing_skew,
+ video_refresh_rate,
+ input_fps);
+ video_swap_interval = runloop_get_video_swap_interval(
+ video_swap_interval);
+
+ if (input_sample_rate > 0.0)
+ {
+ audio_driver_state_t *audio_st = audio_state_get_ptr();
+ if (vrr_runloop_enable)
+ audio_st->input = input_sample_rate;
+ else
+ audio_st->input =
+ audio_driver_monitor_adjust_system_rates(
+ input_sample_rate,
+ input_fps,
+ video_refresh_rate,
+ video_swap_interval,
+ audio_max_timing_skew);
+
+ RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
+ audio_st->input);
+ }
+
+ runloop_st->flags &= ~RUNLOOP_FLAG_FORCE_NONBLOCK;
+
+ if (input_fps > 0.0)
+ {
+ float timing_skew_hz = video_refresh_rate;
+
+ if (video_st->flags & VIDEO_FLAG_CRT_SWITCHING_ACTIVE)
+ timing_skew_hz = input_fps;
+ video_st->core_hz = input_fps;
+
+ if (!video_driver_monitor_adjust_system_rates(
+ timing_skew_hz,
+ video_refresh_rate,
+ vrr_runloop_enable,
+ audio_max_timing_skew,
+ video_swap_interval,
+ input_fps))
+ {
+ /* We won't be able to do VSync reliably
+ when game FPS > monitor FPS. */
+ runloop_st->flags |= RUNLOOP_FLAG_FORCE_NONBLOCK;
+ RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n");
+
+ if (VIDEO_DRIVER_GET_PTR_INTERNAL(video_st))
+ {
+ if (video_st->current_video->set_nonblock_state)
+ video_st->current_video->set_nonblock_state(
+ video_st->data, true,
+ video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC)
+ && video_adaptive_vsync,
+ video_swap_interval);
+ }
+ return;
+ }
+ }
+
+ if (VIDEO_DRIVER_GET_PTR_INTERNAL(video_st))
+ driver_set_nonblock_state();
+}
+
+/**
+ * driver_set_nonblock_state:
+ *
+ * Sets audio and video drivers to nonblock state (if enabled).
+ *
+ * If nonblock state is false, sets
+ * blocking state for both audio and video drivers instead.
+ **/
+void driver_set_nonblock_state(void)
+{
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ input_driver_state_t
+ *input_st = input_state_get_ptr();
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
+ video_driver_state_t
+ *video_st = video_state_get_ptr();
+ bool enable = input_st ?
+ (input_st->flags & INP_FLAG_NONBLOCKING) : false;
+ settings_t *settings = config_get_ptr();
+ bool audio_sync = settings->bools.audio_sync;
+ bool video_vsync = settings->bools.video_vsync;
+ bool adaptive_vsync = settings->bools.video_adaptive_vsync;
+ unsigned swap_interval = runloop_get_video_swap_interval(
+ settings->uints.video_swap_interval);
+ bool video_driver_active = video_st->flags & VIDEO_FLAG_ACTIVE;
+ bool audio_driver_active = audio_st->flags & AUDIO_FLAG_ACTIVE;
+ bool runloop_force_nonblock = runloop_st->flags & RUNLOOP_FLAG_FORCE_NONBLOCK;
+
+ /* Only apply non-block-state for video if we're using vsync. */
+ if (video_driver_active && VIDEO_DRIVER_GET_PTR_INTERNAL(video_st))
+ {
+ if (video_st->current_video->set_nonblock_state)
+ {
+ bool video_nonblock = enable;
+ if (!video_vsync || runloop_force_nonblock)
+ video_nonblock = true;
+ video_st->current_video->set_nonblock_state(video_st->data,
+ video_nonblock,
+ video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
+ adaptive_vsync, swap_interval);
+ }
+ }
+
+ if (audio_driver_active && audio_st->context_audio_data)
+ audio_st->current_audio->set_nonblock_state(
+ audio_st->context_audio_data,
+ audio_sync ? enable : true);
+
+ audio_st->chunk_size = enable
+ ? audio_st->chunk_nonblock_size
+ : audio_st->chunk_block_size;
+}
+
+void drivers_init(
+ settings_t *settings,
+ int flags,
+ bool verbosity_enabled)
+{
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ audio_driver_state_t *audio_st = audio_state_get_ptr();
+ input_driver_state_t *input_st = input_state_get_ptr();
+ video_driver_state_t *video_st = video_state_get_ptr();
+#ifdef HAVE_MENU
+ struct menu_state *menu_st = menu_state_get_ptr();
+#endif
+ camera_driver_state_t
+ *camera_st = camera_state_get_ptr();
+ location_driver_state_t
+ *location_st = location_state_get_ptr();
+ bool video_is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
+ gfx_display_t *p_disp = disp_get_ptr();
+#if defined(HAVE_GFX_WIDGETS)
+ bool video_font_enable = settings->bools.video_font_enable;
+ bool menu_enable_widgets = settings->bools.menu_enable_widgets;
+ dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
+ /* By default, we want display widgets to persist through driver reinits. */
+ p_dispwidget->flags |= DISPGFX_WIDGET_FLAG_PERSISTING;
+#endif
+#ifdef HAVE_MENU
+ /* By default, we want the menu to persist through driver reinits. */
+ if (menu_st)
+ menu_st->flags |= MENU_ST_FLAG_DATA_OWN;
+#endif
+
+ if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
+ driver_adjust_system_rates(
+ settings->bools.vrr_runloop_enable,
+ settings->floats.video_refresh_rate,
+ settings->floats.audio_max_timing_skew,
+ settings->bools.video_adaptive_vsync,
+ settings->uints.video_swap_interval
+ );
+
+ /* Initialize video driver */
+ if (flags & DRIVER_VIDEO_MASK)
+ {
+ struct retro_hw_render_callback *hwr =
+ VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(video_st);
+
+ video_st->frame_time_count = 0;
+
+ video_driver_lock_new();
+#ifdef HAVE_VIDEO_FILTER
+ video_driver_filter_free();
+#endif
+ video_driver_set_cached_frame_ptr(NULL);
+ if (!video_driver_init_internal(&video_is_threaded,
+ verbosity_enabled))
+ retroarch_fail(1, "video_driver_init_internal()");
+
+ if ( !(video_st->flags & VIDEO_FLAG_CACHE_CONTEXT_ACK)
+ && hwr->context_reset)
+ hwr->context_reset();
+ video_st->flags &= ~VIDEO_FLAG_CACHE_CONTEXT_ACK;
+ runloop_st->frame_time_last = 0;
+ }
+
+ /* Initialize audio driver */
+ if (flags & DRIVER_AUDIO_MASK)
+ {
+ audio_driver_init_internal(
+ settings,
+ audio_st->callback.callback != NULL);
+ if ( audio_st->current_audio
+ && audio_st->current_audio->device_list_new
+ && audio_st->context_audio_data)
+ audio_st->devices_list = (struct string_list*)
+ audio_st->current_audio->device_list_new(
+ audio_st->context_audio_data);
+ }
+
+ /* Regular display refresh rate startup autoswitch based on content av_info */
+ if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
+ {
+ struct retro_system_av_info *av_info = &video_st->av_info;
+ float refresh_rate = av_info->timing.fps;
+ unsigned autoswitch_refresh_rate = settings->uints.video_autoswitch_refresh_rate;
+ bool exclusive_fullscreen = settings->bools.video_fullscreen && !settings->bools.video_windowed_fullscreen;
+ bool windowed_fullscreen = settings->bools.video_fullscreen && settings->bools.video_windowed_fullscreen;
+ bool all_fullscreen = settings->bools.video_fullscreen || settings->bools.video_windowed_fullscreen;
+
+ if ( refresh_rate > 0.0
+ && !settings->uints.crt_switch_resolution
+ && !settings->bools.vrr_runloop_enable
+ && video_display_server_has_resolution_list()
+ && (autoswitch_refresh_rate != AUTOSWITCH_REFRESH_RATE_OFF)
+ && (fabs(settings->floats.video_refresh_rate - refresh_rate) > 1))
+ {
+ if (((autoswitch_refresh_rate == AUTOSWITCH_REFRESH_RATE_EXCLUSIVE_FULLSCREEN) && exclusive_fullscreen) ||
+ ((autoswitch_refresh_rate == AUTOSWITCH_REFRESH_RATE_WINDOWED_FULLSCREEN) && windowed_fullscreen) ||
+ ((autoswitch_refresh_rate == AUTOSWITCH_REFRESH_RATE_ALL_FULLSCREEN) && all_fullscreen))
+ {
+ bool video_switch_refresh_rate = false;
+
+ video_switch_refresh_rate_maybe(&refresh_rate, &video_switch_refresh_rate);
+
+ if (video_switch_refresh_rate && video_display_server_set_refresh_rate(refresh_rate))
+ {
+ int reinit_flags = DRIVER_AUDIO_MASK;
+ video_monitor_set_refresh_rate(refresh_rate);
+ /* Audio must reinit after successful rate switch */
+ command_event(CMD_EVENT_REINIT, &reinit_flags);
+ }
+ }
+ }
+ }
+
+ if (flags & DRIVER_CAMERA_MASK)
+ {
+ /* Only initialize camera driver if we're ever going to use it. */
+ if (camera_st->active)
+ {
+ /* Resource leaks will follow if camera is initialized twice. */
+ if (!camera_st->data)
+ {
+ if (!camera_driver_find_driver("camera driver",
+ verbosity_enabled))
+ retroarch_fail(1, "find_camera_driver()");
+
+ if (camera_st->driver)
+ {
+ camera_st->data = camera_st->driver->init(
+ *settings->arrays.camera_device ?
+ settings->arrays.camera_device : NULL,
+ camera_st->cb.caps,
+ settings->uints.camera_width ?
+ settings->uints.camera_width : camera_st->cb.width,
+ settings->uints.camera_height ?
+ settings->uints.camera_height : camera_st->cb.height);
+
+ if (!camera_st->data)
+ {
+ RARCH_ERR("Failed to initialize camera driver. Will continue without camera.\n");
+ camera_st->active = false;
+ }
+
+ if (camera_st->cb.initialized)
+ camera_st->cb.initialized();
+ }
+ }
+ }
+ }
+
+#ifdef HAVE_BLUETOOTH
+ if (flags & DRIVER_BLUETOOTH_MASK)
+ bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_INIT, NULL);
+#endif
+#ifdef HAVE_WIFI
+ if ((flags & DRIVER_WIFI_MASK))
+ wifi_driver_ctl(RARCH_WIFI_CTL_INIT, NULL);
+#endif
+
+ if (flags & DRIVER_LOCATION_MASK)
+ {
+ /* Only initialize location driver if we're ever going to use it. */
+ if (location_st->active)
+ if (!init_location(&runloop_state_get_ptr()->system,
+ settings, verbosity_is_enabled()))
+ location_st->active = false;
+ }
+
+ core_info_init_current_core();
+
+#if defined(HAVE_GFX_WIDGETS)
+ /* Note that we only enable widgets if 'video_font_enable'
+ * is true. 'video_font_enable' corresponds to the generic
+ * 'On-Screen Notifications' setting, which should serve as
+ * a global notifications on/off toggle switch */
+ if ( video_font_enable
+ && menu_enable_widgets
+ && video_driver_has_widgets())
+ {
+ bool rarch_force_fullscreen = video_st->flags &
+ VIDEO_FLAG_FORCE_FULLSCREEN;
+ bool video_is_fullscreen = settings->bools.video_fullscreen ||
+ rarch_force_fullscreen;
+
+ p_dispwidget->active= gfx_widgets_init(
+ p_disp,
+ anim_get_ptr(),
+ settings,
+ (uintptr_t)&p_dispwidget->active,
+ video_is_threaded,
+ video_st->width,
+ video_st->height,
+ video_is_fullscreen,
+ settings->paths.directory_assets,
+ settings->paths.path_font);
+ }
+ else
+#endif
+ {
+ gfx_display_init_first_driver(p_disp, video_is_threaded);
+ }
+
+#ifdef HAVE_MENU
+ if (flags & DRIVER_VIDEO_MASK)
+ {
+ /* Initialize menu driver */
+ if (flags & DRIVER_MENU_MASK)
+ {
+ if (!menu_driver_init(video_is_threaded))
+ RARCH_ERR("Unable to init menu driver.\n");
+
+#ifdef HAVE_LIBRETRODB
+ menu_explore_context_init();
+#endif
+ menu_contentless_cores_context_init();
+ }
+ }
+
+ /* Initialising the menu driver will also initialise
+ * core info - if we are not initialising the menu
+ * driver, must initialise core info 'by hand' */
+ if (!(flags & DRIVER_VIDEO_MASK) ||
+ !(flags & DRIVER_MENU_MASK))
+ {
+ command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
+ command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
+ }
+
+#else
+ /* Qt uses core info, even if the menu is disabled */
+ command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
+ command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
+#endif
+
+ /* Keep non-throttled state as good as possible. */
+ if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
+ if (input_st && (input_st->flags & INP_FLAG_NONBLOCKING))
+ driver_set_nonblock_state();
+
+ /* Initialize LED driver */
+ if (flags & DRIVER_LED_MASK)
+ led_driver_init(settings->arrays.led_driver);
+
+ /* Initialize MIDI driver */
+ if (flags & DRIVER_MIDI_MASK)
+ midi_driver_init(settings);
+
+#ifndef HAVE_LAKKA_SWITCH
+#ifdef HAVE_LAKKA
+ cpu_scaling_driver_init();
+#endif
+#endif /* #ifndef HAVE_LAKKA_SWITCH */
+}
+
+void driver_uninit(int flags)
+{
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ video_driver_state_t *video_st = video_state_get_ptr();
+ camera_driver_state_t *camera_st = camera_state_get_ptr();
+#if defined(HAVE_GFX_WIDGETS)
+ dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
+#endif
+
+ core_info_deinit_list();
+ core_info_free_current_core();
+
+#if defined(HAVE_GFX_WIDGETS)
+ /* This absolutely has to be done before video_driver_free_internal()
+ * is called/completes, otherwise certain menu drivers
+ * (e.g. Vulkan) will segfault */
+ if (p_dispwidget->flags & DISPGFX_WIDGET_FLAG_INITED)
+ {
+ gfx_widgets_deinit(p_dispwidget->flags & DISPGFX_WIDGET_FLAG_PERSISTING);
+ p_dispwidget->active = false;
+ }
+#endif
+
+#ifdef HAVE_MENU
+ if (flags & DRIVER_MENU_MASK)
+ {
+#ifdef HAVE_LIBRETRODB
+ menu_explore_context_deinit();
+#endif
+ menu_contentless_cores_context_deinit();
+
+#ifdef HAVE_CHEEVOS
+ rcheevos_menu_reset_badges();
+#endif
+
+ menu_driver_ctl(RARCH_MENU_CTL_DEINIT, NULL);
+ }
+#endif
+
+ if ((flags & DRIVER_LOCATION_MASK))
+ uninit_location(&runloop_st->system);
+
+ if ((flags & DRIVER_CAMERA_MASK))
+ {
+ if (camera_st->data && camera_st->driver)
+ {
+ if (camera_st->cb.deinitialized)
+ camera_st->cb.deinitialized();
+
+ if (camera_st->driver->free)
+ camera_st->driver->free(camera_st->data);
+ }
+
+ camera_st->data = NULL;
+ }
+
+#ifdef HAVE_BLUETOOTH
+ if ((flags & DRIVER_BLUETOOTH_MASK))
+ bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DEINIT, NULL);
+#endif
+#ifdef HAVE_WIFI
+ if ((flags & DRIVER_WIFI_MASK))
+ wifi_driver_ctl(RARCH_WIFI_CTL_DEINIT, NULL);
+#endif
+
+ if (flags & DRIVER_LED)
+ led_driver_free();
+
+ if (flags & DRIVERS_VIDEO_INPUT)
+ {
+ video_driver_free_internal();
+ VIDEO_DRIVER_LOCK_FREE(video_st);
+ video_st->data = NULL;
+ video_driver_set_cached_frame_ptr(NULL);
+ }
+
+ if (flags & DRIVER_AUDIO_MASK)
+ audio_driver_deinit();
+
+ if ((flags & DRIVER_VIDEO_MASK))
+ video_st->data = NULL;
+
+ if ((flags & DRIVER_INPUT_MASK))
+ input_state_get_ptr()->current_data = NULL;
+
+ if ((flags & DRIVER_AUDIO_MASK))
+ audio_state_get_ptr()->context_audio_data = NULL;
+
+ if (flags & DRIVER_MIDI_MASK)
+ midi_driver_free();
+
+#ifndef HAVE_LAKKA_SWITCH
+#ifdef HAVE_LAKKA
+ cpu_scaling_driver_free();
+#endif
+#endif /* #ifndef HAVE_LAKKA_SWITCH */
+}
+
+static void retroarch_deinit_drivers(struct retro_callbacks *cbs)
+{
+ input_driver_state_t *input_st = input_state_get_ptr();
+ video_driver_state_t *video_st = video_state_get_ptr();
+ camera_driver_state_t *camera_st= camera_state_get_ptr();
+ location_driver_state_t
+ *location_st = location_state_get_ptr();
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+#if defined(HAVE_GFX_WIDGETS)
+ /* Tear down display widgets no matter what
+ * in case the handle is lost in the threaded
+ * video driver in the meantime
+ * (breaking video_driver_has_widgets) */
+ dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
+ if (p_dispwidget->flags & DISPGFX_WIDGET_FLAG_INITED)
+ {
+ gfx_widgets_deinit(
+ p_dispwidget->flags & DISPGFX_WIDGET_FLAG_PERSISTING);
+ p_dispwidget->active = false;
+ }
+#endif
+
+#if defined(HAVE_CRTSWITCHRES)
+ /* Switchres deinit */
+ if (video_st->flags & VIDEO_FLAG_CRT_SWITCHING_ACTIVE)
+ crt_destroy_modes(&video_st->crt_switch_st);
+#endif
+
+ /* Video */
+ video_display_server_destroy();
+
+ video_st->flags &= ~(VIDEO_FLAG_ACTIVE | VIDEO_FLAG_USE_RGBA |
+ VIDEO_FLAG_HDR_SUPPORT | VIDEO_FLAG_CACHE_CONTEXT |
+ VIDEO_FLAG_CACHE_CONTEXT_ACK
+ );
+ video_st->record_gpu_buffer = NULL;
+ video_st->current_video = NULL;
+ video_driver_set_cached_frame_ptr(NULL);
+
+ /* Audio */
+ audio_state_get_ptr()->flags &= ~AUDIO_FLAG_ACTIVE;
+ audio_state_get_ptr()->current_audio = NULL;
+
+ if (input_st)
+ {
+ /* Input */
+ input_st->flags &= ~(INP_FLAG_KB_LINEFEED_ENABLE
+ | INP_FLAG_BLOCK_HOTKEY
+ | INP_FLAG_BLOCK_LIBRETRO_INPUT
+ | INP_FLAG_NONBLOCKING);
+
+ memset(&input_st->turbo_btns, 0, sizeof(turbo_buttons_t));
+ memset(&input_st->analog_requested, 0,
+ sizeof(input_st->analog_requested));
+ input_st->current_driver = NULL;
+ }
+
+#ifdef HAVE_MENU
+ menu_driver_destroy(
+ menu_state_get_ptr());
+#endif
+ location_st->active = false;
+ destroy_location();
+
+ /* Camera */
+ camera_st->active = false;
+ camera_st->driver = NULL;
+ camera_st->data = NULL;
+
+#ifdef HAVE_BLUETOOTH
+ bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DESTROY, NULL);
+#endif
+#ifdef HAVE_WIFI
+ wifi_driver_ctl(RARCH_WIFI_CTL_DESTROY, NULL);
+#endif
+
+ cbs->frame_cb = retro_frame_null;
+ cbs->poll_cb = retro_input_poll_null;
+ cbs->sample_cb = NULL;
+ cbs->sample_batch_cb = NULL;
+ cbs->state_cb = NULL;
+
+ runloop_st->current_core.flags &= ~RETRO_CORE_FLAG_INITED;
+}
+
+bool driver_ctl(enum driver_ctl_state state, void *data)
+{
+ driver_ctx_info_t *drv = (driver_ctx_info_t*)data;
+
+ switch (state)
+ {
+ case RARCH_DRIVER_CTL_SET_REFRESH_RATE:
+ {
+ float *hz = (float*)data;
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
+ settings_t *settings = config_get_ptr();
+ unsigned
+ audio_output_sample_rate = settings->uints.audio_output_sample_rate;
+ bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
+ float video_refresh_rate = settings->floats.video_refresh_rate;
+ float audio_max_timing_skew = settings->floats.audio_max_timing_skew;
+ bool video_adaptive_vsync = settings->bools.video_adaptive_vsync;
+ unsigned video_swap_interval = settings->uints.video_swap_interval;
+
+ video_monitor_set_refresh_rate(*hz);
+
+ /* Sets audio monitor rate to new value. */
+ audio_st->source_ratio_original =
+ audio_st->source_ratio_current =
+ (double)audio_output_sample_rate / audio_st->input;
+
+ driver_adjust_system_rates(
+ vrr_runloop_enable,
+ video_refresh_rate,
+ audio_max_timing_skew,
+ video_adaptive_vsync,
+ video_swap_interval
+ );
+ }
+ break;
+ case RARCH_DRIVER_CTL_FIND_FIRST:
+ if (!drv)
+ return false;
+ find_driver_nonempty(drv->label, 0, drv->s, drv->len);
+ break;
+ case RARCH_DRIVER_CTL_FIND_LAST:
+ if (!drv)
+ return false;
+ driver_find_last(drv->label, drv->s, drv->len);
+ break;
+ case RARCH_DRIVER_CTL_FIND_PREV:
+ if (!drv)
+ return false;
+ return driver_find_prev(drv->label, drv->s, drv->len);
+ case RARCH_DRIVER_CTL_FIND_NEXT:
+ if (!drv)
+ return false;
+ return driver_find_next(drv->label, drv->s, drv->len);
+ case RARCH_DRIVER_CTL_NONE:
+ default:
+ break;
+ }
+
+ return true;
+}
+
access_state_t *access_state_get_ptr(void)
{
return &access_state_st;