1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3  *  Copyright (C) 2011-2017 - Daniel De Matteis
4  *  Copyright (C) 2012-2015 - Michael Lelli
5  *  Copyright (C) 2014-2017 - Jean-Andr� Santoni
6  *  Copyright (C) 2016-2019 - Brad Parker
7  *  Copyright (C) 2016-2019 - Andr�s Su�rez (input mapper/Discord code)
8  *  Copyright (C) 2016-2017 - Gregor Richards (network code)
9  *
10  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
11  *  of the GNU General Public License as published by the Free Software Found-
12  *  ation, either version 3 of the License, or (at your option) any later version.
13  *
14  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16  *  PURPOSE.  See the GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License along with RetroArch.
19  *  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifdef _WIN32
23 #ifdef _XBOX
24 #include <xtl.h>
25 #else
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28 #endif
29 #if defined(DEBUG) && defined(HAVE_DRMINGW)
30 #include "exchndl.h"
31 #endif
32 #endif
33 
34 #if defined(DINGUX)
35 #include <sys/types.h>
36 #include <unistd.h>
37 #endif
38 
39 #if (defined(__linux__) || defined(__unix__) || defined(DINGUX)) && !defined(EMSCRIPTEN)
40 #include <signal.h>
41 #endif
42 
43 #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
44 #ifndef LEGACY_WIN32
45 #define LEGACY_WIN32
46 #endif
47 #endif
48 
49 #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
50 #include <objbase.h>
51 #include <process.h>
52 #endif
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <stdint.h>
58 #include <string.h>
59 #include <ctype.h>
60 #include <errno.h>
61 #include <setjmp.h>
62 #include <math.h>
63 #include <locale.h>
64 
65 #include <boolean.h>
66 #include <clamping.h>
67 #include <string/stdstring.h>
68 #include <dynamic/dylib.h>
69 #include <file/config_file.h>
70 #include <lists/string_list.h>
71 #include <memalign.h>
72 #include <retro_math.h>
73 #include <retro_timers.h>
74 #include <encodings/utf.h>
75 #include <time/rtime.h>
76 
77 #include <gfx/scaler/pixconv.h>
78 #include <gfx/scaler/scaler.h>
79 #include <gfx/video_frame.h>
80 #include <libretro.h>
81 #define VFS_FRONTEND
82 #include <vfs/vfs_implementation.h>
83 
84 #include <features/features_cpu.h>
85 
86 #include <compat/strl.h>
87 #include <compat/strcasestr.h>
88 #include <compat/getopt.h>
89 #include <audio/conversion/float_to_s16.h>
90 #include <audio/conversion/s16_to_float.h>
91 #ifdef HAVE_AUDIOMIXER
92 #include <audio/audio_mixer.h>
93 #endif
94 #ifdef HAVE_DSP_FILTER
95 #include <audio/dsp_filter.h>
96 #endif
97 #include <compat/posix_string.h>
98 #include <streams/file_stream.h>
99 #include <streams/interface_stream.h>
100 #include <file/file_path.h>
101 #include <retro_assert.h>
102 #include <retro_miscellaneous.h>
103 #include <queues/message_queue.h>
104 #include <queues/task_queue.h>
105 #include <lists/dir_list.h>
106 #ifdef HAVE_NETWORKING
107 #include <net/net_http.h>
108 #endif
109 
110 #ifdef WIIU
111 #include <wiiu/os/energy.h>
112 #endif
113 
114 #ifdef EMSCRIPTEN
115 #include <emscripten/emscripten.h>
116 #endif
117 
118 #ifdef HAVE_LIBNX
119 #include <switch.h>
120 #include "switch_performance_profiles.h"
121 #endif
122 
123 #if defined(ANDROID)
124 #include "play_feature_delivery/play_feature_delivery.h"
125 #endif
126 
127 #ifdef HAVE_DISCORD
128 #include <discord_rpc.h>
129 #include "deps/discord-rpc/include/discord_rpc.h"
130 #include "network/discord.h"
131 #endif
132 
133 #include "config.def.h"
134 #include "config.def.keybinds.h"
135 
136 #include "runtime_file.h"
137 
138 #ifdef HAVE_CONFIG_H
139 #include "config.h"
140 #endif
141 
142 #ifdef HAVE_NETWORKING
143 #include <net/net_compat.h>
144 #include <net/net_socket.h>
145 #endif
146 
147 #include <audio/audio_resampler.h>
148 
149 #include "gfx/gfx_animation.h"
150 #include "gfx/gfx_display.h"
151 #include "gfx/gfx_thumbnail.h"
152 #include "gfx/video_filter.h"
153 
154 #include "input/input_osk.h"
155 
156 #ifdef HAVE_MENU
157 #include "menu/menu_cbs.h"
158 #include "menu/menu_driver.h"
159 #include "menu/menu_input.h"
160 #include "menu/menu_dialog.h"
161 #include "menu/menu_input_bind_dialog.h"
162 #endif
163 
164 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
165 #include "menu/menu_shader.h"
166 #endif
167 
168 #ifdef HAVE_GFX_WIDGETS
169 #include "gfx/gfx_widgets.h"
170 #endif
171 
172 #include "input/input_keymaps.h"
173 #include "input/input_remapping.h"
174 
175 #ifdef HAVE_CHEEVOS
176 #include "cheevos/cheevos.h"
177 #include "cheevos/cheevos_menu.h"
178 #endif
179 
180 #ifdef HAVE_TRANSLATE
181 #include <encodings/base64.h>
182 #include <formats/rbmp.h>
183 #include <formats/rpng.h>
184 #include <formats/rjson.h>
185 #include "translation_defines.h"
186 #endif
187 
188 #ifdef HAVE_DISCORD
189 #include "network/discord.h"
190 #endif
191 
192 #ifdef HAVE_NETWORKING
193 #include "network/netplay/netplay.h"
194 #include "network/netplay/netplay_private.h"
195 #include "network/netplay/netplay_discovery.h"
196 #endif
197 
198 #ifdef HAVE_THREADS
199 #include <rthreads/rthreads.h>
200 #endif
201 
202 #if defined(HAVE_OPENGL)
203 #include "gfx/common/gl_common.h"
204 #elif defined(HAVE_OPENGL_CORE)
205 #include "gfx/common/gl_core_common.h"
206 #endif
207 
208 #include "autosave.h"
209 #include "command.h"
210 #include "config.features.h"
211 #include "cores/internal_cores.h"
212 #include "content.h"
213 #include "core_type.h"
214 #include "core_info.h"
215 #include "dynamic.h"
216 #include "defaults.h"
217 #include "driver.h"
218 #include "msg_hash.h"
219 #include "paths.h"
220 #include "file_path_special.h"
221 #include "ui/ui_companion_driver.h"
222 #include "verbosity.h"
223 
224 #include "frontend/frontend_driver.h"
225 #ifdef HAVE_THREADS
226 #include "gfx/video_thread_wrapper.h"
227 #endif
228 #include "gfx/video_display_server.h"
229 #ifdef HAVE_CRTSWITCHRES
230 #include "gfx/video_crt_switch.h"
231 #endif
232 #include "bluetooth/bluetooth_driver.h"
233 #include "wifi/wifi_driver.h"
234 #include "misc/cpufreq/cpufreq.h"
235 #include "led/led_driver.h"
236 #include "midi/midi_driver.h"
237 #include "core.h"
238 #include "configuration.h"
239 #include "list_special.h"
240 #include "core_option_manager.h"
241 #ifdef HAVE_CHEATS
242 #include "cheat_manager.h"
243 #endif
244 #ifdef HAVE_REWIND
245 #include "state_manager.h"
246 #endif
247 #ifdef HAVE_AUDIOMIXER
248 #include "tasks/task_audio_mixer.h"
249 #endif
250 #include "tasks/task_content.h"
251 #include "tasks/task_file_transfer.h"
252 #include "tasks/task_powerstate.h"
253 #include "tasks/tasks_internal.h"
254 #include "performance_counters.h"
255 
256 #include "version.h"
257 #include "version_git.h"
258 
259 #include "retroarch.h"
260 
261 #ifdef HAVE_ACCESSIBILITY
262 #include "accessibility.h"
263 #endif
264 
265 #ifdef HAVE_THREADS
266 #include "audio/audio_thread_wrapper.h"
267 #endif
268 
269 #ifdef HAVE_LANGEXTRA
270 /* This file has a UTF8 BOM, we assume HAVE_LANGEXTRA
271  * is only enabled for compilers that can support this. */
272 #include "input/input_osk_utf8_pages.h"
273 #endif
274 
275 #if defined(HAVE_SDL) || defined(HAVE_SDL2) || defined(HAVE_SDL_DINGUX)
276 #include "SDL.h"
277 #endif
278 
279 /* RetroArch global state / macros */
280 #include "retroarch_data.h"
281 /* Forward declarations */
282 #include "retroarch_fwd_decls.h"
283 
284 #ifdef HAVE_LAKKA
285 #include "lakka.h"
286 #endif
287 
288 static runloop_state_t runloop_state;
289 
290 /* GLOBAL POINTER GETTERS */
291 
292 #ifdef HAVE_NETWORKING
netplay_get_host_room(void)293 struct netplay_room* netplay_get_host_room(void)
294 {
295    struct rarch_state   *p_rarch  = &rarch_st;
296    return &p_rarch->netplay_host_room;
297 }
298 #endif
299 
300 #ifdef HAVE_REWIND
state_manager_frame_is_reversed(void)301 bool state_manager_frame_is_reversed(void)
302 {
303    struct rarch_state   *p_rarch  = &rarch_st;
304    struct state_manager_rewind_state
305                        *rewind_st = &p_rarch->rewind_st;
306    return rewind_st->frame_is_reversed;
307 }
308 #endif
309 
anim_get_ptr(void)310 gfx_animation_t *anim_get_ptr(void)
311 {
312    struct rarch_state   *p_rarch  = &rarch_st;
313    return &p_rarch->anim;
314 }
315 
content_state_get_ptr(void)316 content_state_t *content_state_get_ptr(void)
317 {
318    struct rarch_state   *p_rarch  = &rarch_st;
319    return &p_rarch->content_st;
320 }
321 
322 /* Get the current subsystem rom id */
content_get_subsystem_rom_id(void)323 unsigned content_get_subsystem_rom_id(void)
324 {
325    struct rarch_state *p_rarch   = &rarch_st;
326    content_state_t    *p_content = &p_rarch->content_st;
327    return p_content->pending_subsystem_rom_id;
328 }
329 
330 /* Get the current subsystem */
content_get_subsystem(void)331 int content_get_subsystem(void)
332 {
333    struct rarch_state *p_rarch   = &rarch_st;
334    content_state_t    *p_content = &p_rarch->content_st;
335    return p_content->pending_subsystem_id;
336 }
337 
input_event_get_osk_ptr(void)338 int input_event_get_osk_ptr(void)
339 {
340    struct rarch_state   *p_rarch  = &rarch_st;
341    return p_rarch->osk_ptr;
342 }
343 
input_event_get_osk_grid(void)344 char **input_event_get_osk_grid(void)
345 {
346    struct rarch_state   *p_rarch  = &rarch_st;
347    return p_rarch->osk_grid;
348 }
349 
coreinfo_get_ptr(void)350 core_info_state_t *coreinfo_get_ptr(void)
351 {
352    struct rarch_state   *p_rarch  = &rarch_st;
353    return &p_rarch->core_info_st;
354 }
355 
gfx_thumb_get_ptr(void)356 gfx_thumbnail_state_t *gfx_thumb_get_ptr(void)
357 {
358    struct rarch_state   *p_rarch  = &rarch_st;
359    return &p_rarch->gfx_thumb_state;
360 }
361 
362 #ifdef HAVE_MENU
menu_driver_get_ptr(void)363 menu_handle_t *menu_driver_get_ptr(void)
364 {
365    struct rarch_state   *p_rarch  = &rarch_st;
366    return p_rarch->menu_driver_data;
367 }
368 
menu_navigation_get_selection(void)369 size_t menu_navigation_get_selection(void)
370 {
371    struct rarch_state *p_rarch = &rarch_st;
372    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
373    return menu_st->selection_ptr;
374 }
375 #endif
376 
video_driver_get_hw_context(void)377 struct retro_hw_render_callback *video_driver_get_hw_context(void)
378 {
379    struct rarch_state *p_rarch = &rarch_st;
380    return VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
381 }
382 
video_viewport_get_system_av_info(void)383 struct retro_system_av_info *video_viewport_get_system_av_info(void)
384 {
385    struct rarch_state *p_rarch = &rarch_st;
386    return &p_rarch->video_driver_av_info;
387 }
388 
disp_get_ptr(void)389 gfx_display_t *disp_get_ptr(void)
390 {
391    struct rarch_state   *p_rarch  = &rarch_st;
392    return &p_rarch->dispgfx;
393 }
394 
395 #ifdef HAVE_GFX_WIDGETS
dispwidget_get_ptr(void)396 void *dispwidget_get_ptr(void)
397 {
398    struct rarch_state   *p_rarch  = &rarch_st;
399    return &p_rarch->dispwidget_st;
400 }
401 #endif
402 
config_get_ptr(void)403 settings_t *config_get_ptr(void)
404 {
405    struct rarch_state *p_rarch = &rarch_st;
406    return p_rarch->configuration_settings;
407 }
408 
global_get_ptr(void)409 global_t *global_get_ptr(void)
410 {
411    struct rarch_state *p_rarch = &rarch_st;
412    return &p_rarch->g_extern;
413 }
414 
415 #ifdef HAVE_THREADS
416 /**
417  * video_thread_get_ptr:
418  * @drv                       : Found driver.
419  *
420  * Gets the underlying video driver associated with the
421  * threaded video wrapper. Sets @drv to the found
422  * video driver.
423  *
424  * Returns: Video driver data of the video driver associated
425  * with the threaded wrapper (if successful). If not successful,
426  * NULL.
427  **/
video_thread_get_ptr(struct rarch_state * p_rarch)428 static void *video_thread_get_ptr(struct rarch_state *p_rarch)
429 {
430    const thread_video_t *thr   = (const thread_video_t*)p_rarch->video_driver_data;
431    if (thr)
432       return thr->driver_data;
433    return NULL;
434 }
435 #endif
436 
437 /**
438  * video_driver_get_ptr:
439  *
440  * Use this if you need the real video driver
441  * and driver data pointers.
442  *
443  * Returns: video driver's userdata.
444  **/
video_driver_get_ptr(void)445 void *video_driver_get_ptr(void)
446 {
447    struct rarch_state *p_rarch = &rarch_st;
448    return VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch);
449 }
450 
video_driver_get_data(void)451 void *video_driver_get_data(void)
452 {
453    struct rarch_state *p_rarch = &rarch_st;
454    return p_rarch->video_driver_data;
455 }
456 
input_state_wrap(input_driver_t * current_input,void * data,const input_device_driver_t * joypad,const input_device_driver_t * sec_joypad,rarch_joypad_info_t * joypad_info,const struct retro_keybind ** binds,bool keyboard_mapping_blocked,unsigned port,unsigned device,unsigned idx,unsigned id)457 static int16_t input_state_wrap(
458       input_driver_t *current_input,
459       void *data,
460       const input_device_driver_t *joypad,
461       const input_device_driver_t *sec_joypad,
462       rarch_joypad_info_t *joypad_info,
463       const struct retro_keybind **binds,
464       bool keyboard_mapping_blocked,
465       unsigned port,
466       unsigned device,
467       unsigned idx,
468       unsigned id)
469 {
470    int16_t ret                   = 0;
471 
472    /* Do a bitwise OR to combine input states together */
473 
474    if (device == RETRO_DEVICE_JOYPAD)
475    {
476       if (id == RETRO_DEVICE_ID_JOYPAD_MASK)
477       {
478          ret                       |= joypad->state(
479                joypad_info, binds[port], port);
480 #ifdef HAVE_MFI
481          if (sec_joypad)
482             ret                    |= sec_joypad->state(
483                   joypad_info, binds[port], port);
484 #endif
485       }
486       else
487       {
488          /* Do a bitwise OR to combine both input
489           * states together */
490          if (binds[port][id].valid)
491          {
492             /* Auto-binds are per joypad, not per user. */
493             const uint64_t bind_joykey     = binds[port][id].joykey;
494             const uint64_t bind_joyaxis    = binds[port][id].joyaxis;
495             const uint64_t autobind_joykey = joypad_info->auto_binds[id].joykey;
496             const uint64_t autobind_joyaxis= joypad_info->auto_binds[id].joyaxis;
497             uint16_t port                  = joypad_info->joy_idx;
498             float axis_threshold           = joypad_info->axis_threshold;
499             const uint64_t joykey          = (bind_joykey != NO_BTN)
500                ? bind_joykey  : autobind_joykey;
501             const uint32_t joyaxis         = (bind_joyaxis != AXIS_NONE)
502                ? bind_joyaxis : autobind_joyaxis;
503 
504             if ((uint16_t)joykey != NO_BTN && joypad->button(
505                      port, (uint16_t)joykey))
506                return 1;
507             if (joyaxis != AXIS_NONE &&
508                   ((float)abs(joypad->axis(port, joyaxis))
509                    / 0x8000) > axis_threshold)
510                return 1;
511 #ifdef HAVE_MFI
512             if ((uint16_t)joykey != NO_BTN && sec_joypad->button(
513                      port, (uint16_t)joykey))
514                return 1;
515             if (joyaxis != AXIS_NONE &&
516                   ((float)abs(sec_joypad->axis(port, joyaxis))
517                    / 0x8000) > axis_threshold)
518                return 1;
519 #endif
520          }
521       }
522    }
523 
524    if (current_input->input_state)
525       ret |= current_input->input_state(
526             data,
527             joypad,
528             sec_joypad,
529             joypad_info,
530             binds,
531             keyboard_mapping_blocked,
532             port,
533             device,
534             idx,
535             id);
536    return ret;
537 }
538 
539 /* DRIVERS */
540 
541 /**
542  * driver_find_index:
543  * @label              : string of driver type to be found.
544  * @drv                : identifier of driver to be found.
545  *
546  * Find index of the driver, based on @label.
547  *
548  * Returns: -1 if no driver based on @label and @drv found, otherwise
549  * index number of the driver found in the array.
550  **/
driver_find_index(const char * label,const char * drv)551 static int driver_find_index(const char *label, const char *drv)
552 {
553    unsigned i;
554    char str[256];
555 
556    str[0] = '\0';
557 
558    for (i = 0;
559          find_driver_nonempty(label, i, str, sizeof(str)) != NULL; i++)
560    {
561       if (string_is_empty(str))
562          break;
563       if (string_is_equal_noncase(drv, str))
564          return i;
565    }
566 
567    return -1;
568 }
569 
570 /**
571  * driver_find_last:
572  * @label              : string of driver type to be found.
573  * @s                  : identifier of driver to be found.
574  * @len                : size of @s.
575  *
576  * Find last driver in driver array.
577  **/
driver_find_last(const char * label,char * s,size_t len)578 static void driver_find_last(const char *label, char *s, size_t len)
579 {
580    unsigned i;
581 
582    for (i = 0;
583          find_driver_nonempty(label, i, s, len) != NULL; i++) { }
584 
585    if (i)
586       i = i - 1;
587    else
588       i = 0;
589 
590    find_driver_nonempty(label, i, s, len);
591 }
592 
593 /**
594  * driver_find_prev:
595  * @label              : string of driver type to be found.
596  * @s                  : identifier of driver to be found.
597  * @len                : size of @s.
598  *
599  * Find previous driver in driver array.
600  **/
driver_find_prev(const char * label,char * s,size_t len)601 static bool driver_find_prev(const char *label, char *s, size_t len)
602 {
603    int i = driver_find_index(label, s);
604 
605    if (i > 0)
606    {
607       find_driver_nonempty(label, i - 1, s, len);
608       return true;
609    }
610 
611    RARCH_WARN(
612          "Couldn't find any previous driver (current one: \"%s\").\n", s);
613    return false;
614 }
615 
616 /**
617  * driver_find_next:
618  * @label              : string of driver type to be found.
619  * @s                  : identifier of driver to be found.
620  * @len                : size of @s.
621  *
622  * Find next driver in driver array.
623  **/
driver_find_next(const char * label,char * s,size_t len)624 static bool driver_find_next(const char *label, char *s, size_t len)
625 {
626    int i = driver_find_index(label, s);
627 
628    if (i >= 0 && string_is_not_equal(s, "null"))
629    {
630       find_driver_nonempty(label, i + 1, s, len);
631       return true;
632    }
633 
634    RARCH_WARN("%s (current one: \"%s\").\n",
635          msg_hash_to_str(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER),
636          s);
637    return false;
638 }
639 
input_keyboard_mapping_bits(unsigned mode,unsigned key)640 void input_keyboard_mapping_bits(unsigned mode, unsigned key)
641 {
642    struct rarch_state *p_rarch    = &rarch_st;
643    switch (mode)
644    {
645       case 0:
646          BIT512_CLEAR_PTR(&p_rarch->keyboard_mapping_bits, key);
647          break;
648       case 1:
649          BIT512_SET_PTR(&p_rarch->keyboard_mapping_bits, key);
650          break;
651       default:
652          break;
653    }
654 }
655 
656 
657 #ifdef HAVE_MENU
menu_dialog_iterate(menu_dialog_t * p_dialog,char * s,size_t len,retro_time_t current_time)658 static int menu_dialog_iterate(
659       menu_dialog_t *p_dialog,
660       char *s, size_t len,
661       retro_time_t current_time)
662 {
663    switch (p_dialog->current_type)
664    {
665       case MENU_DIALOG_WELCOME:
666          {
667             static rarch_timer_t timer;
668 
669             if (!timer.timer_begin)
670             {
671                RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
672                      cpu_features_get_time_usec(),
673                      3 * 1000000);
674                timer.timer_begin = true;
675                timer.timer_end   = false;
676             }
677 
678             RARCH_TIMER_TICK(timer, current_time);
679 
680             msg_hash_get_help_enum(
681                   MENU_ENUM_LABEL_WELCOME_TO_RETROARCH,
682                   s, len);
683 
684             if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
685             {
686                RARCH_TIMER_END(timer);
687                p_dialog->current_type = MENU_DIALOG_NONE;
688                return 1;
689             }
690          }
691          break;
692       case MENU_DIALOG_HELP_CONTROLS:
693          {
694             unsigned i;
695             char s2[PATH_MAX_LENGTH];
696             const unsigned binds[] = {
697                RETRO_DEVICE_ID_JOYPAD_UP,
698                RETRO_DEVICE_ID_JOYPAD_DOWN,
699                RETRO_DEVICE_ID_JOYPAD_A,
700                RETRO_DEVICE_ID_JOYPAD_B,
701                RETRO_DEVICE_ID_JOYPAD_SELECT,
702                RETRO_DEVICE_ID_JOYPAD_START,
703                RARCH_MENU_TOGGLE,
704                RARCH_QUIT_KEY,
705                RETRO_DEVICE_ID_JOYPAD_X,
706                RETRO_DEVICE_ID_JOYPAD_Y,
707             };
708             char desc[ARRAY_SIZE(binds)][64];
709 
710             for (i = 0; i < ARRAY_SIZE(binds); i++)
711                desc[i][0] = '\0';
712 
713             for (i = 0; i < ARRAY_SIZE(binds); i++)
714             {
715                const struct retro_keybind *keybind = &input_config_binds[0][binds[i]];
716                const struct retro_keybind *auto_bind =
717                   (const struct retro_keybind*)
718                   input_config_get_bind_auto(0, binds[i]);
719 
720                input_config_get_bind_string(desc[i],
721                      keybind, auto_bind, sizeof(desc[i]));
722             }
723 
724             s2[0] = '\0';
725 
726             msg_hash_get_help_enum(
727                   MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG,
728                   s2, sizeof(s2));
729 
730             snprintf(s, len,
731                   "%s"
732                   "[%s]: "
733                   "%-20s\n"
734                   "[%s]: "
735                   "%-20s\n"
736                   "[%s]: "
737                   "%-20s\n"
738                   "[%s]: "
739                   "%-20s\n"
740                   "[%s]: "
741                   "%-20s\n"
742                   "[%s]: "
743                   "%-20s\n"
744                   "[%s]: "
745                   "%-20s\n"
746                   "[%s]: "
747                   "%-20s\n"
748                   "[%s]: "
749                   "%-20s\n",
750 
751                   s2,
752 
753                   msg_hash_to_str(
754                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP),
755                   desc[0],
756 
757                   msg_hash_to_str(
758                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN),
759                   desc[1],
760 
761                   msg_hash_to_str(
762                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM),
763                   desc[2],
764 
765                   msg_hash_to_str(
766                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK),
767                   desc[3],
768 
769                   msg_hash_to_str(
770                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO),
771                   desc[4],
772 
773                   msg_hash_to_str(
774                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START),
775                   desc[5],
776 
777                   msg_hash_to_str(
778                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU),
779                   desc[6],
780 
781                   msg_hash_to_str(
782                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT),
783                   desc[7],
784 
785                   msg_hash_to_str(
786                         MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD),
787                   desc[8]
788 
789                   );
790          }
791          break;
792 
793 #ifdef HAVE_CHEEVOS
794       case MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION:
795          if (!rcheevos_menu_get_sublabel(p_dialog->current_id, s, len))
796             return 1;
797          break;
798 #endif
799 
800       case MENU_DIALOG_HELP_WHAT_IS_A_CORE:
801          msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC,
802                s, len);
803          break;
804       case MENU_DIALOG_HELP_LOADING_CONTENT:
805          msg_hash_get_help_enum(MENU_ENUM_LABEL_LOAD_CONTENT_LIST,
806                s, len);
807          break;
808       case MENU_DIALOG_HELP_CHANGE_VIRTUAL_GAMEPAD:
809          msg_hash_get_help_enum(
810                MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC,
811                s, len);
812          break;
813       case MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING:
814          msg_hash_get_help_enum(
815                MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC,
816                s, len);
817          break;
818       case MENU_DIALOG_HELP_SEND_DEBUG_INFO:
819          msg_hash_get_help_enum(
820                MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO_DESC,
821                s, len);
822          break;
823       case MENU_DIALOG_HELP_SCANNING_CONTENT:
824          msg_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC,
825                s, len);
826          break;
827       case MENU_DIALOG_HELP_EXTRACT:
828          {
829             struct rarch_state *p_rarch = &rarch_st;
830             settings_t *settings        = p_rarch->configuration_settings;
831             bool bundle_finished        = settings->bools.bundle_finished;
832 
833             msg_hash_get_help_enum(
834                   MENU_ENUM_LABEL_VALUE_EXTRACTING_PLEASE_WAIT,
835                   s, len);
836 
837             if (bundle_finished)
838             {
839                configuration_set_bool(settings,
840                      settings->bools.bundle_finished, false);
841                p_dialog->current_type = MENU_DIALOG_NONE;
842                return 1;
843             }
844          }
845          break;
846       case MENU_DIALOG_QUIT_CONFIRM:
847       case MENU_DIALOG_INFORMATION:
848       case MENU_DIALOG_QUESTION:
849       case MENU_DIALOG_WARNING:
850       case MENU_DIALOG_ERROR:
851          msg_hash_get_help_enum(MSG_UNKNOWN,
852                s, len);
853          break;
854       case MENU_DIALOG_NONE:
855       default:
856          break;
857    }
858 
859    return 0;
860 }
861 
menu_dialog_unset_pending_push(void)862 void menu_dialog_unset_pending_push(void)
863 {
864    struct rarch_state   *p_rarch  = &rarch_st;
865    menu_dialog_t        *p_dialog = &p_rarch->dialog_st;
866 
867    p_dialog->pending_push  = false;
868 }
869 
menu_dialog_push_pending(enum menu_dialog_type type)870 void menu_dialog_push_pending(enum menu_dialog_type type)
871 {
872    struct rarch_state   *p_rarch  = &rarch_st;
873    menu_dialog_t        *p_dialog = &p_rarch->dialog_st;
874    p_dialog->current_type         = type;
875    p_dialog->pending_push         = true;
876 }
877 
menu_dialog_set_current_id(unsigned id)878 void menu_dialog_set_current_id(unsigned id)
879 {
880    struct rarch_state   *p_rarch  = &rarch_st;
881    menu_dialog_t        *p_dialog = &p_rarch->dialog_st;
882 
883    p_dialog->current_id    = id;
884 }
885 
menu_input_key_bind_custom_bind_keyboard_cb(void * data,unsigned code)886 static bool menu_input_key_bind_custom_bind_keyboard_cb(
887       void *data, unsigned code)
888 {
889    uint64_t current_usec;
890    struct rarch_state *p_rarch    = &rarch_st;
891    settings_t     *settings       = p_rarch->configuration_settings;
892    struct menu_bind_state *binds  = &p_rarch->menu_input_binds;
893    uint64_t input_bind_hold_us    = settings->uints.input_bind_hold    * 1000000;
894    uint64_t input_bind_timeout_us = settings->uints.input_bind_timeout * 1000000;
895 
896    /* Clear old mapping bit */
897    BIT512_CLEAR_PTR(&p_rarch->keyboard_mapping_bits, binds->buffer.key);
898 
899    /* store key in bind */
900    binds->buffer.key = (enum retro_key)code;
901 
902    /* Store new mapping bit */
903    BIT512_SET_PTR(&p_rarch->keyboard_mapping_bits, binds->buffer.key);
904 
905    /* write out the bind */
906    *(binds->output)  = binds->buffer;
907 
908    /* next bind */
909    binds->begin++;
910    binds->output++;
911    binds->buffer    =* (binds->output);
912 
913    current_usec     = cpu_features_get_time_usec();
914 
915    RARCH_TIMER_BEGIN_NEW_TIME_USEC(
916          binds->timer_hold,
917          current_usec,
918          input_bind_hold_us);
919    RARCH_TIMER_BEGIN_NEW_TIME_USEC(
920          binds->timer_timeout,
921          current_usec, input_bind_timeout_us);
922 
923    return (binds->begin <= binds->last);
924 }
925 
menu_input_key_bind_set_mode_common(struct menu_state * menu_st,struct menu_bind_state * binds,enum menu_input_binds_ctl_state state,rarch_setting_t * setting,settings_t * settings)926 static int menu_input_key_bind_set_mode_common(
927       struct menu_state *menu_st,
928       struct menu_bind_state *binds,
929       enum menu_input_binds_ctl_state state,
930       rarch_setting_t  *setting,
931       settings_t *settings)
932 {
933    menu_displaylist_info_t info;
934    unsigned bind_type             = 0;
935    struct retro_keybind *keybind  = NULL;
936    unsigned         index_offset  = setting->index_offset;
937    menu_list_t *menu_list         = menu_st->entries.list;
938    file_list_t *menu_stack        = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL;
939    size_t selection               = menu_st->selection_ptr;
940 
941    menu_displaylist_info_init(&info);
942 
943    switch (state)
944    {
945       case MENU_INPUT_BINDS_CTL_BIND_SINGLE:
946          keybind                  = (struct retro_keybind*)setting->value.target.keybind;
947 
948          if (!keybind)
949             return -1;
950 
951          bind_type                = setting_get_bind_type(setting);
952 
953          binds->begin             = bind_type;
954          binds->last              = bind_type;
955          binds->output            = keybind;
956          binds->buffer            = *(binds->output);
957          binds->user              = index_offset;
958 
959          info.list                = menu_stack;
960          info.type                = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD;
961          info.directory_ptr       = selection;
962          info.enum_idx            = MENU_ENUM_LABEL_CUSTOM_BIND;
963          info.label               = strdup(
964                msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND));
965          break;
966       case MENU_INPUT_BINDS_CTL_BIND_ALL:
967          binds->output            = &input_config_binds[index_offset][0];
968          binds->buffer            = *(binds->output);
969          binds->begin             = MENU_SETTINGS_BIND_BEGIN;
970          binds->last              = MENU_SETTINGS_BIND_LAST;
971 
972          info.list                = menu_stack;
973          info.type                = MENU_SETTINGS_CUSTOM_BIND_KEYBOARD;
974          info.directory_ptr       = selection;
975          info.enum_idx            = MENU_ENUM_LABEL_CUSTOM_BIND_ALL;
976          info.label               = strdup(
977                msg_hash_to_str(MENU_ENUM_LABEL_CUSTOM_BIND_ALL));
978          break;
979       default:
980       case MENU_INPUT_BINDS_CTL_BIND_NONE:
981          return 0;
982    }
983 
984    if (menu_displaylist_ctl(DISPLAYLIST_INFO, &info, settings))
985       menu_displaylist_process(&info);
986    menu_displaylist_info_free(&info);
987 
988    return 0;
989 }
990 
menu_input_key_bind_poll_bind_get_rested_axes(const input_device_driver_t * joypad,const input_device_driver_t * sec_joypad,struct menu_bind_state * state)991 static void menu_input_key_bind_poll_bind_get_rested_axes(
992       const input_device_driver_t *joypad,
993       const input_device_driver_t *sec_joypad,
994       struct menu_bind_state *state)
995 {
996    unsigned a;
997    unsigned port                           = state->port;
998 
999    if (joypad)
1000    {
1001       /* poll only the relevant port */
1002       for (a = 0; a < MENU_MAX_AXES; a++)
1003       {
1004          if (AXIS_POS(a) != AXIS_NONE)
1005             state->axis_state[port].rested_axes[a]  =
1006                joypad->axis(port, AXIS_POS(a));
1007          if (AXIS_NEG(a) != AXIS_NONE)
1008             state->axis_state[port].rested_axes[a] +=
1009                joypad->axis(port, AXIS_NEG(a));
1010       }
1011    }
1012 
1013    if (sec_joypad)
1014    {
1015       /* poll only the relevant port */
1016       for (a = 0; a < MENU_MAX_AXES; a++)
1017       {
1018          if (AXIS_POS(a) != AXIS_NONE)
1019             state->axis_state[port].rested_axes[a]  = sec_joypad->axis(port, AXIS_POS(a));
1020 
1021          if (AXIS_NEG(a) != AXIS_NONE)
1022             state->axis_state[port].rested_axes[a] += sec_joypad->axis(port, AXIS_NEG(a));
1023       }
1024    }
1025 }
1026 
menu_input_key_bind_poll_bind_state_internal(const input_device_driver_t * joypad,struct menu_bind_state * state,unsigned port,bool timed_out)1027 static void menu_input_key_bind_poll_bind_state_internal(
1028       const input_device_driver_t *joypad,
1029       struct menu_bind_state *state,
1030       unsigned port,
1031       bool timed_out)
1032 {
1033    unsigned i;
1034 
1035    /* poll only the relevant port */
1036    for (i = 0; i < MENU_MAX_BUTTONS; i++)
1037       state->state[port].buttons[i] = joypad->button(port, i);
1038 
1039    for (i = 0; i < MENU_MAX_AXES; i++)
1040    {
1041       if (AXIS_POS(i) != AXIS_NONE)
1042          state->state[port].axes[i]  = joypad->axis(port, AXIS_POS(i));
1043 
1044       if (AXIS_NEG(i) != AXIS_NONE)
1045          state->state[port].axes[i] += joypad->axis(port, AXIS_NEG(i));
1046    }
1047 
1048    for (i = 0; i < MENU_MAX_HATS; i++)
1049    {
1050       if (joypad->button(port, HAT_MAP(i, HAT_UP_MASK)))
1051          state->state[port].hats[i] |= HAT_UP_MASK;
1052       if (joypad->button(port, HAT_MAP(i, HAT_DOWN_MASK)))
1053          state->state[port].hats[i] |= HAT_DOWN_MASK;
1054       if (joypad->button(port, HAT_MAP(i, HAT_LEFT_MASK)))
1055          state->state[port].hats[i] |= HAT_LEFT_MASK;
1056       if (joypad->button(port, HAT_MAP(i, HAT_RIGHT_MASK)))
1057          state->state[port].hats[i] |= HAT_RIGHT_MASK;
1058    }
1059 }
1060 
menu_input_key_bind_poll_bind_state(struct rarch_state * p_rarch,unsigned joy_idx,struct menu_bind_state * state,bool timed_out)1061 static void menu_input_key_bind_poll_bind_state(
1062       struct rarch_state *p_rarch,
1063       unsigned joy_idx,
1064       struct menu_bind_state *state,
1065       bool timed_out)
1066 {
1067    unsigned b;
1068    rarch_joypad_info_t joypad_info;
1069    input_driver_t *current_input           = p_rarch->current_input;
1070    void *input_data                        = p_rarch->current_input_data;
1071    unsigned port                           = state->port;
1072    const input_device_driver_t *joypad     = p_rarch->joypad;
1073 #ifdef HAVE_MFI
1074    const input_device_driver_t *sec_joypad = p_rarch->sec_joypad;
1075 #else
1076    const input_device_driver_t *sec_joypad = NULL;
1077 #endif
1078 
1079    memset(state->state, 0, sizeof(state->state));
1080 
1081    /* Poll mouse (on the relevant port) */
1082    for (b = 0; b < MENU_MAX_MBUTTONS; b++)
1083       state->state[port].mouse_buttons[b] =
1084          input_mouse_button_raw(p_rarch, current_input, joy_idx, port, b);
1085 
1086    joypad_info.joy_idx        = 0;
1087    joypad_info.auto_binds     = NULL;
1088    joypad_info.axis_threshold = 0.0f;
1089 
1090    state->skip                = timed_out;
1091    if (current_input->input_state)
1092       state->skip             |=
1093          current_input->input_state(
1094                input_data,
1095                joypad,
1096                sec_joypad,
1097                &joypad_info,
1098                NULL,
1099                p_rarch->keyboard_mapping_blocked,
1100                0,
1101                RETRO_DEVICE_KEYBOARD,
1102                0,
1103                RETROK_RETURN);
1104 
1105    if (joypad)
1106    {
1107       if (joypad->poll)
1108          joypad->poll();
1109       menu_input_key_bind_poll_bind_state_internal(
1110             joypad, state, port, timed_out);
1111    }
1112 
1113    if (sec_joypad)
1114    {
1115       if (sec_joypad->poll)
1116          sec_joypad->poll();
1117       menu_input_key_bind_poll_bind_state_internal(
1118             sec_joypad, state, port, timed_out);
1119    }
1120 }
1121 
menu_input_key_bind_poll_find_trigger_pad(struct menu_bind_state * state,struct menu_bind_state * new_state,struct retro_keybind * output,unsigned p)1122 static bool menu_input_key_bind_poll_find_trigger_pad(
1123       struct menu_bind_state *state,
1124       struct menu_bind_state *new_state,
1125      struct retro_keybind * output,
1126       unsigned p)
1127 {
1128    unsigned a, b, h;
1129    const struct menu_bind_state_port *n = (const struct menu_bind_state_port*)
1130       &new_state->state[p];
1131    const struct menu_bind_state_port *o = (const struct menu_bind_state_port*)
1132       &state->state[p];
1133 
1134    for (b = 0; b < MENU_MAX_MBUTTONS; b++)
1135    {
1136       bool iterate = n->mouse_buttons[b] && !o->mouse_buttons[b];
1137 
1138       if (!iterate)
1139          continue;
1140 
1141       switch (b)
1142       {
1143          case RETRO_DEVICE_ID_MOUSE_LEFT:
1144          case RETRO_DEVICE_ID_MOUSE_RIGHT:
1145          case RETRO_DEVICE_ID_MOUSE_MIDDLE:
1146          case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
1147          case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
1148          case RETRO_DEVICE_ID_MOUSE_WHEELUP:
1149          case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
1150          case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
1151          case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
1152             output->mbutton = b;
1153             return true;
1154       }
1155    }
1156 
1157    for (b = 0; b < MENU_MAX_BUTTONS; b++)
1158    {
1159       bool iterate = n->buttons[b] && !o->buttons[b];
1160 
1161       if (!iterate)
1162          continue;
1163 
1164       output->joykey = b;
1165       output->joyaxis = AXIS_NONE;
1166       return true;
1167    }
1168 
1169    /* Axes are a bit tricky ... */
1170    for (a = 0; a < MENU_MAX_AXES; a++)
1171    {
1172       int locked_distance = abs(n->axes[a] -
1173             new_state->axis_state[p].locked_axes[a]);
1174       int rested_distance = abs(n->axes[a] -
1175             new_state->axis_state[p].rested_axes[a]);
1176 
1177       if (abs(n->axes[a]) >= 20000 &&
1178             locked_distance >= 20000 &&
1179             rested_distance >= 20000)
1180       {
1181          /* Take care of case where axis rests on +/- 0x7fff
1182           * (e.g. 360 controller on Linux) */
1183          output->joyaxis = n->axes[a] > 0
1184             ? AXIS_POS(a) : AXIS_NEG(a);
1185          output->joykey = NO_BTN;
1186 
1187          /* Lock the current axis */
1188          new_state->axis_state[p].locked_axes[a] =
1189             n->axes[a] > 0 ?
1190             0x7fff : -0x7fff;
1191          return true;
1192       }
1193 
1194       if (locked_distance >= 20000) /* Unlock the axis. */
1195          new_state->axis_state[p].locked_axes[a] = 0;
1196    }
1197 
1198    for (h = 0; h < MENU_MAX_HATS; h++)
1199    {
1200       uint16_t      trigged = n->hats[h] & (~o->hats[h]);
1201       uint16_t sane_trigger = 0;
1202 
1203       if (trigged & HAT_UP_MASK)
1204          sane_trigger = HAT_UP_MASK;
1205       else if (trigged & HAT_DOWN_MASK)
1206          sane_trigger = HAT_DOWN_MASK;
1207       else if (trigged & HAT_LEFT_MASK)
1208          sane_trigger = HAT_LEFT_MASK;
1209       else if (trigged & HAT_RIGHT_MASK)
1210          sane_trigger = HAT_RIGHT_MASK;
1211 
1212       if (sane_trigger)
1213       {
1214          output->joykey = HAT_MAP(h, sane_trigger);
1215          output->joyaxis = AXIS_NONE;
1216          return true;
1217       }
1218    }
1219 
1220    return false;
1221 }
1222 
1223 #ifdef ANDROID
menu_input_key_bind_poll_find_hold_pad(struct menu_bind_state * new_state,struct retro_keybind * output,unsigned p)1224 static bool menu_input_key_bind_poll_find_hold_pad(
1225       struct menu_bind_state *new_state,
1226      struct retro_keybind * output,
1227       unsigned p)
1228 {
1229    unsigned a, b, h;
1230    const struct menu_bind_state_port *n =
1231       (const struct menu_bind_state_port*)
1232       &new_state->state[p];
1233 
1234    for (b = 0; b < MENU_MAX_MBUTTONS; b++)
1235    {
1236       bool iterate = n->mouse_buttons[b];
1237 
1238       if (!iterate)
1239          continue;
1240 
1241       switch (b)
1242       {
1243          case RETRO_DEVICE_ID_MOUSE_LEFT:
1244          case RETRO_DEVICE_ID_MOUSE_RIGHT:
1245          case RETRO_DEVICE_ID_MOUSE_MIDDLE:
1246          case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
1247          case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
1248          case RETRO_DEVICE_ID_MOUSE_WHEELUP:
1249          case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
1250          case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
1251          case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
1252             output->mbutton = b;
1253             return true;
1254       }
1255    }
1256 
1257    for (b = 0; b < MENU_MAX_BUTTONS; b++)
1258    {
1259       bool iterate = n->buttons[b];
1260 
1261       if (!iterate)
1262          continue;
1263 
1264       output->joykey = b;
1265       output->joyaxis = AXIS_NONE;
1266       return true;
1267    }
1268 
1269    /* Axes are a bit tricky ... */
1270    for (a = 0; a < MENU_MAX_AXES; a++)
1271    {
1272       if (abs(n->axes[a]) >= 20000)
1273       {
1274          /* Take care of case where axis rests on +/- 0x7fff
1275           * (e.g. 360 controller on Linux) */
1276          output->joyaxis = n->axes[a] > 0
1277             ? AXIS_POS(a) : AXIS_NEG(a);
1278          output->joykey = NO_BTN;
1279 
1280          return true;
1281       }
1282    }
1283 
1284    for (h = 0; h < MENU_MAX_HATS; h++)
1285    {
1286       uint16_t      trigged = n->hats[h];
1287       uint16_t sane_trigger = 0;
1288 
1289       if (trigged & HAT_UP_MASK)
1290          sane_trigger = HAT_UP_MASK;
1291       else if (trigged & HAT_DOWN_MASK)
1292          sane_trigger = HAT_DOWN_MASK;
1293       else if (trigged & HAT_LEFT_MASK)
1294          sane_trigger = HAT_LEFT_MASK;
1295       else if (trigged & HAT_RIGHT_MASK)
1296          sane_trigger = HAT_RIGHT_MASK;
1297 
1298       if (sane_trigger)
1299       {
1300          output->joykey  = HAT_MAP(h, sane_trigger);
1301          output->joyaxis = AXIS_NONE;
1302          return true;
1303       }
1304    }
1305 
1306    return false;
1307 }
1308 #endif
1309 
menu_input_key_bind_poll_find_trigger(unsigned max_users,struct menu_bind_state * state,struct menu_bind_state * new_state,struct retro_keybind * output)1310 static bool menu_input_key_bind_poll_find_trigger(
1311       unsigned max_users,
1312       struct menu_bind_state *state,
1313       struct menu_bind_state *new_state,
1314       struct retro_keybind * output)
1315 {
1316    if (state && new_state)
1317    {
1318       unsigned i;
1319 
1320       for (i = 0; i < max_users; i++)
1321       {
1322          if (menu_input_key_bind_poll_find_trigger_pad(
1323                   state, new_state, output, i))
1324             return true;
1325       }
1326    }
1327 
1328    return false;
1329 }
1330 
1331 #ifdef ANDROID
menu_input_key_bind_poll_find_hold(unsigned max_users,struct menu_bind_state * new_state,struct retro_keybind * output)1332 static bool menu_input_key_bind_poll_find_hold(
1333       unsigned max_users,
1334       struct menu_bind_state *new_state,
1335       struct retro_keybind * output)
1336 {
1337    if (new_state)
1338    {
1339       unsigned i;
1340 
1341       for (i = 0; i < max_users; i++)
1342       {
1343          if (menu_input_key_bind_poll_find_hold_pad(new_state, output, i))
1344             return true;
1345       }
1346    }
1347 
1348    return false;
1349 }
1350 #endif
1351 
menu_input_key_bind_set_mode(enum menu_input_binds_ctl_state state,void * data)1352 bool menu_input_key_bind_set_mode(
1353       enum menu_input_binds_ctl_state state, void *data)
1354 {
1355    uint64_t current_usec;
1356    unsigned index_offset;
1357    rarch_setting_t  *setting      = (rarch_setting_t*)data;
1358    struct rarch_state *p_rarch    = &rarch_st;
1359    menu_handle_t       *menu      = p_rarch->menu_driver_data;
1360    menu_input_t *menu_input       = &p_rarch->menu_input_state;
1361    settings_t     *settings       = p_rarch->configuration_settings;
1362    struct menu_bind_state *binds  = &p_rarch->menu_input_binds;
1363    uint64_t input_bind_hold_us    = settings->uints.input_bind_hold
1364       * 1000000;
1365    uint64_t input_bind_timeout_us = settings->uints.input_bind_timeout
1366       * 1000000;
1367 
1368    if (!setting || !menu)
1369       return false;
1370    if (menu_input_key_bind_set_mode_common(&p_rarch->menu_driver_state,
1371             binds, state, setting, settings) == -1)
1372       return false;
1373 
1374    index_offset             = setting->index_offset;
1375    binds->port              = settings->uints.input_joypad_index[index_offset];
1376 
1377    menu_input_key_bind_poll_bind_get_rested_axes(
1378          p_rarch->joypad,
1379 #ifdef HAVE_MFI
1380          p_rarch->sec_joypad,
1381 #else
1382          NULL,
1383 #endif
1384          binds);
1385    menu_input_key_bind_poll_bind_state(p_rarch, settings->uints.input_joypad_index[binds->port],
1386          binds, false);
1387 
1388    current_usec             = cpu_features_get_time_usec();
1389 
1390    RARCH_TIMER_BEGIN_NEW_TIME_USEC(
1391          binds->timer_hold,
1392          current_usec,
1393          input_bind_hold_us);
1394    RARCH_TIMER_BEGIN_NEW_TIME_USEC(
1395          binds->timer_timeout,
1396          current_usec,
1397          input_bind_timeout_us);
1398 
1399    p_rarch->keyboard_press_cb         =
1400       menu_input_key_bind_custom_bind_keyboard_cb;
1401    p_rarch->keyboard_press_data       = menu;
1402 
1403    /* While waiting for input, we have to block all hotkeys. */
1404    p_rarch->keyboard_mapping_blocked  = true;
1405 
1406    /* Upon triggering an input bind operation,
1407     * pointer input must be inhibited - otherwise
1408     * attempting to bind mouse buttons will cause
1409     * spurious menu actions */
1410    menu_input->select_inhibit         = true;
1411    menu_input->cancel_inhibit         = true;
1412 
1413    return true;
1414 }
1415 
menu_input_key_bind_set_min_max(menu_input_ctx_bind_limits_t * lim)1416 bool menu_input_key_bind_set_min_max(menu_input_ctx_bind_limits_t *lim)
1417 {
1418    struct rarch_state *p_rarch    = &rarch_st;
1419    struct menu_bind_state *binds  = &p_rarch->menu_input_binds;
1420    if (!lim)
1421       return false;
1422 
1423    binds->begin = lim->min;
1424    binds->last  = lim->max;
1425 
1426    return true;
1427 }
1428 
menu_input_key_bind_iterate(struct rarch_state * p_rarch,settings_t * settings,menu_input_ctx_bind_t * bind,retro_time_t current_time)1429 static bool menu_input_key_bind_iterate(
1430       struct rarch_state *p_rarch,
1431       settings_t *settings,
1432       menu_input_ctx_bind_t *bind,
1433       retro_time_t current_time)
1434 {
1435    bool               timed_out   = false;
1436    struct menu_bind_state *_binds = &p_rarch->menu_input_binds;
1437    menu_input_t *menu_input       = &p_rarch->menu_input_state;
1438    struct menu_state *menu_st     = &p_rarch->menu_driver_state;
1439    uint64_t input_bind_hold_us    = settings->uints.input_bind_hold * 1000000;
1440    uint64_t input_bind_timeout_us = settings->uints.input_bind_timeout * 1000000;
1441 
1442    snprintf(bind->s, bind->len,
1443          "[%s]\nPress keyboard, mouse or joypad\n(Timeout %d %s)",
1444          input_config_bind_map_get_desc(
1445             _binds->begin - MENU_SETTINGS_BIND_BEGIN),
1446          RARCH_TIMER_GET_TIMEOUT(_binds->timer_timeout),
1447          msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SECONDS));
1448 
1449    /* Tick main timers */
1450    RARCH_TIMER_TICK(_binds->timer_timeout, current_time);
1451    RARCH_TIMER_TICK(_binds->timer_hold, current_time);
1452 
1453    if (RARCH_TIMER_HAS_EXPIRED(_binds->timer_timeout))
1454    {
1455       uint64_t current_usec = cpu_features_get_time_usec();
1456 
1457       p_rarch->keyboard_mapping_blocked = false;
1458 
1459       /*skip to next bind*/
1460       _binds->begin++;
1461       _binds->output++;
1462       RARCH_TIMER_BEGIN_NEW_TIME_USEC(_binds->timer_hold,
1463             current_usec,
1464             input_bind_hold_us);
1465       RARCH_TIMER_BEGIN_NEW_TIME_USEC(_binds->timer_timeout,
1466             current_usec,
1467             input_bind_timeout_us);
1468       timed_out = true;
1469    }
1470 
1471    /* binds.begin is updated in keyboard_press callback. */
1472    if (_binds->begin > _binds->last)
1473    {
1474       /* Avoid new binds triggering things right away. */
1475       /* Inhibits input for 2 frames
1476        * > Required, since input is ignored for 1 frame
1477        *   after certain events - e.g. closing the OSK */
1478       p_rarch->input_driver_flushing_input = 2;
1479 
1480       /* We won't be getting any key events, so just cancel early. */
1481       if (timed_out)
1482       {
1483          p_rarch->keyboard_press_cb        = NULL;
1484          p_rarch->keyboard_press_data      = NULL;
1485          p_rarch->keyboard_mapping_blocked = false;
1486       }
1487 
1488       return true;
1489    }
1490 
1491    {
1492       bool complete                        = false;
1493       struct menu_bind_state new_binds     = *_binds;
1494 
1495       p_rarch->keyboard_mapping_blocked    = false;
1496 
1497       menu_input_key_bind_poll_bind_state(p_rarch,
1498             settings->uints.input_joypad_index[new_binds.port],
1499             &new_binds, timed_out);
1500 
1501 #ifdef ANDROID
1502       /* Keep resetting bind during the hold period,
1503        * or we'll potentially bind joystick and mouse, etc.*/
1504       new_binds.buffer                     = *(new_binds.output);
1505 
1506       if (menu_input_key_bind_poll_find_hold(
1507                p_rarch->input_driver_max_users,
1508                &new_binds, &new_binds.buffer))
1509       {
1510          uint64_t current_usec = cpu_features_get_time_usec();
1511          /* Inhibit timeout*/
1512          RARCH_TIMER_BEGIN_NEW_TIME_USEC(
1513                new_binds.timer_timeout,
1514                current_usec,
1515                input_bind_timeout_us);
1516 
1517          /* Run hold timer*/
1518          RARCH_TIMER_TICK(new_binds.timer_hold, current_time);
1519 
1520          snprintf(bind->s, bind->len,
1521                "[%s]\npress keyboard, mouse or joypad\nand hold ...",
1522                input_config_bind_map_get_desc(
1523                   _binds->begin - MENU_SETTINGS_BIND_BEGIN));
1524 
1525          /* Hold complete? */
1526          if (RARCH_TIMER_HAS_EXPIRED(new_binds.timer_hold))
1527             complete = true;
1528       }
1529       else
1530       {
1531          uint64_t current_usec = cpu_features_get_time_usec();
1532 
1533          /* Reset hold countdown*/
1534          RARCH_TIMER_BEGIN_NEW_TIME_USEC(new_binds.timer_hold,
1535                current_usec,
1536                input_bind_hold_us);
1537       }
1538 #else
1539       if ((new_binds.skip && !_binds->skip) ||
1540             menu_input_key_bind_poll_find_trigger(
1541                p_rarch->input_driver_max_users,
1542                _binds, &new_binds, &(new_binds.buffer)))
1543          complete = true;
1544 #endif
1545 
1546       if (complete)
1547       {
1548          uint64_t current_usec        = cpu_features_get_time_usec();
1549          /* Update bind */
1550          *(new_binds.output)          = new_binds.buffer;
1551 
1552          p_rarch->keyboard_mapping_blocked      = false;
1553 
1554          /* Avoid new binds triggering things right away. */
1555          /* Inhibits input for 2 frames
1556           * > Required, since input is ignored for 1 frame
1557           *   after certain events - e.g. closing the OSK */
1558          p_rarch->input_driver_flushing_input = 2;
1559 
1560          new_binds.begin++;
1561 
1562          if (new_binds.begin > new_binds.last)
1563          {
1564             p_rarch->keyboard_press_cb                       = NULL;
1565             p_rarch->keyboard_press_data                     = NULL;
1566             p_rarch->keyboard_mapping_blocked                = false;
1567             return true;
1568          }
1569 
1570          /*next bind*/
1571          new_binds.output++;
1572          new_binds.buffer = *(new_binds.output);
1573          RARCH_TIMER_BEGIN_NEW_TIME_USEC(new_binds.timer_hold,
1574                current_usec, input_bind_hold_us);
1575          RARCH_TIMER_BEGIN_NEW_TIME_USEC(new_binds.timer_timeout,
1576                current_usec, input_bind_timeout_us);
1577       }
1578 
1579       *(_binds) = new_binds;
1580    }
1581 
1582    /* Pointer input must be inhibited on each
1583     * frame that the bind operation is active -
1584     * otherwise attempting to bind mouse buttons
1585     * will cause spurious menu actions */
1586    menu_input->select_inhibit     = true;
1587    menu_input->cancel_inhibit     = true;
1588 
1589    /* Menu screensaver should be inhibited on each
1590     * frame that the bind operation is active */
1591    menu_st->input_last_time_us    = menu_st->current_time_us;
1592 
1593    return false;
1594 }
1595 
1596 /* This sets up all the callback functions for a menu entry.
1597  *
1598  * OK     : When we press the 'OK' button on an entry.
1599  * Cancel : When we press the 'Cancel' button on an entry.
1600  * Scan   : When we press the 'Scan' button on an entry.
1601  * Start  : When we press the 'Start' button on an entry.
1602  * Select : When we press the 'Select' button on an entry.
1603  * Info   : When we press the 'Info' button on an entry.
1604  * Content Switch   : ??? (TODO/FIXME - Kivutar should document this)
1605  * Up     : when we press 'Up' on the D-pad while this entry is selected.
1606  * Down   : when we press 'Down' on the D-pad while this entry is selected.
1607  * Left   : when we press 'Left' on the D-pad while this entry is selected.
1608  * Right  : when we press 'Right' on the D-pad while this entry is selected.
1609  * Deferred push : When pressing an entry results in spawning a new list, it waits until the next
1610  * frame to push this onto the stack. This function callback will then be invoked.
1611  * Refresh : What happens when the screen has to be refreshed. Does an entry have internal state
1612  * that needs to be rebuild?
1613  * Get value: Each entry has associated 'text', which we call the value. This function callback
1614  * lets us render that text.
1615  * Get title: Each entry can have a custom 'title'.
1616  * Label: Each entry has a label name. This function callback lets us render that label text.
1617  * Sublabel: each entry has a sublabel, which consists of one or more lines of additional information.
1618  * This function callback lets us render that text.
1619  */
menu_cbs_init(struct menu_state * menu_st,const menu_ctx_driver_t * menu_driver_ctx,file_list_t * list,menu_file_list_cbs_t * cbs,const char * path,const char * label,unsigned type,size_t idx)1620 static void menu_cbs_init(
1621       struct menu_state *menu_st,
1622       const menu_ctx_driver_t *menu_driver_ctx,
1623       file_list_t *list,
1624       menu_file_list_cbs_t *cbs,
1625       const char *path, const char *label,
1626       unsigned type, size_t idx)
1627 {
1628    const char *menu_label         = NULL;
1629    file_list_t *menu_list         = MENU_LIST_GET(menu_st->entries.list, 0);
1630 #ifdef DEBUG_LOG
1631    menu_file_list_cbs_t *menu_cbs = (menu_file_list_cbs_t*)
1632       menu_list->list[list->size - 1].actiondata;
1633    enum msg_hash_enums enum_idx   = menu_cbs ? menu_cbs->enum_idx : MSG_UNKNOWN;
1634 #endif
1635 
1636    if (menu_list && menu_list->size)
1637       file_list_get_at_offset(menu_list, menu_list->size - 1, NULL, &menu_label, NULL, NULL);
1638 
1639    if (!label || !menu_label)
1640       return;
1641 
1642 #ifdef DEBUG_LOG
1643    RARCH_LOG("\n");
1644 
1645    if (cbs && cbs->enum_idx != MSG_UNKNOWN)
1646       RARCH_LOG("\t\t\tenum_idx %d [%s]\n", cbs->enum_idx, msg_hash_to_str(cbs->enum_idx));
1647 #endif
1648 
1649    /* It will try to find a corresponding callback function inside
1650     * menu_cbs_ok.c, then map this callback to the entry. */
1651    menu_cbs_init_bind_ok(cbs, path, label, type, idx, menu_label);
1652 
1653    /* It will try to find a corresponding callback function inside
1654     * menu_cbs_cancel.c, then map this callback to the entry. */
1655    menu_cbs_init_bind_cancel(cbs, path, label, type, idx);
1656 
1657    /* It will try to find a corresponding callback function inside
1658     * menu_cbs_scan.c, then map this callback to the entry. */
1659    menu_cbs_init_bind_scan(cbs, path, label, type, idx);
1660 
1661    /* It will try to find a corresponding callback function inside
1662     * menu_cbs_start.c, then map this callback to the entry. */
1663    menu_cbs_init_bind_start(cbs, path, label, type, idx);
1664 
1665    /* It will try to find a corresponding callback function inside
1666     * menu_cbs_select.c, then map this callback to the entry. */
1667    menu_cbs_init_bind_select(cbs, path, label, type, idx);
1668 
1669    /* It will try to find a corresponding callback function inside
1670     * menu_cbs_info.c, then map this callback to the entry. */
1671    menu_cbs_init_bind_info(cbs, path, label, type, idx);
1672 
1673    /* It will try to find a corresponding callback function inside
1674     * menu_cbs_left.c, then map this callback to the entry. */
1675    menu_cbs_init_bind_left(cbs, path, label, type, idx, menu_label);
1676 
1677    /* It will try to find a corresponding callback function inside
1678     * menu_cbs_right.c, then map this callback to the entry. */
1679    menu_cbs_init_bind_right(cbs, path, label, type, idx, menu_label);
1680 
1681    /* It will try to find a corresponding callback function inside
1682     * menu_cbs_deferred_push.c, then map this callback to the entry. */
1683    menu_cbs_init_bind_deferred_push(cbs, path, label, type, idx);
1684 
1685    /* It will try to find a corresponding callback function inside
1686     * menu_cbs_get_string_representation.c, then map this callback to the entry. */
1687    menu_cbs_init_bind_get_string_representation(cbs, path, label, type, idx);
1688 
1689    /* It will try to find a corresponding callback function inside
1690     * menu_cbs_title.c, then map this callback to the entry. */
1691    menu_cbs_init_bind_title(cbs, path, label, type, idx);
1692 
1693    /* It will try to find a corresponding callback function inside
1694     * menu_cbs_label.c, then map this callback to the entry. */
1695    menu_cbs_init_bind_label(cbs, path, label, type, idx);
1696 
1697    /* It will try to find a corresponding callback function inside
1698     * menu_cbs_sublabel.c, then map this callback to the entry. */
1699    menu_cbs_init_bind_sublabel(cbs, path, label, type, idx);
1700 
1701    if (menu_driver_ctx && menu_driver_ctx->bind_init)
1702       menu_driver_ctx->bind_init(
1703             cbs,
1704             path,
1705             label,
1706             type,
1707             idx);
1708 }
1709 
1710 /* Pretty much a stub function. TODO/FIXME - Might as well remove this. */
menu_cbs_exit(void)1711 int menu_cbs_exit(void)
1712 {
1713    return -1;
1714 }
1715 
action_iterate_type(const char * label)1716 static enum action_iterate_type action_iterate_type(const char *label)
1717 {
1718    if (string_is_equal(label, "info_screen"))
1719       return ITERATE_TYPE_INFO;
1720    if (string_starts_with_size(label, "help", STRLEN_CONST("help")))
1721       if (
1722             string_is_equal(label, "help") ||
1723             string_is_equal(label, "help_controls") ||
1724             string_is_equal(label, "help_what_is_a_core") ||
1725             string_is_equal(label, "help_loading_content") ||
1726             string_is_equal(label, "help_scanning_content") ||
1727             string_is_equal(label, "help_change_virtual_gamepad") ||
1728             string_is_equal(label, "help_audio_video_troubleshooting") ||
1729             string_is_equal(label, "help_send_debug_info")
1730          )
1731          return ITERATE_TYPE_HELP;
1732    if (string_is_equal(label, "cheevos_description"))
1733          return ITERATE_TYPE_HELP;
1734    if (string_starts_with_size(label, "custom_bind", STRLEN_CONST("custom_bind")))
1735       if (
1736             string_is_equal(label, "custom_bind") ||
1737             string_is_equal(label, "custom_bind_all") ||
1738             string_is_equal(label, "custom_bind_defaults")
1739          )
1740          return ITERATE_TYPE_BIND;
1741 
1742    return ITERATE_TYPE_DEFAULT;
1743 }
1744 
1745 #ifdef HAVE_ACCESSIBILITY
get_current_menu_value(struct menu_state * menu_st,char * s,size_t len)1746 static void get_current_menu_value(struct menu_state *menu_st,
1747       char *s, size_t len)
1748 {
1749    menu_entry_t     entry;
1750    const char*      entry_label;
1751 
1752    MENU_ENTRY_INIT(entry);
1753    entry.path_enabled          = false;
1754    entry.label_enabled         = false;
1755    entry.rich_label_enabled    = false;
1756    entry.sublabel_enabled      = false;
1757    menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
1758 
1759    if (entry.enum_idx == MENU_ENUM_LABEL_CHEEVOS_PASSWORD)
1760       entry_label              = entry.password_value;
1761    else
1762       entry_label              = entry.value;
1763 
1764    strlcpy(s, entry_label, len);
1765 }
1766 
get_current_menu_label(struct menu_state * menu_st,char * s,size_t len)1767 static void get_current_menu_label(struct menu_state *menu_st,
1768       char *s, size_t len)
1769 {
1770    menu_entry_t     entry;
1771    const char*      entry_label;
1772 
1773    MENU_ENTRY_INIT(entry);
1774    menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
1775 
1776    if (!string_is_empty(entry.rich_label))
1777       entry_label              = entry.rich_label;
1778    else
1779       entry_label              = entry.path;
1780 
1781    strlcpy(s, entry_label, len);
1782 }
1783 
get_current_menu_sublabel(struct menu_state * menu_st,char * s,size_t len)1784 static void get_current_menu_sublabel(struct menu_state *menu_st,
1785       char *s, size_t len)
1786 {
1787    menu_entry_t     entry;
1788 
1789    MENU_ENTRY_INIT(entry);
1790    entry.path_enabled          = false;
1791    entry.label_enabled         = false;
1792    entry.rich_label_enabled    = false;
1793    entry.value_enabled         = false;
1794    menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
1795    strlcpy(s, entry.sublabel, len);
1796 }
1797 #endif
1798 
menu_input_set_pointer_visibility(menu_input_pointer_hw_state_t * pointer_hw_state,menu_input_t * menu_input,retro_time_t current_time)1799 static void menu_input_set_pointer_visibility(
1800       menu_input_pointer_hw_state_t *pointer_hw_state,
1801       menu_input_t *menu_input,
1802       retro_time_t current_time)
1803 {
1804    static bool cursor_shown                        = false;
1805    static bool cursor_hidden                       = false;
1806    static retro_time_t end_time                    = 0;
1807 
1808    /* Ensure that mouse cursor is hidden when not in use */
1809    if ((menu_input->pointer.type == MENU_POINTER_MOUSE)
1810          && pointer_hw_state->active)
1811    {
1812       /* Show cursor */
1813       if ((current_time > end_time) && !cursor_shown)
1814       {
1815          menu_ctx_environment_t menu_environ;
1816          menu_environ.type = MENU_ENVIRON_ENABLE_MOUSE_CURSOR;
1817          menu_environ.data = NULL;
1818 
1819          menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
1820          cursor_shown  = true;
1821          cursor_hidden = false;
1822       }
1823 
1824       end_time = current_time + MENU_INPUT_HIDE_CURSOR_DELAY;
1825    }
1826    else
1827    {
1828       /* Hide cursor */
1829       if ((current_time > end_time) && !cursor_hidden)
1830       {
1831          menu_ctx_environment_t menu_environ;
1832          menu_environ.type = MENU_ENVIRON_DISABLE_MOUSE_CURSOR;
1833          menu_environ.data = NULL;
1834 
1835          menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
1836          cursor_shown  = false;
1837          cursor_hidden = true;
1838       }
1839    }
1840 }
1841 
1842 
1843 /**
1844  * menu_iterate:
1845  * @input                    : input sample for this frame
1846  * @old_input                : input sample of the previous frame
1847  * @trigger_input            : difference' input sample - difference
1848  *                             between 'input' and 'old_input'
1849  *
1850  * Runs RetroArch menu for one frame.
1851  *
1852  * Returns: 0 on success, -1 if we need to quit out of the loop.
1853  **/
generic_menu_iterate(struct rarch_state * p_rarch,struct menu_state * menu_st,gfx_display_t * p_disp,gfx_animation_t * p_anim,settings_t * settings,menu_handle_t * menu,void * userdata,enum menu_action action,retro_time_t current_time)1854 static int generic_menu_iterate(
1855       struct rarch_state *p_rarch,
1856       struct menu_state *menu_st,
1857       gfx_display_t *p_disp,
1858       gfx_animation_t *p_anim,
1859       settings_t *settings,
1860       menu_handle_t *menu,
1861       void *userdata, enum menu_action action,
1862       retro_time_t current_time)
1863 {
1864 #ifdef HAVE_ACCESSIBILITY
1865    static enum action_iterate_type
1866       last_iterate_type            = ITERATE_TYPE_DEFAULT;
1867    bool accessibility_enable       = settings->bools.accessibility_enable;
1868    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
1869 #endif
1870    enum action_iterate_type iterate_type;
1871    unsigned file_type              = 0;
1872    int ret                         = 0;
1873    const char *label               = NULL;
1874    file_list_t *list               = MENU_LIST_GET(menu_st->entries.list, 0);
1875 
1876    if (list && list->size)
1877       file_list_get_at_offset(list, list->size - 1, NULL, &label, &file_type, NULL);
1878 
1879    menu->menu_state_msg[0]         = '\0';
1880 
1881    iterate_type                    = action_iterate_type(label);
1882    p_rarch->menu_driver_is_binding = false;
1883 
1884    if (     action != MENU_ACTION_NOOP
1885          || MENU_ENTRIES_NEEDS_REFRESH(menu_st)
1886          || GFX_DISPLAY_GET_UPDATE_PENDING(p_anim, p_disp))
1887    {
1888       BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
1889    }
1890 
1891    switch (iterate_type)
1892    {
1893       case ITERATE_TYPE_HELP:
1894          ret = menu_dialog_iterate(
1895                &p_rarch->dialog_st,
1896                menu->menu_state_msg, sizeof(menu->menu_state_msg),
1897                current_time);
1898 
1899 #ifdef HAVE_ACCESSIBILITY
1900          if (     (iterate_type != last_iterate_type)
1901                && is_accessibility_enabled(
1902                   accessibility_enable,
1903                   p_rarch->accessibility_enabled))
1904             accessibility_speak_priority(p_rarch,
1905                   accessibility_enable,
1906                   accessibility_narrator_speech_speed,
1907                   menu->menu_state_msg, 10);
1908 #endif
1909 
1910          BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
1911          BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
1912 
1913          {
1914             bool pop_stack = false;
1915             if (  ret == 1 ||
1916                   action == MENU_ACTION_OK ||
1917                   action == MENU_ACTION_CANCEL
1918                )
1919                pop_stack   = true;
1920 
1921             if (pop_stack)
1922                BIT64_SET(menu->state, MENU_STATE_POP_STACK);
1923          }
1924          break;
1925       case ITERATE_TYPE_BIND:
1926          {
1927             menu_input_ctx_bind_t bind;
1928 
1929             p_rarch->menu_driver_is_binding = true;
1930 
1931             bind.s   = menu->menu_state_msg;
1932             bind.len = sizeof(menu->menu_state_msg);
1933 
1934             if (menu_input_key_bind_iterate(p_rarch,
1935                      settings,
1936                      &bind, current_time))
1937             {
1938                size_t selection = menu_st->selection_ptr;
1939                menu_entries_pop_stack(&selection, 0, 0);
1940                menu_st->selection_ptr      = selection;
1941             }
1942             else
1943                BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
1944          }
1945          break;
1946       case ITERATE_TYPE_INFO:
1947          {
1948             menu_list_t *menu_list     = menu_st->entries.list;
1949             file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
1950             size_t selection           = menu_st->selection_ptr;
1951             menu_file_list_cbs_t *cbs  = selection_buf ?
1952                (menu_file_list_cbs_t*)selection_buf->list[selection].actiondata
1953                : NULL;
1954 
1955             if (cbs && cbs->enum_idx != MSG_UNKNOWN)
1956             {
1957                /* Core updater/manager entries require special treatment */
1958                switch (cbs->enum_idx)
1959                {
1960 #ifdef HAVE_NETWORKING
1961                   case MENU_ENUM_LABEL_CORE_UPDATER_ENTRY:
1962                      {
1963                         core_updater_list_t *core_list         =
1964                            core_updater_list_get_cached();
1965                         const core_updater_list_entry_t *entry = NULL;
1966                         const char *path                       =
1967                            selection_buf->list[selection].path;
1968 
1969                         /* Search for specified core */
1970                         if (
1971                                  core_list
1972                               && path
1973                               && core_updater_list_get_filename(core_list,
1974                                  path, &entry)
1975                               && !string_is_empty(entry->description)
1976                            )
1977                            strlcpy(menu->menu_state_msg, entry->description,
1978                                  sizeof(menu->menu_state_msg));
1979                         else
1980                            strlcpy(menu->menu_state_msg,
1981                                  msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
1982                                  sizeof(menu->menu_state_msg));
1983 
1984                         ret = 0;
1985                      }
1986                      break;
1987 #endif
1988                   case MENU_ENUM_LABEL_CORE_MANAGER_ENTRY:
1989                      {
1990                         core_info_t *core_info = NULL;
1991                         const char *path       = selection_buf->list[selection].path;
1992 
1993                         /* Search for specified core */
1994                         if (     path
1995                               && core_info_find(path, &core_info)
1996                               && !string_is_empty(core_info->description))
1997                            strlcpy(menu->menu_state_msg,
1998                                  core_info->description,
1999                                  sizeof(menu->menu_state_msg));
2000                         else
2001                            strlcpy(menu->menu_state_msg,
2002                                  msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
2003                                  sizeof(menu->menu_state_msg));
2004 
2005                         ret = 0;
2006                      }
2007                      break;
2008                   default:
2009                      ret = msg_hash_get_help_enum(cbs->enum_idx,
2010                            menu->menu_state_msg, sizeof(menu->menu_state_msg));
2011                      break;
2012                }
2013 
2014 #ifdef HAVE_ACCESSIBILITY
2015                if (  (iterate_type != last_iterate_type) &&
2016                      is_accessibility_enabled(
2017                         accessibility_enable,
2018                         p_rarch->accessibility_enabled))
2019                {
2020                   if (string_is_equal(menu->menu_state_msg,
2021                            msg_hash_to_str(
2022                               MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE)))
2023                   {
2024                      char current_sublabel[255];
2025                      get_current_menu_sublabel(
2026                            &p_rarch->menu_driver_state,
2027                            current_sublabel, sizeof(current_sublabel));
2028                      if (string_is_equal(current_sublabel, ""))
2029                         accessibility_speak_priority(p_rarch,
2030                               accessibility_enable,
2031                               accessibility_narrator_speech_speed,
2032                               menu->menu_state_msg, 10);
2033                      else
2034                         accessibility_speak_priority(p_rarch,
2035                               accessibility_enable,
2036                               accessibility_narrator_speech_speed,
2037                               current_sublabel, 10);
2038                   }
2039                   else
2040                      accessibility_speak_priority(p_rarch,
2041                            accessibility_enable,
2042                            accessibility_narrator_speech_speed,
2043                            menu->menu_state_msg, 10);
2044                }
2045 #endif
2046             }
2047             else
2048             {
2049                enum msg_hash_enums enum_idx = MSG_UNKNOWN;
2050                size_t selection             = menu_st->selection_ptr;
2051                unsigned type                = selection_buf->list[selection].type;
2052 
2053                switch (type)
2054                {
2055                   case FILE_TYPE_FONT:
2056                   case FILE_TYPE_VIDEO_FONT:
2057                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_FONT;
2058                      break;
2059                   case FILE_TYPE_RDB:
2060                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RDB;
2061                      break;
2062                   case FILE_TYPE_OVERLAY:
2063                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_OVERLAY;
2064                      break;
2065 #ifdef HAVE_VIDEO_LAYOUT
2066                   case FILE_TYPE_VIDEO_LAYOUT:
2067                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_VIDEO_LAYOUT;
2068                      break;
2069 #endif
2070                   case FILE_TYPE_CHEAT:
2071                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CHEAT;
2072                      break;
2073                   case FILE_TYPE_SHADER_PRESET:
2074                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER_PRESET;
2075                      break;
2076                   case FILE_TYPE_SHADER:
2077                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_SHADER;
2078                      break;
2079                   case FILE_TYPE_REMAP:
2080                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_REMAP;
2081                      break;
2082                   case FILE_TYPE_RECORD_CONFIG:
2083                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG;
2084                      break;
2085                   case FILE_TYPE_CURSOR:
2086                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CURSOR;
2087                      break;
2088                   case FILE_TYPE_CONFIG:
2089                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CONFIG;
2090                      break;
2091                   case FILE_TYPE_CARCHIVE:
2092                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE;
2093                      break;
2094                   case FILE_TYPE_DIRECTORY:
2095                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
2096                      break;
2097                   case FILE_TYPE_VIDEOFILTER:            /* TODO/FIXME */
2098                   case FILE_TYPE_AUDIOFILTER:            /* TODO/FIXME */
2099                   case FILE_TYPE_SHADER_SLANG:           /* TODO/FIXME */
2100                   case FILE_TYPE_SHADER_GLSL:            /* TODO/FIXME */
2101                   case FILE_TYPE_SHADER_HLSL:            /* TODO/FIXME */
2102                   case FILE_TYPE_SHADER_CG:              /* TODO/FIXME */
2103                   case FILE_TYPE_SHADER_PRESET_GLSLP:    /* TODO/FIXME */
2104                   case FILE_TYPE_SHADER_PRESET_HLSLP:    /* TODO/FIXME */
2105                   case FILE_TYPE_SHADER_PRESET_CGP:      /* TODO/FIXME */
2106                   case FILE_TYPE_SHADER_PRESET_SLANGP:   /* TODO/FIXME */
2107                   case FILE_TYPE_PLAIN:
2108                      enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_PLAIN_FILE;
2109                      break;
2110                   default:
2111                      break;
2112                }
2113 
2114                if (enum_idx != MSG_UNKNOWN)
2115                   ret = msg_hash_get_help_enum(enum_idx,
2116                         menu->menu_state_msg, sizeof(menu->menu_state_msg));
2117                else
2118                {
2119                   strlcpy(menu->menu_state_msg,
2120                         msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
2121                         sizeof(menu->menu_state_msg));
2122 
2123                   ret = 0;
2124                }
2125             }
2126          }
2127          BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX);
2128          BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
2129          if (action == MENU_ACTION_OK || action == MENU_ACTION_CANCEL)
2130          {
2131             BIT64_SET(menu->state, MENU_STATE_POP_STACK);
2132          }
2133          break;
2134       case ITERATE_TYPE_DEFAULT:
2135          {
2136             menu_entry_t entry;
2137             menu_list_t *menu_list = menu_st->entries.list;
2138             size_t selection       = menu_st->selection_ptr;
2139             size_t menu_list_size  = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0;
2140             /* FIXME: Crappy hack, needed for mouse controls
2141              * to not be completely broken in case we press back.
2142              *
2143              * We need to fix this entire mess, mouse controls
2144              * should not rely on a hack like this in order to work. */
2145             selection = MAX(MIN(selection, (menu_list_size - 1)), 0);
2146 
2147             MENU_ENTRY_INIT(entry);
2148             /* NOTE: If menu_entry_action() is modified,
2149              * will have to verify that these parameters
2150              * remain unused... */
2151             entry.rich_label_enabled = false;
2152             entry.value_enabled      = false;
2153             entry.sublabel_enabled   = false;
2154             menu_entry_get(&entry, 0, selection, NULL, false);
2155             ret                      = menu_entry_action(&entry,
2156                   selection, (enum menu_action)action);
2157             if (ret)
2158                return -1;
2159 
2160             BIT64_SET(menu->state, MENU_STATE_POST_ITERATE);
2161 
2162             /* Have to defer it so we let settings refresh. */
2163             if (p_rarch->dialog_st.pending_push)
2164             {
2165                const char *label;
2166                menu_displaylist_info_t info;
2167 
2168                menu_displaylist_info_init(&info);
2169 
2170                info.list                 = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL;
2171                info.enum_idx             = MENU_ENUM_LABEL_HELP;
2172 
2173                /* Set the label string, if it exists. */
2174                label                     = msg_hash_to_str(MENU_ENUM_LABEL_HELP);
2175                if (label)
2176                   info.label             = strdup(label);
2177 
2178                menu_displaylist_ctl(DISPLAYLIST_HELP, &info, settings);
2179             }
2180          }
2181          break;
2182    }
2183 
2184 #ifdef HAVE_ACCESSIBILITY
2185    if ((last_iterate_type == ITERATE_TYPE_HELP
2186             || last_iterate_type == ITERATE_TYPE_INFO)
2187          && last_iterate_type != iterate_type
2188          && is_accessibility_enabled(
2189             accessibility_enable,
2190             p_rarch->accessibility_enabled))
2191       accessibility_speak_priority(p_rarch,
2192             accessibility_enable,
2193             accessibility_narrator_speech_speed,
2194             "Closed dialog.", 10);
2195 
2196    last_iterate_type = iterate_type;
2197 #endif
2198 
2199    BIT64_SET(menu->state, MENU_STATE_BLIT);
2200 
2201    if (BIT64_GET(menu->state, MENU_STATE_POP_STACK))
2202    {
2203       size_t selection         = menu_st->selection_ptr;
2204       size_t new_selection_ptr = selection;
2205       menu_entries_pop_stack(&new_selection_ptr, 0, 0);
2206       menu_st->selection_ptr   = selection;
2207    }
2208 
2209    if (BIT64_GET(menu->state, MENU_STATE_POST_ITERATE))
2210    {
2211       menu_input_t     *menu_input  = &p_rarch->menu_input_state;
2212       /* If pointer devices are disabled, just ensure mouse
2213        * cursor is hidden */
2214       if (menu_input->pointer.type == MENU_POINTER_DISABLED)
2215          ret = 0;
2216       else
2217          ret = menu_input_post_iterate(p_rarch, p_disp, menu_st, action,
2218                current_time);
2219       menu_input_set_pointer_visibility(
2220             &p_rarch->menu_input_pointer_hw_state, menu_input, current_time);
2221    }
2222 
2223    if (ret)
2224       return -1;
2225    return 0;
2226 }
2227 
menu_driver_displaylist_push_internal(const char * label,menu_displaylist_info_t * info,settings_t * settings)2228 static bool menu_driver_displaylist_push_internal(
2229       const char *label,
2230       menu_displaylist_info_t *info,
2231       settings_t *settings)
2232 {
2233    if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HISTORY_TAB)))
2234    {
2235       if (menu_displaylist_ctl(DISPLAYLIST_HISTORY, info, settings))
2236          return true;
2237    }
2238    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES_TAB)))
2239    {
2240       if (menu_displaylist_ctl(DISPLAYLIST_FAVORITES, info, settings))
2241          return true;
2242    }
2243    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SETTINGS_TAB)))
2244    {
2245       if (menu_displaylist_ctl(DISPLAYLIST_SETTINGS_ALL, info, settings))
2246          return true;
2247    }
2248 #ifdef HAVE_CHEATS
2249    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS)))
2250    {
2251       if (menu_displaylist_ctl(DISPLAYLIST_CHEAT_SEARCH_SETTINGS_LIST, info, settings))
2252          return true;
2253    }
2254 #endif
2255    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MUSIC_TAB)))
2256    {
2257       filebrowser_clear_type();
2258       info->type = 42;
2259 
2260       if (!string_is_empty(info->exts))
2261          free(info->exts);
2262       if (!string_is_empty(info->label))
2263          free(info->label);
2264 
2265       info->exts  = strdup("lpl");
2266       info->label = strdup(
2267             msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
2268 
2269       menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
2270       menu_displaylist_ctl(DISPLAYLIST_MUSIC_HISTORY, info, settings);
2271       return true;
2272    }
2273    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_TAB)))
2274    {
2275       filebrowser_clear_type();
2276       info->type = 42;
2277 
2278       if (!string_is_empty(info->exts))
2279          free(info->exts);
2280       if (!string_is_empty(info->label))
2281          free(info->label);
2282 
2283       info->exts  = strdup("lpl");
2284       info->label = strdup(
2285             msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
2286 
2287       menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
2288       menu_displaylist_ctl(DISPLAYLIST_VIDEO_HISTORY, info, settings);
2289       return true;
2290    }
2291    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_IMAGES_TAB)))
2292    {
2293       filebrowser_clear_type();
2294       info->type = 42;
2295 
2296       if (!string_is_empty(info->exts))
2297          free(info->exts);
2298       if (!string_is_empty(info->label))
2299          free(info->label);
2300 
2301       info->exts  = strdup("lpl");
2302       info->label = strdup(
2303             msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
2304 
2305       menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
2306 
2307 #if 0
2308 #ifdef HAVE_SCREENSHOTS
2309       if (!rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
2310          menu_entries_append_enum(info->list,
2311                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT),
2312                msg_hash_to_str(MENU_ENUM_LABEL_TAKE_SCREENSHOT),
2313                MENU_ENUM_LABEL_TAKE_SCREENSHOT,
2314                MENU_SETTING_ACTION_SCREENSHOT, 0, 0);
2315       else
2316          info->need_push_no_playlist_entries = true;
2317 #endif
2318 #endif
2319       menu_displaylist_ctl(DISPLAYLIST_IMAGES_HISTORY, info, settings);
2320       return true;
2321    }
2322    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB)))
2323    {
2324       const char *dir_playlist    = settings->paths.directory_playlist;
2325 
2326       filebrowser_clear_type();
2327       info->type                  = 42;
2328 
2329       if (!string_is_empty(info->exts))
2330          free(info->exts);
2331       if (!string_is_empty(info->label))
2332          free(info->label);
2333 
2334       info->exts  = strdup("lpl");
2335       info->label = strdup(
2336             msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
2337 
2338       if (string_is_empty(dir_playlist))
2339       {
2340          menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
2341          info->need_refresh                  = true;
2342          info->need_push_no_playlist_entries = true;
2343          info->need_push                     = true;
2344 
2345          return true;
2346       }
2347 
2348       if (!string_is_empty(info->path))
2349          free(info->path);
2350 
2351       info->path = strdup(dir_playlist);
2352 
2353       if (menu_displaylist_ctl(
2354                DISPLAYLIST_DATABASE_PLAYLISTS, info, settings))
2355          return true;
2356    }
2357    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ADD_TAB)))
2358    {
2359       if (menu_displaylist_ctl(DISPLAYLIST_SCAN_DIRECTORY_LIST, info, settings))
2360          return true;
2361    }
2362 #if defined(HAVE_LIBRETRODB)
2363    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_EXPLORE_TAB)))
2364    {
2365       if (menu_displaylist_ctl(DISPLAYLIST_EXPLORE, info, settings))
2366          return true;
2367    }
2368 #endif
2369    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)))
2370    {
2371       if (menu_displaylist_ctl(DISPLAYLIST_NETPLAY_ROOM_LIST, info, settings))
2372          return true;
2373    }
2374    else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU)))
2375    {
2376       if (menu_displaylist_ctl(DISPLAYLIST_HORIZONTAL, info, settings))
2377          return true;
2378    }
2379 
2380    return false;
2381 }
2382 
menu_driver_displaylist_push(struct menu_state * menu_st,settings_t * settings,file_list_t * entry_list,file_list_t * entry_stack)2383 static bool menu_driver_displaylist_push(
2384       struct menu_state *menu_st,
2385       settings_t *settings,
2386       file_list_t *entry_list,
2387       file_list_t *entry_stack)
2388 {
2389    menu_displaylist_info_t info;
2390    const char *path               = NULL;
2391    const char *label              = NULL;
2392    unsigned type                  = 0;
2393    bool ret                       = false;
2394    enum msg_hash_enums enum_idx   = MSG_UNKNOWN;
2395    file_list_t *list              = MENU_LIST_GET(menu_st->entries.list, 0);
2396    menu_file_list_cbs_t *cbs      = (menu_file_list_cbs_t*)
2397       list->list[list->size - 1].actiondata;
2398 
2399    menu_displaylist_info_init(&info);
2400 
2401    if (list && list->size)
2402       file_list_get_at_offset(list, list->size - 1, &path, &label, &type, NULL);
2403 
2404    if (cbs)
2405       enum_idx    = cbs->enum_idx;
2406 
2407    info.list      = entry_list;
2408    info.menu_list = entry_stack;
2409    info.type      = type;
2410    info.enum_idx  = enum_idx;
2411 
2412    if (!string_is_empty(path))
2413       info.path  = strdup(path);
2414 
2415    if (!string_is_empty(label))
2416       info.label = strdup(label);
2417 
2418    if (!info.list)
2419       goto error;
2420 
2421    if (menu_driver_displaylist_push_internal(label, &info, settings))
2422    {
2423       ret = menu_displaylist_process(&info);
2424       goto end;
2425    }
2426 
2427    cbs = (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata;
2428 
2429    if (cbs && cbs->action_deferred_push)
2430       if (cbs->action_deferred_push(&info) != 0)
2431          goto error;
2432 
2433    ret = true;
2434 
2435 end:
2436    menu_displaylist_info_free(&info);
2437 
2438    return ret;
2439 
2440 error:
2441    menu_displaylist_info_free(&info);
2442    return false;
2443 }
2444 
generic_menu_entry_action(void * userdata,menu_entry_t * entry,size_t i,enum menu_action action)2445 int generic_menu_entry_action(
2446       void *userdata, menu_entry_t *entry, size_t i, enum menu_action action)
2447 {
2448    int ret                        = 0;
2449    struct rarch_state *p_rarch    = &rarch_st;
2450    const menu_ctx_driver_t
2451       *menu_driver_ctx            = p_rarch->menu_driver_ctx;
2452    settings_t   *settings         = p_rarch->configuration_settings;
2453    bool wraparound_enable         = settings->bools.menu_navigation_wraparound_enable;
2454    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
2455    size_t scroll_accel            = menu_st->scroll.acceleration;
2456    menu_list_t *menu_list         = menu_st->entries.list;
2457    file_list_t *selection_buf     = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
2458    file_list_t *menu_stack        = menu_list ? MENU_LIST_GET(menu_list, (unsigned)0) : NULL;
2459    size_t selection_buf_size      = selection_buf ? selection_buf->size : 0;
2460    menu_file_list_cbs_t *cbs      = selection_buf ?
2461       (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL;
2462 #ifdef HAVE_ACCESSIBILITY
2463    bool accessibility_enable      = settings->bools.accessibility_enable;
2464    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
2465 #endif
2466 
2467    switch (action)
2468    {
2469       case MENU_ACTION_UP:
2470          if (selection_buf_size > 0)
2471          {
2472             unsigned scroll_speed  = (unsigned)((MAX(scroll_accel, 2) - 2) / 4 + 1);
2473             if (!(menu_st->selection_ptr == 0 && !wraparound_enable))
2474             {
2475                size_t idx             = 0;
2476                if (menu_st->selection_ptr >= scroll_speed)
2477                   idx = menu_st->selection_ptr - scroll_speed;
2478                else
2479                {
2480                   idx  = selection_buf_size - 1;
2481                   if (!wraparound_enable)
2482                      idx = 0;
2483                }
2484 
2485                menu_st->selection_ptr = idx;
2486                menu_driver_navigation_set(true);
2487 
2488                if (menu_driver_ctx->navigation_decrement)
2489                   menu_driver_ctx->navigation_decrement(p_rarch->menu_userdata);
2490             }
2491          }
2492          break;
2493       case MENU_ACTION_DOWN:
2494          if (selection_buf_size > 0)
2495          {
2496             unsigned scroll_speed  = (unsigned)((MAX(scroll_accel, 2) - 2) / 4 + 1);
2497             if (!(menu_st->selection_ptr >= selection_buf_size - 1
2498                   && !wraparound_enable))
2499             {
2500                if ((menu_st->selection_ptr + scroll_speed) < selection_buf_size)
2501                {
2502                   size_t idx  = menu_st->selection_ptr + scroll_speed;
2503 
2504                   menu_st->selection_ptr = idx;
2505                   menu_driver_navigation_set(true);
2506                }
2507                else
2508                {
2509                   if (wraparound_enable)
2510                   {
2511                      bool pending_push = false;
2512                      menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
2513                   }
2514                   else
2515                      menu_driver_ctl(MENU_NAVIGATION_CTL_SET_LAST,  NULL);
2516                }
2517 
2518                if (menu_driver_ctx->navigation_increment)
2519                   menu_driver_ctx->navigation_increment(p_rarch->menu_userdata);
2520             }
2521          }
2522          break;
2523       case MENU_ACTION_SCROLL_UP:
2524          if (
2525                   menu_st->scroll.index_size
2526                && menu_st->selection_ptr != 0
2527             )
2528          {
2529             size_t l   = menu_st->scroll.index_size - 1;
2530 
2531             while (l
2532                   && menu_st->scroll.index_list[l - 1]
2533                   >= menu_st->selection_ptr)
2534                l--;
2535 
2536             if (l > 0)
2537                menu_st->selection_ptr = menu_st->scroll.index_list[l - 1];
2538 
2539             if (menu_driver_ctx->navigation_descend_alphabet)
2540                menu_driver_ctx->navigation_descend_alphabet(
2541                      p_rarch->menu_userdata, &menu_st->selection_ptr);
2542          }
2543          break;
2544       case MENU_ACTION_SCROLL_DOWN:
2545          if (menu_st->scroll.index_size)
2546          {
2547             if (menu_st->selection_ptr == menu_st->scroll.index_list[menu_st->scroll.index_size - 1])
2548                menu_st->selection_ptr = selection_buf_size - 1;
2549             else
2550             {
2551                size_t l               = 0;
2552                while (l < menu_st->scroll.index_size - 1
2553                      && menu_st->scroll.index_list[l + 1] <= menu_st->selection_ptr)
2554                   l++;
2555                menu_st->selection_ptr = menu_st->scroll.index_list[l + 1];
2556 
2557                if (menu_st->selection_ptr >= selection_buf_size)
2558                   menu_st->selection_ptr = selection_buf_size - 1;
2559             }
2560 
2561             if (menu_driver_ctx->navigation_ascend_alphabet)
2562                menu_driver_ctx->navigation_ascend_alphabet(
2563                      p_rarch->menu_userdata, &menu_st->selection_ptr);
2564          }
2565          break;
2566       case MENU_ACTION_CANCEL:
2567          if (cbs && cbs->action_cancel)
2568             ret = cbs->action_cancel(entry->path,
2569                   entry->label, entry->type, i);
2570          break;
2571       case MENU_ACTION_OK:
2572          if (cbs && cbs->action_ok)
2573             ret = cbs->action_ok(entry->path,
2574                   entry->label, entry->type, i, entry->entry_idx);
2575          break;
2576       case MENU_ACTION_START:
2577          if (cbs && cbs->action_start)
2578             ret = cbs->action_start(entry->path,
2579                   entry->label, entry->type, i, entry->entry_idx);
2580          break;
2581       case MENU_ACTION_LEFT:
2582          if (cbs && cbs->action_left)
2583             ret = cbs->action_left(entry->type, entry->label, false);
2584          break;
2585       case MENU_ACTION_RIGHT:
2586          if (cbs && cbs->action_right)
2587             ret = cbs->action_right(entry->type, entry->label, false);
2588          break;
2589       case MENU_ACTION_INFO:
2590          if (cbs && cbs->action_info)
2591             ret = cbs->action_info(entry->type, entry->label);
2592          break;
2593       case MENU_ACTION_SELECT:
2594          if (cbs && cbs->action_select)
2595             ret = cbs->action_select(entry->path,
2596                   entry->label, entry->type, i, entry->entry_idx);
2597          break;
2598       case MENU_ACTION_SEARCH:
2599          menu_input_dialog_start_search();
2600          break;
2601       case MENU_ACTION_SCAN:
2602          if (cbs && cbs->action_scan)
2603             ret = cbs->action_scan(entry->path,
2604                   entry->label, entry->type, i);
2605          break;
2606       default:
2607          break;
2608    }
2609 
2610    if (MENU_ENTRIES_NEEDS_REFRESH(menu_st))
2611    {
2612       bool refresh            = false;
2613       menu_driver_displaylist_push(
2614             menu_st,
2615             settings,
2616             selection_buf,
2617             menu_stack);
2618       menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh);
2619    }
2620 
2621 #ifdef HAVE_ACCESSIBILITY
2622    if (     action != 0
2623          && is_accessibility_enabled(
2624             accessibility_enable,
2625             p_rarch->accessibility_enabled)
2626          && !menu_input_dialog_get_display_kb())
2627    {
2628       char current_label[255];
2629       char current_value[255];
2630       char title_name[255];
2631       char speak_string[512];
2632 
2633       speak_string[0]  = '\0';
2634       title_name  [0]  = '\0';
2635       current_label[0] = '\0';
2636 
2637       get_current_menu_value(&p_rarch->menu_driver_state,
2638             current_value, sizeof(current_value));
2639 
2640       switch (action)
2641       {
2642          case MENU_ACTION_ACCESSIBILITY_SPEAK_TITLE:
2643             menu_entries_get_title(title_name, sizeof(title_name));
2644             break;
2645          case MENU_ACTION_START:
2646             /* if equal to '..' we break, else we fall-through */
2647             if (string_is_equal(current_value, "..."))
2648                break;
2649             /* fall-through */
2650          case MENU_ACTION_ACCESSIBILITY_SPEAK_TITLE_LABEL:
2651          case MENU_ACTION_OK:
2652          case MENU_ACTION_LEFT:
2653          case MENU_ACTION_RIGHT:
2654          case MENU_ACTION_CANCEL:
2655             menu_entries_get_title(title_name, sizeof(title_name));
2656             get_current_menu_label(&p_rarch->menu_driver_state, current_label, sizeof(current_label));
2657             break;
2658          case MENU_ACTION_UP:
2659          case MENU_ACTION_DOWN:
2660          case MENU_ACTION_SCROLL_UP:
2661          case MENU_ACTION_SCROLL_DOWN:
2662          case MENU_ACTION_SELECT:
2663          case MENU_ACTION_SEARCH:
2664          case MENU_ACTION_ACCESSIBILITY_SPEAK_LABEL:
2665             get_current_menu_label(&p_rarch->menu_driver_state, current_label, sizeof(current_label));
2666             break;
2667          case MENU_ACTION_SCAN:
2668          case MENU_ACTION_INFO:
2669          default:
2670             break;
2671       }
2672 
2673       if (!string_is_empty(title_name))
2674       {
2675          if (!string_is_equal(current_value, "..."))
2676             snprintf(speak_string, sizeof(speak_string),
2677                   "%s %s %s", title_name, current_label, current_value);
2678          else
2679             snprintf(speak_string, sizeof(speak_string),
2680                   "%s %s", title_name, current_label);
2681       }
2682       else
2683       {
2684          if (!string_is_equal(current_value, "..."))
2685             snprintf(speak_string, sizeof(speak_string),
2686                   "%s %s", current_label, current_value);
2687          else
2688             strlcpy(speak_string, current_label, sizeof(speak_string));
2689       }
2690 
2691       if (!string_is_empty(speak_string))
2692          accessibility_speak_priority(p_rarch,
2693                accessibility_enable,
2694                accessibility_narrator_speech_speed,
2695                speak_string, 10);
2696    }
2697 #endif
2698 
2699    if (p_rarch->menu_driver_state.pending_close_content)
2700    {
2701       menu_handle_t       *menu = p_rarch->menu_driver_data;
2702       const char *content_path  = path_get(RARCH_PATH_CONTENT);
2703       const char *menu_flush_to = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU);
2704 
2705       /* Flush to playlist entry menu if launched via playlist */
2706       if (menu &&
2707           !string_is_empty(menu->deferred_path) &&
2708           !string_is_empty(content_path) &&
2709           string_is_equal(menu->deferred_path, content_path))
2710          menu_flush_to = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS);
2711 
2712       command_event(CMD_EVENT_UNLOAD_CORE, NULL);
2713       menu_entries_flush_stack(menu_flush_to, 0);
2714       menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL);
2715       menu_st->selection_ptr   = 0;
2716 
2717       p_rarch->menu_driver_state.pending_close_content = false;
2718    }
2719 
2720    return ret;
2721 }
2722 
menu_navigation_set_selection(size_t val)2723 void menu_navigation_set_selection(size_t val)
2724 {
2725    struct rarch_state *p_rarch = &rarch_st;
2726    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
2727    menu_st->selection_ptr      = val;
2728 }
2729 
menu_entry_get(menu_entry_t * entry,size_t stack_idx,size_t i,void * userdata,bool use_representation)2730 void menu_entry_get(menu_entry_t *entry, size_t stack_idx,
2731       size_t i, void *userdata, bool use_representation)
2732 {
2733    char newpath[255];
2734    const char *path            = NULL;
2735    const char *entry_label     = NULL;
2736    menu_file_list_cbs_t *cbs   = NULL;
2737    struct rarch_state *p_rarch = &rarch_st;
2738    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
2739    file_list_t *selection_buf  = MENU_ENTRIES_GET_SELECTION_BUF_PTR_INTERNAL(menu_st, stack_idx);
2740    file_list_t *list           = (userdata) ? (file_list_t*)userdata : selection_buf;
2741    bool path_enabled           = entry->path_enabled;
2742 
2743    newpath[0]                  = '\0';
2744 
2745    if (!list)
2746       return;
2747 
2748    path                       = list->list[i].path;
2749    entry_label                = list->list[i].label;
2750    entry->type                = list->list[i].type;
2751    entry->entry_idx           = list->list[i].entry_idx;
2752 
2753    cbs                        = (menu_file_list_cbs_t*)list->list[i].actiondata;
2754    entry->idx                 = (unsigned)i;
2755 
2756    if (entry->label_enabled && !string_is_empty(entry_label))
2757       strlcpy(entry->label, entry_label, sizeof(entry->label));
2758 
2759    if (cbs)
2760    {
2761       const char *label             = NULL;
2762 
2763       entry->enum_idx               = cbs->enum_idx;
2764       entry->checked                = cbs->checked;
2765 
2766       file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
2767             NULL, &label, NULL, NULL);
2768 
2769       if (entry->rich_label_enabled && cbs->action_label)
2770       {
2771          cbs->action_label(list,
2772                entry->type, (unsigned)i,
2773                label, path,
2774                entry->rich_label,
2775                sizeof(entry->rich_label));
2776 
2777          if (string_is_empty(entry->rich_label))
2778             path_enabled = true;
2779       }
2780 
2781       if ((path_enabled || entry->value_enabled) &&
2782           cbs->action_get_value &&
2783           use_representation)
2784       {
2785          cbs->action_get_value(list,
2786                &entry->spacing, entry->type,
2787                (unsigned)i, label,
2788                entry->value,
2789                entry->value_enabled ? sizeof(entry->value) : 0,
2790                path,
2791                newpath,
2792                path_enabled ? sizeof(newpath) : 0);
2793 
2794          if (!string_is_empty(entry->value))
2795          {
2796             if (entry->enum_idx == MENU_ENUM_LABEL_CHEEVOS_PASSWORD)
2797             {
2798                size_t j;
2799                size_t size = strlcpy(entry->password_value, entry->value,
2800                      sizeof(entry->password_value));
2801                for (j = 0; j < size; j++)
2802                   entry->password_value[j] = '*';
2803             }
2804          }
2805       }
2806 
2807       if (entry->sublabel_enabled)
2808       {
2809          if (!string_is_empty(cbs->action_sublabel_cache))
2810             strlcpy(entry->sublabel,
2811                      cbs->action_sublabel_cache, sizeof(entry->sublabel));
2812          else if (cbs->action_sublabel)
2813          {
2814             /* If this function callback returns true,
2815              * we know that the value won't change - so we
2816              * can cache it instead. */
2817             if (cbs->action_sublabel(list,
2818                      entry->type, (unsigned)i,
2819                      label, path,
2820                      entry->sublabel,
2821                      sizeof(entry->sublabel)) > 0)
2822                strlcpy(cbs->action_sublabel_cache,
2823                      entry->sublabel,
2824                      sizeof(cbs->action_sublabel_cache));
2825          }
2826       }
2827    }
2828 
2829    if (path_enabled)
2830    {
2831       if (!string_is_empty(path) && !use_representation)
2832          strlcpy(entry->path, path, sizeof(entry->path));
2833       else if (
2834                 cbs
2835             &&  cbs->setting
2836             &&  cbs->setting->enum_value_idx != MSG_UNKNOWN
2837             && !cbs->setting->dont_use_enum_idx_representation)
2838          strlcpy(entry->path,
2839                msg_hash_to_str(cbs->setting->enum_value_idx),
2840                sizeof(entry->path));
2841       else
2842          if (!string_is_empty(newpath))
2843             strlcpy(entry->path, newpath, sizeof(entry->path));
2844    }
2845 }
2846 
menu_entry_action(menu_entry_t * entry,size_t i,enum menu_action action)2847 int menu_entry_action(
2848       menu_entry_t *entry, size_t i, enum menu_action action)
2849 {
2850    struct rarch_state   *p_rarch  = &rarch_st;
2851    if (     p_rarch->menu_driver_ctx
2852          && p_rarch->menu_driver_ctx->entry_action)
2853       return p_rarch->menu_driver_ctx->entry_action(
2854             p_rarch->menu_userdata, entry, i, action);
2855    return -1;
2856 }
2857 
menu_list_free_list(const menu_ctx_driver_t * menu_driver_ctx,file_list_t * list)2858 static void menu_list_free_list(
2859       const menu_ctx_driver_t *menu_driver_ctx,
2860       file_list_t *list)
2861 {
2862    unsigned i;
2863 
2864    for (i = 0; i < list->size; i++)
2865    {
2866       menu_ctx_list_t list_info;
2867 
2868       list_info.list      = list;
2869       list_info.idx       = i;
2870       list_info.list_size = list->size;
2871 
2872       menu_driver_list_free(menu_driver_ctx, &list_info);
2873    }
2874 
2875    file_list_free(list);
2876 }
2877 
menu_list_free(const menu_ctx_driver_t * menu_driver_ctx,menu_list_t * menu_list)2878 static void menu_list_free(
2879       const menu_ctx_driver_t *menu_driver_ctx,
2880       menu_list_t *menu_list)
2881 {
2882    if (!menu_list)
2883       return;
2884 
2885    if (menu_list->menu_stack)
2886    {
2887       unsigned i;
2888 
2889       for (i = 0; i < menu_list->menu_stack_size; i++)
2890       {
2891          if (!menu_list->menu_stack[i])
2892             continue;
2893 
2894          menu_list_free_list(menu_driver_ctx,
2895                menu_list->menu_stack[i]);
2896          menu_list->menu_stack[i]    = NULL;
2897       }
2898 
2899       free(menu_list->menu_stack);
2900    }
2901 
2902    if (menu_list->selection_buf)
2903    {
2904       unsigned i;
2905 
2906       for (i = 0; i < menu_list->selection_buf_size; i++)
2907       {
2908          if (!menu_list->selection_buf[i])
2909             continue;
2910 
2911          menu_list_free_list(menu_driver_ctx,
2912                menu_list->selection_buf[i]);
2913          menu_list->selection_buf[i] = NULL;
2914       }
2915 
2916       free(menu_list->selection_buf);
2917    }
2918 
2919    free(menu_list);
2920 }
2921 
menu_list_new(const menu_ctx_driver_t * menu_driver_ctx)2922 static menu_list_t *menu_list_new(const menu_ctx_driver_t *menu_driver_ctx)
2923 {
2924    unsigned i;
2925    menu_list_t           *list = (menu_list_t*)malloc(sizeof(*list));
2926 
2927    if (!list)
2928       return NULL;
2929 
2930    list->menu_stack_size       = 1;
2931    list->selection_buf_size    = 1;
2932    list->selection_buf         = NULL;
2933    list->menu_stack            = (file_list_t**)
2934       calloc(list->menu_stack_size, sizeof(*list->menu_stack));
2935 
2936    if (!list->menu_stack)
2937       goto error;
2938 
2939    list->selection_buf         = (file_list_t**)
2940       calloc(list->selection_buf_size, sizeof(*list->selection_buf));
2941 
2942    if (!list->selection_buf)
2943       goto error;
2944 
2945    for (i = 0; i < list->menu_stack_size; i++)
2946    {
2947       list->menu_stack[i]           = (file_list_t*)
2948          malloc(sizeof(*list->menu_stack[i]));
2949       list->menu_stack[i]->list     = NULL;
2950       list->menu_stack[i]->capacity = 0;
2951       list->menu_stack[i]->size     = 0;
2952    }
2953 
2954    for (i = 0; i < list->selection_buf_size; i++)
2955    {
2956       list->selection_buf[i]           = (file_list_t*)
2957          malloc(sizeof(*list->selection_buf[i]));
2958       list->selection_buf[i]->list     = NULL;
2959       list->selection_buf[i]->capacity = 0;
2960       list->selection_buf[i]->size     = 0;
2961    }
2962 
2963    return list;
2964 
2965 error:
2966    menu_list_free(menu_driver_ctx, list);
2967    return NULL;
2968 }
2969 
menu_list_flush_stack_type(const char * needle,const char * label,unsigned type,unsigned final_type)2970 static int menu_list_flush_stack_type(const char *needle, const char *label,
2971       unsigned type, unsigned final_type)
2972 {
2973    return needle ? !string_is_equal(needle, label) : (type != final_type);
2974 }
2975 
menu_list_pop_stack(const menu_ctx_driver_t * menu_driver_ctx,void * menu_userdata,menu_list_t * list,size_t idx,size_t * directory_ptr)2976 static bool menu_list_pop_stack(
2977       const menu_ctx_driver_t *menu_driver_ctx,
2978       void *menu_userdata,
2979       menu_list_t *list,
2980       size_t idx,
2981       size_t *directory_ptr)
2982 {
2983    file_list_t *menu_list = MENU_LIST_GET(list, (unsigned)idx);
2984 
2985    if (!menu_list)
2986       return false;
2987 
2988    if (menu_list->size != 0)
2989    {
2990       menu_ctx_list_t list_info;
2991 
2992       list_info.list      = menu_list;
2993       list_info.idx       = menu_list->size - 1;
2994       list_info.list_size = menu_list->size - 1;
2995 
2996       menu_driver_list_free(menu_driver_ctx, &list_info);
2997    }
2998 
2999    file_list_pop(menu_list, directory_ptr);
3000    if (  menu_driver_ctx &&
3001          menu_driver_ctx->list_set_selection)
3002       menu_driver_ctx->list_set_selection(menu_userdata,
3003             menu_list);
3004 
3005    return true;
3006 }
3007 
menu_list_flush_stack(const menu_ctx_driver_t * menu_driver_ctx,void * menu_userdata,struct menu_state * menu_st,menu_list_t * list,size_t idx,const char * needle,unsigned final_type)3008 static void menu_list_flush_stack(
3009       const menu_ctx_driver_t *menu_driver_ctx,
3010       void *menu_userdata,
3011       struct menu_state *menu_st,
3012       menu_list_t *list,
3013       size_t idx, const char *needle, unsigned final_type)
3014 {
3015    bool refresh                = false;
3016    const char *path            = NULL;
3017    const char *label           = NULL;
3018    unsigned type               = 0;
3019    size_t entry_idx            = 0;
3020    file_list_t *menu_list      = MENU_LIST_GET(list, (unsigned)idx);
3021 
3022    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
3023 
3024    if (menu_list && menu_list->size)
3025       file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx);
3026 
3027    while (menu_list_flush_stack_type(
3028             needle, label, type, final_type) != 0)
3029    {
3030       bool refresh             = false;
3031       size_t new_selection_ptr = menu_st->selection_ptr;
3032       bool wont_pop_stack      = (MENU_LIST_GET_STACK_SIZE(list, idx) <= 1);
3033       if (wont_pop_stack)
3034          break;
3035 
3036       if (menu_driver_ctx->list_cache)
3037          menu_driver_ctx->list_cache(menu_userdata,
3038                MENU_LIST_PLAIN, 0);
3039 
3040       menu_list_pop_stack(menu_driver_ctx,
3041             menu_userdata,
3042             list, idx, &new_selection_ptr);
3043 
3044       menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
3045 
3046       menu_st->selection_ptr   = new_selection_ptr;
3047       menu_list                = MENU_LIST_GET(list, (unsigned)idx);
3048 
3049       if (menu_list && menu_list->size)
3050          file_list_get_at_offset(menu_list, menu_list->size - 1, &path, &label, &type, &entry_idx);
3051    }
3052 }
3053 
3054 /**
3055  * menu_entries_elem_get_first_char:
3056  * @list                     : File list handle.
3057  * @offset                   : Offset index of element.
3058  *
3059  * Gets the first character of an element in the
3060  * file list.
3061  *
3062  * Returns: first character of element in file list.
3063  **/
menu_entries_elem_get_first_char(file_list_t * list,unsigned offset)3064 static int menu_entries_elem_get_first_char(
3065       file_list_t *list, unsigned offset)
3066 {
3067    const char *path =   list->list[offset].alt
3068                       ? list->list[offset].alt
3069                       : list->list[offset].path;
3070    int ret          = path ? TOLOWER((int)*path) : 0;
3071 
3072    /* "Normalize" non-alphabetical entries so they
3073     * are lumped together for purposes of jumping. */
3074    if (ret < 'a')
3075       return ('a' - 1);
3076    else if (ret > 'z')
3077       return ('z' + 1);
3078    return ret;
3079 }
3080 
menu_entries_build_scroll_indices(struct menu_state * menu_st,file_list_t * list)3081 static void menu_entries_build_scroll_indices(
3082       struct menu_state *menu_st,
3083       file_list_t *list)
3084 {
3085    bool current_is_dir             = false;
3086    size_t i                        = 0;
3087    int current                     = menu_entries_elem_get_first_char(list, 0);
3088    unsigned type                   = list->list[0].type;
3089 
3090    menu_st->scroll.index_list[0]   = 0;
3091    menu_st->scroll.index_size      = 1;
3092 
3093    if (type == FILE_TYPE_DIRECTORY)
3094       current_is_dir               = true;
3095 
3096    for (i = 1; i < list->size; i++)
3097    {
3098       int first    = menu_entries_elem_get_first_char(list, (unsigned)i);
3099       bool is_dir  = false;
3100       unsigned idx = (unsigned)i;
3101 
3102       type         = list->list[idx].type;
3103 
3104       if (type == FILE_TYPE_DIRECTORY)
3105          is_dir = true;
3106 
3107       if ((current_is_dir && !is_dir) || (first > current))
3108       {
3109          /* Add scroll index */
3110          menu_st->scroll.index_list[menu_st->scroll.index_size]   = i;
3111          if (!((menu_st->scroll.index_size + 1) >= SCROLL_INDEX_SIZE))
3112             menu_st->scroll.index_size++;
3113       }
3114 
3115       current        = first;
3116       current_is_dir = is_dir;
3117    }
3118 
3119    /* Add scroll index */
3120    menu_st->scroll.index_list[menu_st->scroll.index_size]   = list->size - 1;
3121    if (!((menu_st->scroll.index_size + 1) >= SCROLL_INDEX_SIZE))
3122       menu_st->scroll.index_size++;
3123 }
3124 
menu_entries_get_last_stack_actiondata(void)3125 menu_file_list_cbs_t *menu_entries_get_last_stack_actiondata(void)
3126 {
3127    struct rarch_state *p_rarch = &rarch_st;
3128    struct menu_state  *menu_st = &p_rarch->menu_driver_state;
3129    if (menu_st->entries.list)
3130    {
3131       const file_list_t *list  = MENU_LIST_GET(menu_st->entries.list, 0);
3132       return (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata;
3133    }
3134    return NULL;
3135 }
3136 
3137 /* Sets title to what the name of the current menu should be. */
menu_entries_get_title(char * s,size_t len)3138 int menu_entries_get_title(char *s, size_t len)
3139 {
3140    unsigned menu_type            = 0;
3141    const char *path              = NULL;
3142    const char *label             = NULL;
3143    struct rarch_state   *p_rarch = &rarch_st;
3144    struct menu_state    *menu_st = &p_rarch->menu_driver_state;
3145    const file_list_t *list       = menu_st->entries.list ?
3146       MENU_LIST_GET(menu_st->entries.list, 0) : NULL;
3147    menu_file_list_cbs_t *cbs     = list
3148       ? (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata
3149       : NULL;
3150 
3151    if (!cbs)
3152       return -1;
3153 
3154    if (cbs && cbs->action_get_title)
3155    {
3156       int ret;
3157       if (!string_is_empty(cbs->action_title_cache))
3158       {
3159          strlcpy(s, cbs->action_title_cache, len);
3160          return 0;
3161       }
3162       file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
3163             &path, &label, &menu_type, NULL);
3164       ret = cbs->action_get_title(path, label, menu_type, s, len);
3165       if (ret == 1)
3166          strlcpy(cbs->action_title_cache, s, sizeof(cbs->action_title_cache));
3167       return ret;
3168    }
3169    return 0;
3170 }
3171 
3172 #if defined(_MSC_VER)
msvc_vercode_to_str(const unsigned vercode)3173 static const char * msvc_vercode_to_str(const unsigned vercode)
3174 {
3175    switch (vercode)
3176    {
3177       case 1200:
3178          return " msvc6";
3179       case 1300:
3180          return " msvc2002";
3181       case 1310:
3182          return " msvc2003";
3183       case 1400:
3184          return " msvc2005";
3185       case 1500:
3186          return " msvc2008";
3187       case 1600:
3188          return " msvc2010";
3189       case 1700:
3190          return " msvc2012";
3191       case 1800:
3192          return " msvc2013";
3193       case 1900:
3194          return " msvc2015";
3195       default:
3196          if (vercode >= 1910 && vercode < 1920)
3197             return " msvc2017";
3198          else if (vercode >= 1920 && vercode < 2000)
3199             return " msvc2019";
3200          break;
3201    }
3202 
3203    return "";
3204 }
3205 #endif
3206 
3207 /* Sets 's' to the name of the current core
3208  * (shown at the top of the UI). */
menu_entries_get_core_title(char * s,size_t len)3209 int menu_entries_get_core_title(char *s, size_t len)
3210 {
3211    struct retro_system_info    *system = &runloop_state.system.info;
3212    const char *core_name               = (system && !string_is_empty(system->library_name))
3213       ? system->library_name
3214       : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE);
3215    const char *core_version            = (system && system->library_version) ? system->library_version : "";
3216    if (!string_is_empty(core_version))
3217    {
3218 #if defined(_MSC_VER)
3219       snprintf(s, len, PACKAGE_VERSION "%s"        " - %s (%s)", msvc_vercode_to_str(_MSC_VER), core_name, core_version);
3220 #else
3221       snprintf(s, len, PACKAGE_VERSION             " - %s (%s)",                                core_name, core_version);
3222 #endif
3223    }
3224    else
3225    {
3226 #if defined(_MSC_VER)
3227       snprintf(s, len, PACKAGE_VERSION "%s"        " - %s", msvc_vercode_to_str(_MSC_VER), core_name);
3228 #else
3229       snprintf(s, len, PACKAGE_VERSION             " - %s",                                core_name);
3230 #endif
3231    }
3232 
3233    return 0;
3234 }
3235 
menu_entries_get_menu_stack_ptr(size_t idx)3236 file_list_t *menu_entries_get_menu_stack_ptr(size_t idx)
3237 {
3238    struct rarch_state   *p_rarch  = &rarch_st;
3239    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3240    menu_list_t *menu_list         = menu_st->entries.list;
3241    if (!menu_list)
3242       return NULL;
3243    return MENU_LIST_GET(menu_list, (unsigned)idx);
3244 }
3245 
menu_entries_get_selection_buf_ptr(size_t idx)3246 file_list_t *menu_entries_get_selection_buf_ptr(size_t idx)
3247 {
3248    struct rarch_state   *p_rarch  = &rarch_st;
3249    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3250    menu_list_t *menu_list         = menu_st->entries.list;
3251    if (!menu_list)
3252       return NULL;
3253    return MENU_LIST_GET_SELECTION(menu_list, (unsigned)idx);
3254 }
3255 
menu_entries_list_deinit(const menu_ctx_driver_t * menu_driver_ctx,struct menu_state * menu_st)3256 static void menu_entries_list_deinit(
3257       const menu_ctx_driver_t *menu_driver_ctx,
3258       struct menu_state *menu_st)
3259 {
3260    if (menu_st->entries.list)
3261       menu_list_free(menu_driver_ctx, menu_st->entries.list);
3262    menu_st->entries.list          = NULL;
3263 }
3264 
menu_entries_settings_deinit(struct menu_state * menu_st)3265 static void menu_entries_settings_deinit(struct menu_state *menu_st)
3266 {
3267    menu_setting_free(menu_st->entries.list_settings);
3268    if (menu_st->entries.list_settings)
3269       free(menu_st->entries.list_settings);
3270    menu_st->entries.list_settings = NULL;
3271 }
3272 
3273 
menu_entries_init(struct menu_state * menu_st,const menu_ctx_driver_t * menu_driver_ctx)3274 static bool menu_entries_init(
3275       struct menu_state *menu_st,
3276       const menu_ctx_driver_t *menu_driver_ctx
3277       )
3278 {
3279    if (!(menu_st->entries.list = (menu_list_t*)menu_list_new(menu_driver_ctx)))
3280       return false;
3281    if (!(menu_st->entries.list_settings = menu_setting_new()))
3282       return false;
3283    return true;
3284 }
3285 
menu_entries_append(file_list_t * list,const char * path,const char * label,unsigned type,size_t directory_ptr,size_t entry_idx)3286 void menu_entries_append(
3287       file_list_t *list,
3288       const char *path,
3289       const char *label,
3290       unsigned type,
3291       size_t directory_ptr,
3292       size_t entry_idx)
3293 {
3294    menu_ctx_list_t list_info;
3295    size_t i;
3296    size_t idx;
3297    const char *menu_path           = NULL;
3298    menu_file_list_cbs_t *cbs       = NULL;
3299    struct rarch_state   *p_rarch   = &rarch_st;
3300    struct menu_state    *menu_st   = &p_rarch->menu_driver_state;
3301    if (!list || !label)
3302       return;
3303 
3304    file_list_append(list, path, label, type, directory_ptr, entry_idx);
3305    file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
3306          &menu_path, NULL, NULL, NULL);
3307 
3308    idx                = list->size - 1;
3309 
3310    list_info.list     = list;
3311    list_info.path     = path;
3312    list_info.fullpath = NULL;
3313 
3314    if (!string_is_empty(menu_path))
3315       list_info.fullpath = strdup(menu_path);
3316 
3317    list_info.label       = label;
3318    list_info.idx         = idx;
3319    list_info.entry_type  = type;
3320 
3321    if (  p_rarch->menu_driver_ctx &&
3322          p_rarch->menu_driver_ctx->list_insert)
3323       p_rarch->menu_driver_ctx->list_insert(
3324             p_rarch->menu_userdata,
3325             list_info.list,
3326             list_info.path,
3327             list_info.fullpath,
3328             list_info.label,
3329             list_info.idx,
3330             list_info.entry_type);
3331 
3332    if (list_info.fullpath)
3333       free(list_info.fullpath);
3334 
3335    file_list_free_actiondata(list, idx);
3336    cbs                             = (menu_file_list_cbs_t*)
3337       malloc(sizeof(menu_file_list_cbs_t));
3338 
3339    if (!cbs)
3340       return;
3341 
3342    cbs->action_sublabel_cache[0]   = '\0';
3343    cbs->action_title_cache[0]      = '\0';
3344    cbs->enum_idx                   = MSG_UNKNOWN;
3345    cbs->checked                    = false;
3346    cbs->setting                    = menu_setting_find(label);
3347    cbs->action_iterate             = NULL;
3348    cbs->action_deferred_push       = NULL;
3349    cbs->action_select              = NULL;
3350    cbs->action_get_title           = NULL;
3351    cbs->action_ok                  = NULL;
3352    cbs->action_cancel              = NULL;
3353    cbs->action_scan                = NULL;
3354    cbs->action_start               = NULL;
3355    cbs->action_info                = NULL;
3356    cbs->action_left                = NULL;
3357    cbs->action_right               = NULL;
3358    cbs->action_label               = NULL;
3359    cbs->action_sublabel            = NULL;
3360    cbs->action_get_value           = NULL;
3361 
3362    cbs->search.size                = 0;
3363    for (i = 0; i < MENU_SEARCH_FILTER_MAX_TERMS; i++)
3364       cbs->search.terms[i][0]      = '\0';
3365 
3366    list->list[idx].actiondata      = cbs;
3367 
3368    menu_cbs_init(&p_rarch->menu_driver_state,
3369          p_rarch->menu_driver_ctx,
3370          list, cbs, path, label, type, idx);
3371 }
3372 
menu_entries_append_enum(file_list_t * list,const char * path,const char * label,enum msg_hash_enums enum_idx,unsigned type,size_t directory_ptr,size_t entry_idx)3373 bool menu_entries_append_enum(
3374       file_list_t *list,
3375       const char *path,
3376       const char *label,
3377       enum msg_hash_enums enum_idx,
3378       unsigned type,
3379       size_t directory_ptr,
3380       size_t entry_idx)
3381 {
3382    menu_ctx_list_t list_info;
3383    size_t i;
3384    size_t idx;
3385    const char *menu_path           = NULL;
3386    menu_file_list_cbs_t *cbs       = NULL;
3387    struct rarch_state   *p_rarch   = &rarch_st;
3388    struct menu_state    *menu_st   = &p_rarch->menu_driver_state;
3389 
3390    if (!list || !label)
3391       return false;
3392 
3393    file_list_append(list, path, label, type, directory_ptr, entry_idx);
3394    file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
3395          &menu_path, NULL, NULL, NULL);
3396 
3397    idx                   = list->size - 1;
3398 
3399    list_info.fullpath    = NULL;
3400 
3401    if (!string_is_empty(menu_path))
3402       list_info.fullpath = strdup(menu_path);
3403    list_info.list        = list;
3404    list_info.path        = path;
3405    list_info.label       = label;
3406    list_info.idx         = idx;
3407    list_info.entry_type  = type;
3408 
3409    if (  p_rarch->menu_driver_ctx &&
3410          p_rarch->menu_driver_ctx->list_insert)
3411       p_rarch->menu_driver_ctx->list_insert(
3412             p_rarch->menu_userdata,
3413             list_info.list,
3414             list_info.path,
3415             list_info.fullpath,
3416             list_info.label,
3417             list_info.idx,
3418             list_info.entry_type);
3419 
3420    if (list_info.fullpath)
3421       free(list_info.fullpath);
3422 
3423    file_list_free_actiondata(list, idx);
3424    cbs                             = (menu_file_list_cbs_t*)
3425       malloc(sizeof(menu_file_list_cbs_t));
3426 
3427    if (!cbs)
3428       return false;
3429 
3430    cbs->action_sublabel_cache[0]   = '\0';
3431    cbs->action_title_cache[0]      = '\0';
3432    cbs->enum_idx                   = enum_idx;
3433    cbs->checked                    = false;
3434    cbs->setting                    = NULL;
3435    cbs->action_iterate             = NULL;
3436    cbs->action_deferred_push       = NULL;
3437    cbs->action_select              = NULL;
3438    cbs->action_get_title           = NULL;
3439    cbs->action_ok                  = NULL;
3440    cbs->action_cancel              = NULL;
3441    cbs->action_scan                = NULL;
3442    cbs->action_start               = NULL;
3443    cbs->action_info                = NULL;
3444    cbs->action_left                = NULL;
3445    cbs->action_right               = NULL;
3446    cbs->action_label               = NULL;
3447    cbs->action_sublabel            = NULL;
3448    cbs->action_get_value           = NULL;
3449 
3450    cbs->search.size                = 0;
3451    for (i = 0; i < MENU_SEARCH_FILTER_MAX_TERMS; i++)
3452       cbs->search.terms[i][0]      = '\0';
3453 
3454    list->list[idx].actiondata      = cbs;
3455 
3456    if (   enum_idx != MENU_ENUM_LABEL_PLAYLIST_ENTRY
3457        && enum_idx != MENU_ENUM_LABEL_PLAYLIST_COLLECTION_ENTRY
3458        && enum_idx != MENU_ENUM_LABEL_EXPLORE_ITEM
3459        && enum_idx != MENU_ENUM_LABEL_RDB_ENTRY)
3460       cbs->setting                 = menu_setting_find_enum(enum_idx);
3461 
3462    menu_cbs_init(&p_rarch->menu_driver_state,
3463          p_rarch->menu_driver_ctx,
3464          list, cbs, path, label, type, idx);
3465 
3466    return true;
3467 }
3468 
menu_entries_prepend(file_list_t * list,const char * path,const char * label,enum msg_hash_enums enum_idx,unsigned type,size_t directory_ptr,size_t entry_idx)3469 void menu_entries_prepend(file_list_t *list,
3470       const char *path, const char *label,
3471       enum msg_hash_enums enum_idx,
3472       unsigned type, size_t directory_ptr, size_t entry_idx)
3473 {
3474    menu_ctx_list_t list_info;
3475    size_t i;
3476    size_t idx                      = 0;
3477    const char *menu_path           = NULL;
3478    menu_file_list_cbs_t *cbs       = NULL;
3479    struct rarch_state   *p_rarch   = &rarch_st;
3480    struct menu_state    *menu_st   = &p_rarch->menu_driver_state;
3481    if (!list || !label)
3482       return;
3483 
3484    file_list_prepend(list, path, label, type, directory_ptr, entry_idx);
3485    file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
3486          &menu_path, NULL, NULL, NULL);
3487 
3488    list_info.fullpath    = NULL;
3489 
3490    if (!string_is_empty(menu_path))
3491       list_info.fullpath = strdup(menu_path);
3492    list_info.list        = list;
3493    list_info.path        = path;
3494    list_info.label       = label;
3495    list_info.idx         = idx;
3496    list_info.entry_type  = type;
3497 
3498    if (  p_rarch->menu_driver_ctx &&
3499          p_rarch->menu_driver_ctx->list_insert)
3500       p_rarch->menu_driver_ctx->list_insert(
3501             p_rarch->menu_userdata,
3502             list_info.list,
3503             list_info.path,
3504             list_info.fullpath,
3505             list_info.label,
3506             list_info.idx,
3507             list_info.entry_type);
3508 
3509    if (list_info.fullpath)
3510       free(list_info.fullpath);
3511 
3512    file_list_free_actiondata(list, idx);
3513    cbs                             = (menu_file_list_cbs_t*)
3514       malloc(sizeof(menu_file_list_cbs_t));
3515 
3516    if (!cbs)
3517       return;
3518 
3519    cbs->action_sublabel_cache[0]   = '\0';
3520    cbs->action_title_cache[0]      = '\0';
3521    cbs->enum_idx                   = enum_idx;
3522    cbs->checked                    = false;
3523    cbs->setting                    = menu_setting_find_enum(cbs->enum_idx);
3524    cbs->action_iterate             = NULL;
3525    cbs->action_deferred_push       = NULL;
3526    cbs->action_select              = NULL;
3527    cbs->action_get_title           = NULL;
3528    cbs->action_ok                  = NULL;
3529    cbs->action_cancel              = NULL;
3530    cbs->action_scan                = NULL;
3531    cbs->action_start               = NULL;
3532    cbs->action_info                = NULL;
3533    cbs->action_left                = NULL;
3534    cbs->action_right               = NULL;
3535    cbs->action_label               = NULL;
3536    cbs->action_sublabel            = NULL;
3537    cbs->action_get_value           = NULL;
3538 
3539    cbs->search.size                = 0;
3540    for (i = 0; i < MENU_SEARCH_FILTER_MAX_TERMS; i++)
3541       cbs->search.terms[i][0]      = '\0';
3542 
3543    list->list[idx].actiondata      = cbs;
3544 
3545    menu_cbs_init(&p_rarch->menu_driver_state,
3546          p_rarch->menu_driver_ctx,
3547          list, cbs, path, label, type, idx);
3548 }
3549 
menu_entries_get_last_stack(const char ** path,const char ** label,unsigned * file_type,enum msg_hash_enums * enum_idx,size_t * entry_idx)3550 void menu_entries_get_last_stack(const char **path, const char **label,
3551       unsigned *file_type, enum msg_hash_enums *enum_idx, size_t *entry_idx)
3552 {
3553    file_list_t *list              = NULL;
3554    struct rarch_state   *p_rarch  = &rarch_st;
3555    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3556    if (!menu_st->entries.list)
3557       return;
3558 
3559    list                           = MENU_LIST_GET(menu_st->entries.list, 0);
3560 
3561    if (list && list->size)
3562       file_list_get_at_offset(list, list->size - 1, path, label, file_type, entry_idx);
3563 
3564    if (enum_idx)
3565    {
3566       menu_file_list_cbs_t *cbs  = (menu_file_list_cbs_t*)
3567          list->list[list->size - 1].actiondata;
3568 
3569       if (cbs)
3570          *enum_idx = cbs->enum_idx;
3571    }
3572 }
3573 
menu_entries_flush_stack(const char * needle,unsigned final_type)3574 void menu_entries_flush_stack(const char *needle, unsigned final_type)
3575 {
3576    struct rarch_state   *p_rarch  = &rarch_st;
3577    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3578    menu_list_t *menu_list         = menu_st->entries.list;
3579    if (menu_list)
3580       menu_list_flush_stack(
3581             p_rarch->menu_driver_ctx,
3582             p_rarch->menu_userdata,
3583             menu_st,
3584             menu_list, 0, needle, final_type);
3585 }
3586 
menu_entries_pop_stack(size_t * ptr,size_t idx,bool animate)3587 void menu_entries_pop_stack(size_t *ptr, size_t idx, bool animate)
3588 {
3589    struct rarch_state   *p_rarch            = &rarch_st;
3590    const menu_ctx_driver_t *menu_driver_ctx = p_rarch->menu_driver_ctx;
3591    struct menu_state    *menu_st            = &p_rarch->menu_driver_state;
3592    menu_list_t *menu_list                   = menu_st->entries.list;
3593    if (!menu_list)
3594       return;
3595 
3596    if (MENU_LIST_GET_STACK_SIZE(menu_list, idx) > 1)
3597    {
3598       bool refresh             = false;
3599       if (animate)
3600       {
3601          if (menu_driver_ctx->list_cache)
3602             menu_driver_ctx->list_cache(p_rarch->menu_userdata,
3603                   MENU_LIST_PLAIN, 0);
3604       }
3605       menu_list_pop_stack(menu_driver_ctx,
3606             p_rarch->menu_userdata, menu_list, idx, ptr);
3607 
3608       if (animate)
3609          menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
3610    }
3611 }
3612 
menu_entries_get_stack_size(size_t idx)3613 size_t menu_entries_get_stack_size(size_t idx)
3614 {
3615    struct rarch_state   *p_rarch  = &rarch_st;
3616    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3617    menu_list_t *menu_list         = menu_st->entries.list;
3618    if (!menu_list)
3619       return 0;
3620    return MENU_LIST_GET_STACK_SIZE(menu_list, idx);
3621 }
3622 
menu_entries_get_size(void)3623 size_t menu_entries_get_size(void)
3624 {
3625    struct rarch_state   *p_rarch  = &rarch_st;
3626    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3627    menu_list_t *menu_list         = menu_st->entries.list;
3628    if (!menu_list)
3629       return 0;
3630    return MENU_LIST_GET_SELECTION(menu_list, 0)->size;
3631 }
3632 
menu_entries_ctl(enum menu_entries_ctl_state state,void * data)3633 bool menu_entries_ctl(enum menu_entries_ctl_state state, void *data)
3634 {
3635    struct rarch_state   *p_rarch  = &rarch_st;
3636    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
3637 
3638    switch (state)
3639    {
3640       case MENU_ENTRIES_CTL_NEEDS_REFRESH:
3641          return MENU_ENTRIES_NEEDS_REFRESH(menu_st);
3642       case MENU_ENTRIES_CTL_SETTINGS_GET:
3643          {
3644             rarch_setting_t **settings  = (rarch_setting_t**)data;
3645             if (!settings)
3646                return false;
3647             *settings = menu_st->entries.list_settings;
3648          }
3649          break;
3650       case MENU_ENTRIES_CTL_SET_REFRESH:
3651          {
3652             bool *nonblocking = (bool*)data;
3653 
3654             if (*nonblocking)
3655                menu_st->entries_nonblocking_refresh = true;
3656             else
3657                menu_st->entries_need_refresh        = true;
3658          }
3659          break;
3660       case MENU_ENTRIES_CTL_UNSET_REFRESH:
3661          {
3662             bool *nonblocking = (bool*)data;
3663 
3664             if (*nonblocking)
3665                menu_st->entries_nonblocking_refresh = false;
3666             else
3667                menu_st->entries_need_refresh        = false;
3668          }
3669          break;
3670       case MENU_ENTRIES_CTL_SET_START:
3671          {
3672             size_t *idx = (size_t*)data;
3673             if (idx)
3674                menu_st->entries.begin = *idx;
3675          }
3676       case MENU_ENTRIES_CTL_START_GET:
3677          {
3678             size_t *idx = (size_t*)data;
3679             if (!idx)
3680                return 0;
3681 
3682             *idx = menu_st->entries.begin;
3683          }
3684          break;
3685       case MENU_ENTRIES_CTL_REFRESH:
3686          /**
3687           * Before a refresh, we could have deleted a
3688           * file on disk, causing selection_ptr to
3689           * suddendly be out of range.
3690           *
3691           * Ensure it doesn't overflow.
3692           **/
3693          {
3694             size_t list_size;
3695             file_list_t *list               = (file_list_t*)data;
3696             if (!list)
3697                return false;
3698             if (list->size)
3699                menu_entries_build_scroll_indices(menu_st, list);
3700             list_size                       = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0;
3701 
3702             if (list_size)
3703             {
3704                size_t          selection    = menu_st->selection_ptr;
3705                if (selection >= list_size)
3706                {
3707                   size_t idx                = list_size - 1;
3708                   menu_st->selection_ptr    = idx;
3709 
3710                   menu_driver_navigation_set(true);
3711                }
3712             }
3713             else
3714             {
3715                bool pending_push = true;
3716                menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
3717             }
3718          }
3719          break;
3720       case MENU_ENTRIES_CTL_CLEAR:
3721          {
3722             unsigned i;
3723             file_list_t *list = (file_list_t*)data;
3724 
3725             if (!list)
3726                return false;
3727 
3728             /* Clear all the menu lists. */
3729             if (p_rarch->menu_driver_ctx->list_clear)
3730                p_rarch->menu_driver_ctx->list_clear(list);
3731 
3732             for (i = 0; i < list->size; i++)
3733             {
3734                if (list->list[i].actiondata)
3735                   free(list->list[i].actiondata);
3736                list->list[i].actiondata = NULL;
3737             }
3738 
3739             file_list_clear(list);
3740          }
3741          break;
3742       case MENU_ENTRIES_CTL_SHOW_BACK:
3743          /* Returns true if a Back button should be shown
3744           * (i.e. we are at least
3745           * one level deep in the menu hierarchy). */
3746          if (!menu_st->entries.list)
3747             return false;
3748          return (MENU_LIST_GET_STACK_SIZE(menu_st->entries.list, 0) > 1);
3749       case MENU_ENTRIES_CTL_NONE:
3750       default:
3751          break;
3752    }
3753 
3754    return true;
3755 }
3756 
menu_entries_search_get_terms_internal(void)3757 static menu_serch_terms_t *menu_entries_search_get_terms_internal(void)
3758 {
3759    struct rarch_state *p_rarch = &rarch_st;
3760    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
3761    file_list_t *list           = MENU_LIST_GET(menu_st->entries.list, 0);
3762    menu_file_list_cbs_t *cbs   = NULL;
3763 
3764    if (!list ||
3765        (list->size < 1))
3766       return NULL;
3767 
3768    cbs = (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata;
3769 
3770    if (!cbs)
3771       return NULL;
3772 
3773    return &cbs->search;
3774 }
3775 
menu_entries_search_push(const char * search_term)3776 bool menu_entries_search_push(const char *search_term)
3777 {
3778    menu_serch_terms_t *search = menu_entries_search_get_terms_internal();
3779    char search_term_clipped[MENU_SEARCH_FILTER_MAX_LENGTH];
3780    size_t i;
3781 
3782    search_term_clipped[0] = '\0';
3783 
3784    /* Sanity check + verify whether we have reached
3785     * the maximum number of allowed search terms */
3786    if (!search ||
3787        string_is_empty(search_term) ||
3788        (search->size >= MENU_SEARCH_FILTER_MAX_TERMS))
3789       return false;
3790 
3791    /* Check whether search term already exists
3792     * > Note that we clip the input search term
3793     *   to MENU_SEARCH_FILTER_MAX_LENGTH characters
3794     *   *before* comparing existing entries */
3795    strlcpy(search_term_clipped, search_term,
3796          sizeof(search_term_clipped));
3797 
3798    for (i = 0; i < search->size; i++)
3799    {
3800       if (string_is_equal(search_term_clipped,
3801             search->terms[i]))
3802          return false;
3803    }
3804 
3805    /* Add search term */
3806    strlcpy(search->terms[search->size], search_term_clipped,
3807          sizeof(search->terms[search->size]));
3808    search->size++;
3809 
3810    return true;
3811 }
3812 
menu_entries_search_pop(void)3813 bool menu_entries_search_pop(void)
3814 {
3815    menu_serch_terms_t *search = menu_entries_search_get_terms_internal();
3816 
3817    /* Do nothing if list of search terms is empty */
3818    if (!search ||
3819        (search->size == 0))
3820       return false;
3821 
3822    /* Remove last item from the list */
3823    search->size--;
3824    search->terms[search->size][0] = '\0';
3825 
3826    return true;
3827 }
3828 
menu_entries_search_get_terms(void)3829 menu_serch_terms_t *menu_entries_search_get_terms(void)
3830 {
3831    menu_serch_terms_t *search = menu_entries_search_get_terms_internal();
3832 
3833    if (!search ||
3834        (search->size == 0))
3835       return NULL;
3836 
3837    return search;
3838 }
3839 
3840 /* Convenience function: Appends list of current
3841  * search terms to specified string */
menu_entries_search_append_terms_string(char * s,size_t len)3842 void menu_entries_search_append_terms_string(char *s, size_t len)
3843 {
3844    menu_serch_terms_t *search = menu_entries_search_get_terms_internal();
3845 
3846    if (search &&
3847        (search->size > 0) &&
3848        s)
3849    {
3850       size_t current_len = strlen_size(s, len);
3851       size_t i;
3852 
3853       /* If buffer is already 'full', nothing
3854        * further can be added */
3855       if (current_len >= len)
3856          return;
3857 
3858       s   += current_len;
3859       len -= current_len;
3860 
3861       for (i = 0; i < search->size; i++)
3862       {
3863          strlcat(s, " > ", len);
3864          strlcat(s, search->terms[i], len);
3865       }
3866    }
3867 }
3868 
3869 /* Searches current menu list for specified 'needle'
3870  * string. If string is found, returns true and sets
3871  * 'idx' to the matching list entry index. */
menu_entries_list_search(const char * needle,size_t * idx)3872 bool menu_entries_list_search(const char *needle, size_t *idx)
3873 {
3874    struct rarch_state *p_rarch = &rarch_st;
3875    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
3876    menu_list_t *menu_list      = menu_st->entries.list;
3877    file_list_t *list           = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0);
3878    bool match_found            = false;
3879    bool char_search            = false;
3880    char needle_char            = 0;
3881    size_t i;
3882 
3883    if (!list ||
3884        string_is_empty(needle) ||
3885        !idx)
3886       goto end;
3887 
3888    /* Check if we are searching for a single
3889     * Latin alphabet character */
3890    char_search    = ((needle[1] == '\0') && (ISALPHA(needle[0])));
3891    if (char_search)
3892       needle_char = TOLOWER(needle[0]);
3893 
3894    for (i = 0; i < list->size; i++)
3895    {
3896       const char *entry_label = NULL;
3897       menu_entry_t entry;
3898 
3899       /* Note the we have to get the actual menu
3900        * entry here, since we need the exact label
3901        * that is currently displayed by the menu
3902        * driver */
3903       MENU_ENTRY_INIT(entry);
3904       entry.value_enabled    = false;
3905       entry.sublabel_enabled = false;
3906       menu_entry_get(&entry, 0, i, NULL, true);
3907 
3908       /* When using the file browser, one or more
3909        * 'utility' entries will be added to the top
3910        * of the list (e.g. 'Parent Directory'). These
3911        * have no bearing on the actual content of the
3912        * list, and should be excluded from the search */
3913       if ((entry.type == FILE_TYPE_SCAN_DIRECTORY) ||
3914           (entry.type == FILE_TYPE_MANUAL_SCAN_DIRECTORY) ||
3915           (entry.type == FILE_TYPE_USE_DIRECTORY) ||
3916           (entry.type == FILE_TYPE_PARENT_DIRECTORY))
3917          continue;
3918 
3919       /* Get displayed entry label */
3920       if (!string_is_empty(entry.rich_label))
3921          entry_label = entry.rich_label;
3922       else
3923          entry_label = entry.path;
3924 
3925       if (string_is_empty(entry_label))
3926          continue;
3927 
3928       /* If we are performing a single character
3929        * search, jump to the first entry whose
3930        * first character matches */
3931       if (char_search)
3932       {
3933          if (needle_char == TOLOWER(entry_label[0]))
3934          {
3935             *idx        = i;
3936             match_found = true;
3937             break;
3938          }
3939       }
3940       /* Otherwise perform an exhaustive string
3941        * comparison */
3942       else
3943       {
3944          const char *found_str = (const char *)strcasestr(entry_label, needle);
3945 
3946          /* Found a match with the first characters
3947           * of the label -> best possible match,
3948           * so quit immediately */
3949          if (found_str == entry_label)
3950          {
3951             *idx        = i;
3952             match_found = true;
3953             break;
3954          }
3955          /* Found a mid-string match; this is a valid
3956           * result, but keep searching for the best
3957           * possible match */
3958          else if (found_str)
3959          {
3960             *idx        = i;
3961             match_found = true;
3962          }
3963       }
3964    }
3965 
3966 end:
3967    return match_found;
3968 }
3969 
menu_display_common_image_upload(const menu_ctx_driver_t * menu_driver_ctx,void * menu_userdata,struct texture_image * img,void * user_data,unsigned type)3970 static void menu_display_common_image_upload(
3971       const menu_ctx_driver_t *menu_driver_ctx,
3972       void *menu_userdata,
3973       struct texture_image *img,
3974       void *user_data,
3975       unsigned type)
3976 {
3977    if (     menu_driver_ctx
3978          && menu_driver_ctx->load_image)
3979       menu_driver_ctx->load_image(menu_userdata,
3980             img, (enum menu_image_type)type);
3981 
3982    image_texture_free(img);
3983    free(img);
3984    free(user_data);
3985 }
3986 
3987 /* TODO/FIXME - seems only RGUI uses this - can this be
3988  * refactored away or we can have one common function used
3989  * across all menu drivers? */
3990 #ifdef HAVE_RGUI
menu_display_handle_thumbnail_upload(retro_task_t * task,void * task_data,void * user_data,const char * err)3991 void menu_display_handle_thumbnail_upload(
3992       retro_task_t *task,
3993       void *task_data,
3994       void *user_data, const char *err)
3995 {
3996    struct rarch_state   *p_rarch  = &rarch_st;
3997    menu_display_common_image_upload(
3998          p_rarch->menu_driver_ctx,
3999          p_rarch->menu_userdata,
4000          (struct texture_image*)task_data,
4001          user_data,
4002          MENU_IMAGE_THUMBNAIL);
4003 }
4004 
menu_display_handle_left_thumbnail_upload(retro_task_t * task,void * task_data,void * user_data,const char * err)4005 void menu_display_handle_left_thumbnail_upload(
4006       retro_task_t *task,
4007       void *task_data,
4008       void *user_data, const char *err)
4009 {
4010    struct rarch_state   *p_rarch  = &rarch_st;
4011    menu_display_common_image_upload(
4012          p_rarch->menu_driver_ctx,
4013          p_rarch->menu_userdata,
4014          (struct texture_image*)task_data,
4015          user_data,
4016          MENU_IMAGE_LEFT_THUMBNAIL);
4017 }
4018 #endif
4019 
menu_display_handle_savestate_thumbnail_upload(retro_task_t * task,void * task_data,void * user_data,const char * err)4020 void menu_display_handle_savestate_thumbnail_upload(
4021       retro_task_t *task,
4022       void *task_data,
4023       void *user_data, const char *err)
4024 {
4025    struct rarch_state   *p_rarch  = &rarch_st;
4026    menu_display_common_image_upload(
4027          p_rarch->menu_driver_ctx,
4028          p_rarch->menu_userdata,
4029          (struct texture_image*)task_data,
4030          user_data,
4031          MENU_IMAGE_SAVESTATE_THUMBNAIL);
4032 }
4033 
4034 /* Function that gets called when we want to load in a
4035  * new menu wallpaper.
4036  */
menu_display_handle_wallpaper_upload(retro_task_t * task,void * task_data,void * user_data,const char * err)4037 void menu_display_handle_wallpaper_upload(
4038       retro_task_t *task,
4039       void *task_data,
4040       void *user_data, const char *err)
4041 {
4042    struct rarch_state   *p_rarch  = &rarch_st;
4043    menu_display_common_image_upload(
4044          p_rarch->menu_driver_ctx,
4045          p_rarch->menu_userdata,
4046          (struct texture_image*)task_data,
4047          user_data,
4048          MENU_IMAGE_WALLPAPER);
4049 }
4050 
4051 /**
4052  * config_get_menu_driver_options:
4053  *
4054  * Get an enumerated list of all menu driver names,
4055  * separated by '|'.
4056  *
4057  * Returns: string listing of all menu driver names,
4058  * separated by '|'.
4059  **/
config_get_menu_driver_options(void)4060 const char *config_get_menu_driver_options(void)
4061 {
4062    return char_list_new_special(STRING_LIST_MENU_DRIVERS, NULL);
4063 }
4064 
4065 #ifdef HAVE_COMPRESSION
4066 /* This function gets called at first startup on Android/iOS
4067  * when we need to extract the APK contents/zip file. This
4068  * file contains assets which then get extracted to the
4069  * user's asset directories. */
bundle_decompressed(retro_task_t * task,void * task_data,void * user_data,const char * err)4070 static void bundle_decompressed(retro_task_t *task,
4071       void *task_data,
4072       void *user_data, const char *err)
4073 {
4074    struct rarch_state *p_rarch = &rarch_st;
4075    settings_t        *settings = p_rarch->configuration_settings;
4076    decompress_task_data_t *dec = (decompress_task_data_t*)task_data;
4077 
4078    if (err)
4079       RARCH_ERR("%s", err);
4080 
4081    if (dec)
4082    {
4083       if (!err)
4084          command_event(CMD_EVENT_REINIT, NULL);
4085 
4086       /* delete bundle? */
4087       free(dec->source_file);
4088       free(dec);
4089    }
4090 
4091    configuration_set_uint(settings,
4092          settings->uints.bundle_assets_extract_last_version,
4093          settings->uints.bundle_assets_extract_version_current);
4094 
4095    configuration_set_bool(settings, settings->bools.bundle_finished, true);
4096 
4097    command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
4098 }
4099 #endif
4100 
4101 /**
4102  * menu_init:
4103  * @data                     : Menu context handle.
4104  *
4105  * Create and initialize menu handle.
4106  *
4107  * Returns: menu handle on success, otherwise NULL.
4108  **/
menu_init(struct menu_state * menu_st,menu_dialog_t * p_dialog,const menu_ctx_driver_t * menu_driver_ctx,menu_input_t * menu_input,menu_input_pointer_hw_state_t * pointer_hw_state,settings_t * settings)4109 static bool menu_init(
4110       struct menu_state *menu_st,
4111       menu_dialog_t        *p_dialog,
4112       const menu_ctx_driver_t *menu_driver_ctx,
4113       menu_input_t *menu_input,
4114       menu_input_pointer_hw_state_t *pointer_hw_state,
4115       settings_t *settings
4116       )
4117 {
4118 #ifdef HAVE_CONFIGFILE
4119    bool menu_show_start_screen = settings->bools.menu_show_start_screen;
4120    bool config_save_on_exit    = settings->bools.config_save_on_exit;
4121 #endif
4122 
4123    /* Ensure that menu pointer input is correctly
4124     * initialised */
4125    memset(menu_input, 0, sizeof(menu_input_t));
4126    memset(pointer_hw_state, 0, sizeof(menu_input_pointer_hw_state_t));
4127 
4128    if (!menu_entries_init(menu_st, menu_driver_ctx))
4129    {
4130       menu_entries_settings_deinit(menu_st);
4131       menu_entries_list_deinit(menu_driver_ctx, menu_st);
4132       return false;
4133    }
4134 
4135 #ifdef HAVE_CONFIGFILE
4136    if (menu_show_start_screen)
4137    {
4138       /* We don't want the welcome dialog screen to show up
4139        * again after the first startup, so we save to config
4140        * file immediately. */
4141       p_dialog->current_type         = MENU_DIALOG_WELCOME;
4142 
4143       configuration_set_bool(settings,
4144             settings->bools.menu_show_start_screen, false);
4145       if (config_save_on_exit)
4146          command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
4147    }
4148 #endif
4149 
4150 #ifdef HAVE_COMPRESSION
4151    if (      settings->bools.bundle_assets_extract_enable
4152          && !string_is_empty(settings->arrays.bundle_assets_src)
4153          && !string_is_empty(settings->arrays.bundle_assets_dst)
4154          && (settings->uints.bundle_assets_extract_version_current
4155             != settings->uints.bundle_assets_extract_last_version)
4156       )
4157    {
4158       p_dialog->current_type         = MENU_DIALOG_HELP_EXTRACT;
4159       task_push_decompress(
4160             settings->arrays.bundle_assets_src,
4161             settings->arrays.bundle_assets_dst,
4162             NULL,
4163             settings->arrays.bundle_assets_dst_subdir,
4164             NULL,
4165             bundle_decompressed,
4166             NULL,
4167             NULL,
4168             false);
4169       /* Support only 1 version - setting this would prevent the assets from being extracted every time */
4170       configuration_set_int(settings,
4171             settings->uints.bundle_assets_extract_last_version, 1);
4172    }
4173 #endif
4174 
4175 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
4176    menu_shader_manager_init();
4177 #endif
4178 
4179    return true;
4180 }
4181 
menu_driver_ident(void)4182 const char *menu_driver_ident(void)
4183 {
4184    struct rarch_state   *p_rarch  = &rarch_st;
4185    if (p_rarch->menu_driver_alive)
4186       if (p_rarch->menu_driver_ctx && p_rarch->menu_driver_ctx->ident)
4187          return p_rarch->menu_driver_ctx->ident;
4188    return NULL;
4189 }
4190 
menu_driver_frame(bool menu_is_alive,video_frame_info_t * video_info)4191 void menu_driver_frame(bool menu_is_alive, video_frame_info_t *video_info)
4192 {
4193    struct rarch_state   *p_rarch  = &rarch_st;
4194    if (menu_is_alive && p_rarch->menu_driver_ctx->frame)
4195       p_rarch->menu_driver_ctx->frame(p_rarch->menu_userdata, video_info);
4196 }
4197 
4198 /* Time format strings with AM-PM designation require special
4199  * handling due to platform dependence */
strftime_am_pm(char * ptr,size_t maxsize,const char * format,const struct tm * timeptr)4200 static void strftime_am_pm(char* ptr, size_t maxsize, const char* format,
4201       const struct tm* timeptr)
4202 {
4203    char *local = NULL;
4204 
4205    /* Ensure correct locale is set
4206     * > Required for localised AM/PM strings */
4207    setlocale(LC_TIME, "");
4208 
4209    strftime(ptr, maxsize, format, timeptr);
4210 #if !(defined(__linux__) && !defined(ANDROID))
4211    local = local_to_utf8_string_alloc(ptr);
4212 
4213    if (!string_is_empty(local))
4214       strlcpy(ptr, local, maxsize);
4215 
4216    if (local)
4217    {
4218       free(local);
4219       local = NULL;
4220    }
4221 #endif
4222 }
4223 
4224 /* Display the date and time - time_mode will influence how
4225  * the time representation will look like.
4226  * */
menu_display_timedate(gfx_display_ctx_datetime_t * datetime)4227 void menu_display_timedate(gfx_display_ctx_datetime_t *datetime)
4228 {
4229    struct rarch_state   *p_rarch  = &rarch_st;
4230    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
4231    if (!datetime)
4232       return;
4233 
4234    /* Trigger an update, if required */
4235    if (menu_st->current_time_us - menu_st->datetime_last_time_us >=
4236          DATETIME_CHECK_INTERVAL)
4237    {
4238       time_t time_;
4239       struct tm tm_;
4240       bool has_am_pm         = false;
4241       const char *format_str = "";
4242 
4243       menu_st->datetime_last_time_us = menu_st->current_time_us;
4244 
4245       /* Get current time */
4246       time(&time_);
4247       rtime_localtime(&time_, &tm_);
4248 
4249       /* Format string representation */
4250       switch (datetime->time_mode)
4251       {
4252          case MENU_TIMEDATE_STYLE_YMD_HMS: /* YYYY-MM-DD HH:MM:SS */
4253             /* Using switch statements to set the format
4254              * string is verbose, but has far less performance
4255              * impact than setting the date separator dynamically
4256              * (i.e. no snprintf() or character replacement...) */
4257             switch (datetime->date_separator)
4258             {
4259                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4260                   format_str = "%Y/%m/%d %H:%M:%S";
4261                   break;
4262                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4263                   format_str = "%Y.%m.%d %H:%M:%S";
4264                   break;
4265                default:
4266                   format_str = "%Y-%m-%d %H:%M:%S";
4267                   break;
4268             }
4269             break;
4270          case MENU_TIMEDATE_STYLE_YMD_HM: /* YYYY-MM-DD HH:MM */
4271             switch (datetime->date_separator)
4272             {
4273                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4274                   format_str = "%Y/%m/%d %H:%M";
4275                   break;
4276                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4277                   format_str = "%Y.%m.%d %H:%M";
4278                   break;
4279                default:
4280                   format_str = "%Y-%m-%d %H:%M";
4281                   break;
4282             }
4283             break;
4284          case MENU_TIMEDATE_STYLE_YMD: /* YYYY-MM-DD */
4285             switch (datetime->date_separator)
4286             {
4287                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4288                   format_str = "%Y/%m/%d";
4289                   break;
4290                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4291                   format_str = "%Y.%m.%d";
4292                   break;
4293                default:
4294                   format_str = "%Y-%m-%d";
4295                   break;
4296             }
4297             break;
4298          case MENU_TIMEDATE_STYLE_YM: /* YYYY-MM */
4299             switch (datetime->date_separator)
4300             {
4301                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4302                   format_str = "%Y/%m";
4303                   break;
4304                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4305                   format_str = "%Y.%m";
4306                   break;
4307                default:
4308                   format_str = "%Y-%m";
4309                   break;
4310             }
4311             break;
4312          case MENU_TIMEDATE_STYLE_MDYYYY_HMS: /* MM-DD-YYYY HH:MM:SS */
4313             switch (datetime->date_separator)
4314             {
4315                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4316                   format_str = "%m/%d/%Y %H:%M:%S";
4317                   break;
4318                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4319                   format_str = "%m.%d.%Y %H:%M:%S";
4320                   break;
4321                default:
4322                   format_str = "%m-%d-%Y %H:%M:%S";
4323                   break;
4324             }
4325             break;
4326          case MENU_TIMEDATE_STYLE_MDYYYY_HM: /* MM-DD-YYYY HH:MM */
4327             switch (datetime->date_separator)
4328             {
4329                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4330                   format_str = "%m/%d/%Y %H:%M";
4331                   break;
4332                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4333                   format_str = "%m.%d.%Y %H:%M";
4334                   break;
4335                default:
4336                   format_str = "%m-%d-%Y %H:%M";
4337                   break;
4338             }
4339             break;
4340          case MENU_TIMEDATE_STYLE_MD_HM: /* MM-DD HH:MM */
4341             switch (datetime->date_separator)
4342             {
4343                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4344                   format_str = "%m/%d %H:%M";
4345                   break;
4346                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4347                   format_str = "%m.%d %H:%M";
4348                   break;
4349                default:
4350                   format_str = "%m-%d %H:%M";
4351                   break;
4352             }
4353             break;
4354          case MENU_TIMEDATE_STYLE_MDYYYY: /* MM-DD-YYYY */
4355             switch (datetime->date_separator)
4356             {
4357                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4358                   format_str = "%m/%d/%Y";
4359                   break;
4360                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4361                   format_str = "%m.%d.%Y";
4362                   break;
4363                default:
4364                   format_str = "%m-%d-%Y";
4365                   break;
4366             }
4367             break;
4368          case MENU_TIMEDATE_STYLE_MD: /* MM-DD */
4369             switch (datetime->date_separator)
4370             {
4371                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4372                   format_str = "%m/%d";
4373                   break;
4374                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4375                   format_str = "%m.%d";
4376                   break;
4377                default:
4378                   format_str = "%m-%d";
4379                   break;
4380             }
4381             break;
4382          case MENU_TIMEDATE_STYLE_DDMMYYYY_HMS: /* DD-MM-YYYY HH:MM:SS */
4383             switch (datetime->date_separator)
4384             {
4385                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4386                   format_str = "%d/%m/%Y %H:%M:%S";
4387                   break;
4388                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4389                   format_str = "%d.%m.%Y %H:%M:%S";
4390                   break;
4391                default:
4392                   format_str = "%d-%m-%Y %H:%M:%S";
4393                   break;
4394             }
4395             break;
4396          case MENU_TIMEDATE_STYLE_DDMMYYYY_HM: /* DD-MM-YYYY HH:MM */
4397             switch (datetime->date_separator)
4398             {
4399                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4400                   format_str = "%d/%m/%Y %H:%M";
4401                   break;
4402                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4403                   format_str = "%d.%m.%Y %H:%M";
4404                   break;
4405                default:
4406                   format_str = "%d-%m-%Y %H:%M";
4407                   break;
4408             }
4409             break;
4410          case MENU_TIMEDATE_STYLE_DDMM_HM: /* DD-MM HH:MM */
4411             switch (datetime->date_separator)
4412             {
4413                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4414                   format_str = "%d/%m %H:%M";
4415                   break;
4416                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4417                   format_str = "%d.%m %H:%M";
4418                   break;
4419                default:
4420                   format_str = "%d-%m %H:%M";
4421                   break;
4422             }
4423             break;
4424          case MENU_TIMEDATE_STYLE_DDMMYYYY: /* DD-MM-YYYY */
4425             switch (datetime->date_separator)
4426             {
4427                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4428                   format_str = "%d/%m/%Y";
4429                   break;
4430                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4431                   format_str = "%d.%m.%Y";
4432                   break;
4433                default:
4434                   format_str = "%d-%m-%Y";
4435                   break;
4436             }
4437             break;
4438          case MENU_TIMEDATE_STYLE_DDMM: /* DD-MM */
4439             switch (datetime->date_separator)
4440             {
4441                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4442                   format_str = "%d/%m";
4443                   break;
4444                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4445                   format_str = "%d.%m";
4446                   break;
4447                default:
4448                   format_str = "%d-%m";
4449                   break;
4450             }
4451             break;
4452          case MENU_TIMEDATE_STYLE_HMS: /* HH:MM:SS */
4453             format_str = "%H:%M:%S";
4454             break;
4455          case MENU_TIMEDATE_STYLE_HM: /* HH:MM */
4456             format_str = "%H:%M";
4457             break;
4458          case MENU_TIMEDATE_STYLE_YMD_HMS_AMPM: /* YYYY-MM-DD HH:MM:SS (AM/PM) */
4459             has_am_pm = true;
4460             switch (datetime->date_separator)
4461             {
4462                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4463                   format_str = "%Y/%m/%d %I:%M:%S %p";
4464                   break;
4465                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4466                   format_str = "%Y.%m.%d %I:%M:%S %p";
4467                   break;
4468                default:
4469                   format_str = "%Y-%m-%d %I:%M:%S %p";
4470                   break;
4471             }
4472             break;
4473          case MENU_TIMEDATE_STYLE_YMD_HM_AMPM: /* YYYY-MM-DD HH:MM (AM/PM) */
4474             has_am_pm = true;
4475             switch (datetime->date_separator)
4476             {
4477                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4478                   format_str = "%Y/%m/%d %I:%M %p";
4479                   break;
4480                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4481                   format_str = "%Y.%m.%d %I:%M %p";
4482                   break;
4483                default:
4484                   format_str = "%Y-%m-%d %I:%M %p";
4485                   break;
4486             }
4487             break;
4488          case MENU_TIMEDATE_STYLE_MDYYYY_HMS_AMPM: /* MM-DD-YYYY HH:MM:SS (AM/PM) */
4489             has_am_pm = true;
4490             switch (datetime->date_separator)
4491             {
4492                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4493                   format_str = "%m/%d/%Y %I:%M:%S %p";
4494                   break;
4495                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4496                   format_str = "%m.%d.%Y %I:%M:%S %p";
4497                   break;
4498                default:
4499                   format_str = "%m-%d-%Y %I:%M:%S %p";
4500                   break;
4501             }
4502             break;
4503          case MENU_TIMEDATE_STYLE_MDYYYY_HM_AMPM: /* MM-DD-YYYY HH:MM (AM/PM) */
4504             has_am_pm = true;
4505             switch (datetime->date_separator)
4506             {
4507                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4508                   format_str = "%m/%d/%Y %I:%M %p";
4509                   break;
4510                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4511                   format_str = "%m.%d.%Y %I:%M %p";
4512                   break;
4513                default:
4514                   format_str = "%m-%d-%Y %I:%M %p";
4515                   break;
4516             }
4517             break;
4518          case MENU_TIMEDATE_STYLE_MD_HM_AMPM: /* MM-DD HH:MM (AM/PM) */
4519             has_am_pm = true;
4520             switch (datetime->date_separator)
4521             {
4522                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4523                   format_str = "%m/%d %I:%M %p";
4524                   break;
4525                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4526                   format_str = "%m.%d %I:%M %p";
4527                   break;
4528                default:
4529                   format_str = "%m-%d %I:%M %p";
4530                   break;
4531             }
4532             break;
4533          case MENU_TIMEDATE_STYLE_DDMMYYYY_HMS_AMPM: /* DD-MM-YYYY HH:MM:SS (AM/PM) */
4534             has_am_pm = true;
4535             switch (datetime->date_separator)
4536             {
4537                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4538                   format_str = "%d/%m/%Y %I:%M:%S %p";
4539                   break;
4540                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4541                   format_str = "%d.%m.%Y %I:%M:%S %p";
4542                   break;
4543                default:
4544                   format_str = "%d-%m-%Y %I:%M:%S %p";
4545                   break;
4546             }
4547             break;
4548          case MENU_TIMEDATE_STYLE_DDMMYYYY_HM_AMPM: /* DD-MM-YYYY HH:MM (AM/PM) */
4549             has_am_pm = true;
4550             switch (datetime->date_separator)
4551             {
4552                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4553                   format_str = "%d/%m/%Y %I:%M %p";
4554                   break;
4555                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4556                   format_str = "%d.%m.%Y %I:%M %p";
4557                   break;
4558                default:
4559                   format_str = "%d-%m-%Y %I:%M %p";
4560                   break;
4561             }
4562             break;
4563          case MENU_TIMEDATE_STYLE_DDMM_HM_AMPM: /* DD-MM HH:MM (AM/PM) */
4564             has_am_pm = true;
4565             switch (datetime->date_separator)
4566             {
4567                case MENU_TIMEDATE_DATE_SEPARATOR_SLASH:
4568                   format_str = "%d/%m %I:%M %p";
4569                   break;
4570                case MENU_TIMEDATE_DATE_SEPARATOR_PERIOD:
4571                   format_str = "%d.%m %I:%M %p";
4572                   break;
4573                default:
4574                   format_str = "%d-%m %I:%M %p";
4575                   break;
4576             }
4577             break;
4578          case MENU_TIMEDATE_STYLE_HMS_AMPM: /* HH:MM:SS (AM/PM) */
4579             has_am_pm  = true;
4580             format_str = "%I:%M:%S %p";
4581             break;
4582          case MENU_TIMEDATE_STYLE_HM_AMPM: /* HH:MM (AM/PM) */
4583             has_am_pm  = true;
4584             format_str = "%I:%M %p";
4585             break;
4586       }
4587 
4588       if (has_am_pm)
4589          strftime_am_pm(menu_st->datetime_cache, sizeof(menu_st->datetime_cache),
4590                format_str, &tm_);
4591       else
4592          strftime(menu_st->datetime_cache, sizeof(menu_st->datetime_cache),
4593                format_str, &tm_);
4594    }
4595 
4596    /* Copy cached datetime string to input
4597     * menu_display_ctx_datetime_t struct */
4598    strlcpy(datetime->s, menu_st->datetime_cache, datetime->len);
4599 }
4600 
4601 /* Display current (battery) power state */
menu_display_powerstate(gfx_display_ctx_powerstate_t * powerstate)4602 void menu_display_powerstate(gfx_display_ctx_powerstate_t *powerstate)
4603 {
4604    int percent                    = 0;
4605    struct rarch_state   *p_rarch  = &rarch_st;
4606    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
4607    enum frontend_powerstate state = FRONTEND_POWERSTATE_NONE;
4608 
4609    if (!powerstate)
4610       return;
4611 
4612    /* Trigger an update, if required */
4613    if (menu_st->current_time_us - menu_st->powerstate_last_time_us >=
4614          POWERSTATE_CHECK_INTERVAL)
4615    {
4616       menu_st->powerstate_last_time_us = menu_st->current_time_us;
4617       task_push_get_powerstate();
4618    }
4619 
4620    /* Get last recorded state */
4621    state                       = get_last_powerstate(&percent);
4622 
4623    /* Populate gfx_display_ctx_powerstate_t */
4624    powerstate->battery_enabled = (state != FRONTEND_POWERSTATE_NONE) &&
4625                                  (state != FRONTEND_POWERSTATE_NO_SOURCE);
4626    powerstate->percent         = 0;
4627    powerstate->charging        = false;
4628 
4629    if (powerstate->battery_enabled)
4630    {
4631       if (state == FRONTEND_POWERSTATE_CHARGING)
4632          powerstate->charging  = true;
4633       if (percent > 0)
4634          powerstate->percent   = (unsigned)percent;
4635       snprintf(powerstate->s, powerstate->len, "%u%%", powerstate->percent);
4636    }
4637 }
4638 
4639 /* Iterate the menu driver for one frame. */
menu_driver_iterate(struct rarch_state * p_rarch,struct menu_state * menu_st,gfx_display_t * p_disp,gfx_animation_t * p_anim,settings_t * settings,enum menu_action action,retro_time_t current_time)4640 static bool menu_driver_iterate(
4641       struct rarch_state *p_rarch,
4642       struct menu_state *menu_st,
4643       gfx_display_t *p_disp,
4644       gfx_animation_t *p_anim,
4645       settings_t *settings,
4646       enum menu_action action,
4647       retro_time_t current_time)
4648 {
4649    return (p_rarch->menu_driver_data &&
4650          generic_menu_iterate(
4651             p_rarch,
4652             menu_st,
4653             p_disp,
4654             p_anim,
4655             settings,
4656             p_rarch->menu_driver_data,
4657             p_rarch->menu_userdata, action,
4658             current_time) != -1);
4659 }
4660 
menu_driver_deferred_push_content_list(file_list_t * list)4661 int menu_driver_deferred_push_content_list(file_list_t *list)
4662 {
4663    struct rarch_state   *p_rarch  = &rarch_st;
4664    settings_t *settings           = p_rarch->configuration_settings;
4665    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
4666    menu_list_t *menu_list         = menu_st->entries.list;
4667    file_list_t *selection_buf     = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0);
4668 
4669    menu_st->selection_ptr         = 0;
4670 
4671    if (!menu_driver_displaylist_push(
4672             menu_st,
4673             settings,
4674             list,
4675             selection_buf))
4676       return -1;
4677    return 0;
4678 }
4679 
menu_driver_list_cache(menu_ctx_list_t * list)4680 bool menu_driver_list_cache(menu_ctx_list_t *list)
4681 {
4682    struct rarch_state       *p_rarch = &rarch_st;
4683    if (!list || !p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->list_cache)
4684       return false;
4685 
4686    p_rarch->menu_driver_ctx->list_cache(p_rarch->menu_userdata,
4687          list->type, list->action);
4688    return true;
4689 }
4690 
menu_driver_set_id(const char * driver_name)4691 static enum menu_driver_id_type menu_driver_set_id(const char *driver_name)
4692 {
4693    if (!string_is_empty(driver_name))
4694    {
4695       if (string_is_equal(driver_name, "rgui"))
4696          return MENU_DRIVER_ID_RGUI;
4697       else if (string_is_equal(driver_name, "ozone"))
4698          return MENU_DRIVER_ID_OZONE;
4699       else if (string_is_equal(driver_name, "glui"))
4700          return MENU_DRIVER_ID_GLUI;
4701       else if (string_is_equal(driver_name, "xmb"))
4702          return MENU_DRIVER_ID_XMB;
4703       else if (string_is_equal(driver_name, "stripes"))
4704          return MENU_DRIVER_ID_STRIPES;
4705    }
4706    return MENU_DRIVER_ID_UNKNOWN;
4707 }
4708 
generic_menu_init_list(struct menu_state * menu_st,settings_t * settings)4709 static bool generic_menu_init_list(struct menu_state *menu_st,
4710       settings_t *settings)
4711 {
4712    menu_displaylist_info_t info;
4713    menu_list_t *menu_list       = menu_st->entries.list;
4714    file_list_t *menu_stack      = NULL;
4715    file_list_t *selection_buf   = NULL;
4716 
4717    if (menu_list)
4718    {
4719       menu_stack                = MENU_LIST_GET(menu_list, (unsigned)0);
4720       selection_buf             = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0);
4721    }
4722 
4723    menu_displaylist_info_init(&info);
4724 
4725    info.label                   = strdup(
4726          msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU));
4727    info.enum_idx                = MENU_ENUM_LABEL_MAIN_MENU;
4728 
4729    menu_entries_append_enum(menu_stack,
4730          info.path,
4731          info.label,
4732          MENU_ENUM_LABEL_MAIN_MENU,
4733          info.type, info.flags, 0);
4734 
4735    info.list                    = selection_buf;
4736 
4737    if (menu_displaylist_ctl(DISPLAYLIST_MAIN_MENU, &info, settings))
4738       menu_displaylist_process(&info);
4739 
4740    menu_displaylist_info_free(&info);
4741 
4742    return true;
4743 }
4744 
menu_driver_init_internal(gfx_display_t * p_disp,struct rarch_state * p_rarch,settings_t * settings,bool video_is_threaded)4745 static bool menu_driver_init_internal(
4746       gfx_display_t *p_disp,
4747       struct rarch_state *p_rarch,
4748       settings_t *settings,
4749       bool video_is_threaded)
4750 {
4751    struct menu_state *menu_st = &p_rarch->menu_driver_state;
4752    menu_ctx_environment_t menu_environ;
4753 
4754    if (p_rarch->menu_driver_ctx)
4755    {
4756       const char *ident = p_rarch->menu_driver_ctx->ident;
4757       /* ID must be set first, since it is required for
4758        * the proper determination of pixel/dpi scaling
4759        * parameters (and some menu drivers fetch the
4760        * current pixel/dpi scale during 'menu_driver_ctx->init()') */
4761       if (ident)
4762          p_disp->menu_driver_id                  = menu_driver_set_id(ident);
4763       else
4764          p_disp->menu_driver_id                  = MENU_DRIVER_ID_UNKNOWN;
4765 
4766       if (p_rarch->menu_driver_ctx->init)
4767       {
4768          p_rarch->menu_driver_data               = (menu_handle_t*)
4769             p_rarch->menu_driver_ctx->init(&p_rarch->menu_userdata,
4770                   video_is_threaded);
4771          p_rarch->menu_driver_data->userdata     = p_rarch->menu_userdata;
4772          p_rarch->menu_driver_data->driver_ctx   = p_rarch->menu_driver_ctx;
4773       }
4774    }
4775 
4776    if (!p_rarch->menu_driver_data || !menu_init(
4777             menu_st,
4778             &p_rarch->dialog_st,
4779             p_rarch->menu_driver_ctx,
4780             &p_rarch->menu_input_state,
4781             &p_rarch->menu_input_pointer_hw_state,
4782             settings))
4783       return false;
4784 
4785    gfx_display_init();
4786 
4787    /* TODO/FIXME - can we get rid of this? Is this needed? */
4788    configuration_set_string(settings,
4789          settings->arrays.menu_driver, p_rarch->menu_driver_ctx->ident);
4790 
4791    if (p_rarch->menu_driver_ctx->lists_init)
4792    {
4793       if (!p_rarch->menu_driver_ctx->lists_init(p_rarch->menu_driver_data))
4794          return false;
4795    }
4796    else
4797       generic_menu_init_list(menu_st, settings);
4798 
4799    /* Initialise menu screensaver */
4800    menu_environ.type              = MENU_ENVIRON_DISABLE_SCREENSAVER;
4801    menu_environ.data              = NULL;
4802    menu_st->input_last_time_us    = cpu_features_get_time_usec();
4803    menu_st->screensaver_active    = false;
4804    menu_st->screensaver_supported = menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
4805 
4806    return true;
4807 }
4808 
menu_driver_init(bool video_is_threaded)4809 bool menu_driver_init(bool video_is_threaded)
4810 {
4811    struct rarch_state       *p_rarch = &rarch_st;
4812    gfx_display_t            *p_disp  = &p_rarch->dispgfx;
4813 
4814    command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
4815    command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
4816 
4817    if (  p_rarch->menu_driver_data ||
4818          menu_driver_init_internal(
4819             &p_rarch->dispgfx,
4820             p_rarch,
4821             p_rarch->configuration_settings,
4822             video_is_threaded))
4823    {
4824       if (p_rarch->menu_driver_ctx && p_rarch->menu_driver_ctx->context_reset)
4825       {
4826          p_rarch->menu_driver_ctx->context_reset(p_rarch->menu_userdata,
4827                video_is_threaded);
4828          return true;
4829       }
4830    }
4831 
4832    /* If driver initialisation failed, must reset
4833     * driver id to 'unknown' */
4834    p_disp->menu_driver_id = MENU_DRIVER_ID_UNKNOWN;
4835 
4836    return false;
4837 }
4838 
menu_driver_navigation_set(bool scroll)4839 void menu_driver_navigation_set(bool scroll)
4840 {
4841    struct rarch_state       *p_rarch = &rarch_st;
4842    if (p_rarch->menu_driver_ctx->navigation_set)
4843       p_rarch->menu_driver_ctx->navigation_set(p_rarch->menu_userdata, scroll);
4844 }
4845 
menu_driver_populate_entries(menu_displaylist_info_t * info)4846 void menu_driver_populate_entries(menu_displaylist_info_t *info)
4847 {
4848    struct rarch_state       *p_rarch = &rarch_st;
4849    if (p_rarch->menu_driver_ctx && p_rarch->menu_driver_ctx->populate_entries)
4850       p_rarch->menu_driver_ctx->populate_entries(
4851             p_rarch->menu_userdata, info->path,
4852             info->label, info->type);
4853 }
4854 
menu_driver_push_list(menu_ctx_displaylist_t * disp_list)4855 bool menu_driver_push_list(menu_ctx_displaylist_t *disp_list)
4856 {
4857    struct rarch_state       *p_rarch = &rarch_st;
4858    if (p_rarch->menu_driver_ctx->list_push)
4859       if (p_rarch->menu_driver_ctx->list_push(
4860                p_rarch->menu_driver_data,
4861                p_rarch->menu_userdata,
4862                disp_list->info, disp_list->type) == 0)
4863          return true;
4864    return false;
4865 }
4866 
menu_driver_set_thumbnail_system(char * s,size_t len)4867 void menu_driver_set_thumbnail_system(char *s, size_t len)
4868 {
4869    struct rarch_state       *p_rarch = &rarch_st;
4870    if (     p_rarch->menu_driver_ctx
4871          && p_rarch->menu_driver_ctx->set_thumbnail_system)
4872       p_rarch->menu_driver_ctx->set_thumbnail_system(
4873             p_rarch->menu_userdata, s, len);
4874 }
4875 
menu_driver_get_thumbnail_system(char * s,size_t len)4876 void menu_driver_get_thumbnail_system(char *s, size_t len)
4877 {
4878    struct rarch_state       *p_rarch = &rarch_st;
4879    if (     p_rarch->menu_driver_ctx
4880          && p_rarch->menu_driver_ctx->get_thumbnail_system)
4881       p_rarch->menu_driver_ctx->get_thumbnail_system(
4882             p_rarch->menu_userdata, s, len);
4883 }
4884 
menu_driver_set_thumbnail_content(char * s,size_t len)4885 void menu_driver_set_thumbnail_content(char *s, size_t len)
4886 {
4887    struct rarch_state       *p_rarch = &rarch_st;
4888    if (     p_rarch->menu_driver_ctx
4889          && p_rarch->menu_driver_ctx->set_thumbnail_content)
4890       p_rarch->menu_driver_ctx->set_thumbnail_content(
4891             p_rarch->menu_userdata, s);
4892 }
4893 
4894 /* Teardown function for the menu driver. */
menu_driver_destroy(struct rarch_state * p_rarch,struct menu_state * menu_st)4895 static void menu_driver_destroy(
4896       struct rarch_state *p_rarch,
4897       struct menu_state *menu_st)
4898 {
4899    menu_st->pending_quick_menu    = false;
4900    menu_st->prevent_populate      = false;
4901    menu_st->data_own              = false;
4902    p_rarch->menu_driver_ctx       = NULL;
4903    p_rarch->menu_userdata         = NULL;
4904 }
4905 
menu_driver_list_get_entry(menu_ctx_list_t * list)4906 bool menu_driver_list_get_entry(menu_ctx_list_t *list)
4907 {
4908    struct rarch_state       *p_rarch = &rarch_st;
4909    if (  !p_rarch->menu_driver_ctx ||
4910          !p_rarch->menu_driver_ctx->list_get_entry)
4911    {
4912       list->entry = NULL;
4913       return false;
4914    }
4915    list->entry = p_rarch->menu_driver_ctx->list_get_entry(
4916          p_rarch->menu_userdata,
4917          list->type, (unsigned int)list->idx);
4918    return true;
4919 }
4920 
menu_driver_list_get_selection(menu_ctx_list_t * list)4921 bool menu_driver_list_get_selection(menu_ctx_list_t *list)
4922 {
4923    struct rarch_state       *p_rarch = &rarch_st;
4924    if (  !p_rarch->menu_driver_ctx ||
4925          !p_rarch->menu_driver_ctx->list_get_selection)
4926    {
4927       list->selection = 0;
4928       return false;
4929    }
4930    list->selection    = p_rarch->menu_driver_ctx->list_get_selection(
4931          p_rarch->menu_userdata);
4932 
4933    return true;
4934 }
4935 
menu_driver_list_get_size(menu_ctx_list_t * list)4936 bool menu_driver_list_get_size(menu_ctx_list_t *list)
4937 {
4938    struct rarch_state       *p_rarch = &rarch_st;
4939    if (  !p_rarch->menu_driver_ctx ||
4940          !p_rarch->menu_driver_ctx->list_get_size)
4941    {
4942       list->size = 0;
4943       return false;
4944    }
4945    list->size = p_rarch->menu_driver_ctx->list_get_size(
4946          p_rarch->menu_userdata, list->type);
4947    return true;
4948 }
4949 
menu_driver_screensaver_supported(void)4950 bool menu_driver_screensaver_supported(void)
4951 {
4952    struct rarch_state   *p_rarch  = &rarch_st;
4953    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
4954    return menu_st->screensaver_supported;
4955 }
4956 
menu_driver_get_current_time(void)4957 retro_time_t menu_driver_get_current_time(void)
4958 {
4959    struct rarch_state   *p_rarch  = &rarch_st;
4960    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
4961    return menu_st->current_time_us;
4962 }
4963 
menu_driver_list_free(const menu_ctx_driver_t * menu_driver_ctx,menu_ctx_list_t * list)4964 static void menu_driver_list_free(
4965       const menu_ctx_driver_t *menu_driver_ctx,
4966       menu_ctx_list_t *list)
4967 {
4968    if (menu_driver_ctx)
4969       if (menu_driver_ctx->list_free)
4970          menu_driver_ctx->list_free(
4971                list->list, list->idx, list->list_size);
4972 
4973    if (list->list)
4974    {
4975       file_list_free_userdata  (list->list, list->idx);
4976       file_list_free_actiondata(list->list, list->idx);
4977    }
4978 }
4979 
4980 /* Returns true if search filter is enabled
4981  * for the specified menu list */
menu_driver_search_filter_enabled(const char * label,unsigned type)4982 bool menu_driver_search_filter_enabled(const char *label, unsigned type)
4983 {
4984    bool filter_enabled = false;
4985 
4986    /* > Check for playlists */
4987    filter_enabled = (type == MENU_SETTING_HORIZONTAL_MENU) ||
4988                     (type == MENU_HISTORY_TAB) ||
4989                     (type == MENU_FAVORITES_TAB) ||
4990                     (type == MENU_IMAGES_TAB) ||
4991                     (type == MENU_MUSIC_TAB) ||
4992                     (type == MENU_VIDEO_TAB) ||
4993                     (type == FILE_TYPE_PLAYLIST_COLLECTION);
4994 
4995    if (!filter_enabled && !string_is_empty(label))
4996       filter_enabled = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY)) ||
4997                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST)) ||
4998                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST)) ||
4999                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST)) ||
5000                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST)) ||
5001                        /* > Core updater */
5002                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST)) ||
5003                        /* > File browser (Load Content) */
5004                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES)) ||
5005                        /* > Shader presets/passes */
5006                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET)) ||
5007                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PASS)) ||
5008                        /* > Cheat files */
5009                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_FILE_LOAD)) ||
5010                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND)) ||
5011                        /* > Overlays */
5012                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INPUT_OVERLAY)) ||
5013                        /* > Manage Cores */
5014                        string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST));
5015 
5016    return filter_enabled;
5017 }
5018 
5019 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
menu_driver_set_last_shader_path_int(const char * shader_path,enum rarch_shader_type * type,char * shader_dir,size_t dir_len,char * shader_file,size_t file_len)5020 static void menu_driver_set_last_shader_path_int(
5021       const char *shader_path,
5022       enum rarch_shader_type *type,
5023       char *shader_dir, size_t dir_len,
5024       char *shader_file, size_t file_len)
5025 {
5026    const char *file_name = NULL;
5027 
5028    if (!type ||
5029        !shader_dir ||
5030        (dir_len < 1) ||
5031        !shader_file ||
5032        (file_len < 1))
5033       return;
5034 
5035    /* Reset existing cache */
5036    *type          = RARCH_SHADER_NONE;
5037    shader_dir[0]  = '\0';
5038    shader_file[0] = '\0';
5039 
5040    /* If path is empty, do nothing */
5041    if (string_is_empty(shader_path))
5042       return;
5043 
5044    /* Get shader type */
5045    *type = video_shader_parse_type(shader_path);
5046 
5047    /* If type is invalid, do nothing */
5048    if (*type == RARCH_SHADER_NONE)
5049       return;
5050 
5051    /* Cache parent directory */
5052    fill_pathname_parent_dir(shader_dir, shader_path, dir_len);
5053 
5054    /* If parent directory is empty, then file name
5055     * is only valid if 'shader_path' refers to an
5056     * existing file in the root of the file system */
5057    if (string_is_empty(shader_dir) &&
5058        !path_is_valid(shader_path))
5059       return;
5060 
5061    /* Cache file name */
5062    file_name = path_basename_nocompression(shader_path);
5063    if (!string_is_empty(file_name))
5064       strlcpy(shader_file, file_name, file_len);
5065 }
5066 
menu_driver_set_last_shader_preset_path(const char * path)5067 void menu_driver_set_last_shader_preset_path(const char *path)
5068 {
5069    struct rarch_state *p_rarch = &rarch_st;
5070    menu_handle_t *menu         = p_rarch->menu_driver_data;
5071 
5072    if (!menu)
5073       return;
5074 
5075    menu_driver_set_last_shader_path_int(
5076          path,
5077          &menu->last_shader_selection.preset_type,
5078          menu->last_shader_selection.preset_dir,
5079          sizeof(menu->last_shader_selection.preset_dir),
5080          menu->last_shader_selection.preset_file_name,
5081          sizeof(menu->last_shader_selection.preset_file_name));
5082 }
5083 
menu_driver_set_last_shader_pass_path(const char * path)5084 void menu_driver_set_last_shader_pass_path(const char *path)
5085 {
5086    struct rarch_state *p_rarch = &rarch_st;
5087    menu_handle_t *menu         = p_rarch->menu_driver_data;
5088 
5089    if (!menu)
5090       return;
5091 
5092    menu_driver_set_last_shader_path_int(
5093          path,
5094          &menu->last_shader_selection.pass_type,
5095          menu->last_shader_selection.pass_dir,
5096          sizeof(menu->last_shader_selection.pass_dir),
5097          menu->last_shader_selection.pass_file_name,
5098          sizeof(menu->last_shader_selection.pass_file_name));
5099 }
5100 
menu_driver_get_last_shader_preset_type(void)5101 enum rarch_shader_type menu_driver_get_last_shader_preset_type(void)
5102 {
5103    struct rarch_state *p_rarch = &rarch_st;
5104    menu_handle_t *menu         = p_rarch->menu_driver_data;
5105 
5106    if (!menu)
5107       return RARCH_SHADER_NONE;
5108 
5109    return menu->last_shader_selection.preset_type;
5110 }
5111 
menu_driver_get_last_shader_pass_type(void)5112 enum rarch_shader_type menu_driver_get_last_shader_pass_type(void)
5113 {
5114    struct rarch_state *p_rarch = &rarch_st;
5115    menu_handle_t *menu         = p_rarch->menu_driver_data;
5116 
5117    if (!menu)
5118       return RARCH_SHADER_NONE;
5119 
5120    return menu->last_shader_selection.pass_type;
5121 }
5122 
menu_driver_get_last_shader_path_int(settings_t * settings,enum rarch_shader_type type,const char * shader_dir,const char * shader_file_name,const char ** dir_out,const char ** file_name_out)5123 static void menu_driver_get_last_shader_path_int(
5124       settings_t *settings, enum rarch_shader_type type,
5125       const char *shader_dir, const char *shader_file_name,
5126       const char **dir_out, const char **file_name_out)
5127 {
5128    bool remember_last_dir       = settings->bools.video_shader_remember_last_dir;
5129    const char *video_shader_dir = settings->paths.directory_video_shader;
5130 
5131    /* File name is NULL by default */
5132    if (file_name_out)
5133       *file_name_out = NULL;
5134 
5135    /* If any of the following are true:
5136     * - Directory caching is disabled
5137     * - No directory has been cached
5138     * - Cached directory is invalid
5139     * - Last selected shader is incompatible with
5140     *   the current video driver
5141     * ...use default settings */
5142    if (!remember_last_dir ||
5143        (type == RARCH_SHADER_NONE) ||
5144        string_is_empty(shader_dir) ||
5145        !path_is_directory(shader_dir) ||
5146        !video_shader_is_supported(type))
5147    {
5148       if (dir_out)
5149          *dir_out = video_shader_dir;
5150       return;
5151    }
5152 
5153    /* Assign last set directory */
5154    if (dir_out)
5155       *dir_out = shader_dir;
5156 
5157    /* Assign file name */
5158    if (file_name_out &&
5159        !string_is_empty(shader_file_name))
5160       *file_name_out = shader_file_name;
5161 }
5162 
menu_driver_get_last_shader_preset_path(const char ** directory,const char ** file_name)5163 void menu_driver_get_last_shader_preset_path(
5164       const char **directory, const char **file_name)
5165 {
5166    struct rarch_state *p_rarch  = &rarch_st;
5167    settings_t *settings         = p_rarch->configuration_settings;
5168    menu_handle_t *menu          = p_rarch->menu_driver_data;
5169    enum rarch_shader_type type  = RARCH_SHADER_NONE;
5170    const char *shader_dir       = NULL;
5171    const char *shader_file_name = NULL;
5172 
5173    if (menu)
5174    {
5175       type             = menu->last_shader_selection.preset_type;
5176       shader_dir       = menu->last_shader_selection.preset_dir;
5177       shader_file_name = menu->last_shader_selection.preset_file_name;
5178    }
5179 
5180    menu_driver_get_last_shader_path_int(settings, type,
5181          shader_dir, shader_file_name,
5182          directory, file_name);
5183 }
5184 
menu_driver_get_last_shader_pass_path(const char ** directory,const char ** file_name)5185 void menu_driver_get_last_shader_pass_path(
5186       const char **directory, const char **file_name)
5187 {
5188    struct rarch_state *p_rarch  = &rarch_st;
5189    menu_handle_t *menu          = p_rarch->menu_driver_data;
5190    settings_t *settings         = p_rarch->configuration_settings;
5191    enum rarch_shader_type type  = RARCH_SHADER_NONE;
5192    const char *shader_dir       = NULL;
5193    const char *shader_file_name = NULL;
5194 
5195    if (menu)
5196    {
5197       type             = menu->last_shader_selection.pass_type;
5198       shader_dir       = menu->last_shader_selection.pass_dir;
5199       shader_file_name = menu->last_shader_selection.pass_file_name;
5200    }
5201 
5202    menu_driver_get_last_shader_path_int(settings, type,
5203          shader_dir, shader_file_name,
5204          directory, file_name);
5205 }
5206 #endif
5207 
menu_driver_get_last_start_directory(void)5208 const char *menu_driver_get_last_start_directory(void)
5209 {
5210    struct rarch_state *p_rarch   = &rarch_st;
5211    menu_handle_t *menu           = p_rarch->menu_driver_data;
5212    settings_t *settings          = p_rarch->configuration_settings;
5213    bool use_last                 = settings->bools.use_last_start_directory;
5214    const char *default_directory = settings->paths.directory_menu_content;
5215 
5216    /* Return default directory if there is no
5217     * last directory or it's invalid */
5218    if (!menu ||
5219        !use_last ||
5220        string_is_empty(menu->last_start_content.directory) ||
5221        !path_is_directory(menu->last_start_content.directory))
5222       return default_directory;
5223 
5224    return menu->last_start_content.directory;
5225 }
5226 
menu_driver_get_last_start_file_name(void)5227 const char *menu_driver_get_last_start_file_name(void)
5228 {
5229    struct rarch_state *p_rarch = &rarch_st;
5230    menu_handle_t *menu         = p_rarch->menu_driver_data;
5231    settings_t *settings        = p_rarch->configuration_settings;
5232    bool use_last               = settings->bools.use_last_start_directory;
5233 
5234    /* Return NULL if there is no last 'file name' */
5235    if (!menu ||
5236        !use_last ||
5237        string_is_empty(menu->last_start_content.file_name))
5238       return NULL;
5239 
5240    return menu->last_start_content.file_name;
5241 }
5242 
menu_driver_set_last_start_content(const char * start_content_path)5243 void menu_driver_set_last_start_content(const char *start_content_path)
5244 {
5245    char archive_path[PATH_MAX_LENGTH];
5246    struct rarch_state *p_rarch = &rarch_st;
5247    menu_handle_t *menu         = p_rarch->menu_driver_data;
5248    settings_t *settings        = p_rarch->configuration_settings;
5249    bool use_last               = settings->bools.use_last_start_directory;
5250    const char *archive_delim   = NULL;
5251    const char *file_name       = NULL;
5252 
5253    if (!menu)
5254       return;
5255 
5256    /* Reset existing cache */
5257    menu->last_start_content.directory[0] = '\0';
5258    menu->last_start_content.file_name[0] = '\0';
5259 
5260    /* If 'use_last_start_directory' is disabled or
5261     * path is empty, do nothing */
5262    if (!use_last ||
5263        string_is_empty(start_content_path))
5264       return;
5265 
5266    /* Cache directory */
5267    fill_pathname_parent_dir(menu->last_start_content.directory,
5268          start_content_path, sizeof(menu->last_start_content.directory));
5269 
5270    /* Cache file name */
5271    archive_delim      = path_get_archive_delim(start_content_path);
5272    if (archive_delim)
5273    {
5274       /* If path references a file inside an
5275        * archive, must extract the string segment
5276        * before the archive delimiter (i.e. path of
5277        * 'parent' archive file) */
5278       size_t len;
5279 
5280       archive_path[0] = '\0';
5281       len             = (size_t)(1 + archive_delim - start_content_path);
5282       len             = (len < PATH_MAX_LENGTH) ? len : PATH_MAX_LENGTH;
5283 
5284       strlcpy(archive_path, start_content_path, len * sizeof(char));
5285 
5286       file_name       = path_basename(archive_path);
5287    }
5288    else
5289       file_name       = path_basename_nocompression(start_content_path);
5290 
5291    if (!string_is_empty(file_name))
5292       strlcpy(menu->last_start_content.file_name, file_name,
5293             sizeof(menu->last_start_content.file_name));
5294 }
5295 
menu_driver_get_pending_selection(void)5296 const char *menu_driver_get_pending_selection(void)
5297 {
5298    struct rarch_state *p_rarch = &rarch_st;
5299    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
5300    return menu_st->pending_selection;
5301 }
5302 
menu_driver_set_pending_selection(const char * pending_selection)5303 void menu_driver_set_pending_selection(const char *pending_selection)
5304 {
5305    struct rarch_state *p_rarch = &rarch_st;
5306    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
5307    char *selection             = menu_st->pending_selection;
5308 
5309    /* Reset existing cache */
5310    selection[0] = '\0';
5311 
5312    /* If path is empty, do nothing */
5313    if (string_is_empty(pending_selection))
5314       return;
5315 
5316    strlcpy(selection, pending_selection,
5317          sizeof(menu_st->pending_selection));
5318 }
5319 
menu_driver_ctl(enum rarch_menu_ctl_state state,void * data)5320 bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data)
5321 {
5322    struct rarch_state   *p_rarch  = &rarch_st;
5323    gfx_display_t         *p_disp  = &p_rarch->dispgfx;
5324    struct menu_state    *menu_st  = &p_rarch->menu_driver_state;
5325 
5326    switch (state)
5327    {
5328       case RARCH_MENU_CTL_SET_PENDING_QUICK_MENU:
5329          menu_entries_flush_stack(NULL, MENU_SETTINGS);
5330          menu_st->pending_quick_menu = true;
5331          break;
5332       case RARCH_MENU_CTL_SET_PREVENT_POPULATE:
5333          menu_st->prevent_populate = true;
5334          break;
5335       case RARCH_MENU_CTL_UNSET_PREVENT_POPULATE:
5336          menu_st->prevent_populate = false;
5337          break;
5338       case RARCH_MENU_CTL_IS_PREVENT_POPULATE:
5339          return menu_st->prevent_populate;
5340       case RARCH_MENU_CTL_DEINIT:
5341          if (     p_rarch->menu_driver_ctx
5342                && p_rarch->menu_driver_ctx->context_destroy)
5343             p_rarch->menu_driver_ctx->context_destroy(p_rarch->menu_userdata);
5344 
5345          if (menu_st->data_own)
5346             return true;
5347 
5348          playlist_free_cached();
5349 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
5350          menu_shader_manager_free(p_rarch);
5351 #endif
5352 #ifdef HAVE_NETWORKING
5353          core_updater_list_free_cached();
5354 #endif
5355 #if defined(HAVE_MENU) && defined(HAVE_LIBRETRODB)
5356          menu_explore_free();
5357 #endif
5358 
5359          if (p_rarch->menu_driver_data)
5360          {
5361             unsigned i;
5362 
5363             menu_st->scroll.acceleration = 0;
5364             menu_st->selection_ptr       = 0;
5365             menu_st->scroll.index_size   = 0;
5366 
5367             for (i = 0; i < SCROLL_INDEX_SIZE; i++)
5368                menu_st->scroll.index_list[i] = 0;
5369 
5370             memset(&p_rarch->menu_input_state, 0, sizeof(menu_input_t));
5371             memset(&p_rarch->menu_input_pointer_hw_state, 0, sizeof(menu_input_pointer_hw_state_t));
5372 
5373             if (     p_rarch->menu_driver_ctx
5374                   && p_rarch->menu_driver_ctx->free)
5375                p_rarch->menu_driver_ctx->free(p_rarch->menu_userdata);
5376             p_rarch->anim.updatetime_cb = NULL;
5377 
5378             if (p_rarch->menu_userdata)
5379                free(p_rarch->menu_userdata);
5380             p_rarch->menu_userdata = NULL;
5381             p_disp->menu_driver_id = MENU_DRIVER_ID_UNKNOWN;
5382 
5383 #ifndef HAVE_DYNAMIC
5384             if (frontend_driver_has_fork())
5385 #endif
5386             {
5387                rarch_system_info_t *system = &runloop_state.system;
5388                libretro_free_system_info(&system->info);
5389                memset(&system->info, 0, sizeof(struct retro_system_info));
5390             }
5391 
5392             gfx_animation_deinit(&p_rarch->anim);
5393             gfx_display_free();
5394 
5395             menu_entries_settings_deinit(menu_st);
5396             menu_entries_list_deinit(p_rarch->menu_driver_ctx, menu_st);
5397 
5398             if (p_rarch->menu_driver_data->core_buf)
5399                free(p_rarch->menu_driver_data->core_buf);
5400             p_rarch->menu_driver_data->core_buf  = NULL;
5401 
5402             menu_st->entries_need_refresh        = false;
5403             menu_st->entries_nonblocking_refresh = false;
5404             menu_st->entries.begin               = 0;
5405 
5406             command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
5407             rarch_favorites_deinit();
5408 
5409             p_rarch->dialog_st.pending_push  = false;
5410             p_rarch->dialog_st.current_id    = 0;
5411             p_rarch->dialog_st.current_type  = MENU_DIALOG_NONE;
5412 
5413             free(p_rarch->menu_driver_data);
5414          }
5415          p_rarch->menu_driver_data = NULL;
5416          break;
5417       case RARCH_MENU_CTL_ENVIRONMENT:
5418          {
5419             menu_ctx_environment_t *menu_environ =
5420                (menu_ctx_environment_t*)data;
5421 
5422             if (p_rarch->menu_driver_ctx->environ_cb)
5423             {
5424                if (p_rarch->menu_driver_ctx->environ_cb(menu_environ->type,
5425                         menu_environ->data, p_rarch->menu_userdata) == 0)
5426                   return true;
5427             }
5428          }
5429          return false;
5430       case RARCH_MENU_CTL_POINTER_DOWN:
5431          {
5432             menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data;
5433             if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->pointer_down)
5434             {
5435                point->retcode = 0;
5436                return false;
5437             }
5438             point->retcode = p_rarch->menu_driver_ctx->pointer_down(
5439                   p_rarch->menu_userdata,
5440                   point->x, point->y, point->ptr,
5441                   point->cbs, point->entry, point->action);
5442          }
5443          break;
5444       case RARCH_MENU_CTL_POINTER_UP:
5445          {
5446             menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data;
5447             if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->pointer_up)
5448             {
5449                point->retcode = 0;
5450                return false;
5451             }
5452             point->retcode = p_rarch->menu_driver_ctx->pointer_up(
5453                   p_rarch->menu_userdata,
5454                   point->x, point->y, point->ptr,
5455                   point->gesture,
5456                   point->cbs, point->entry, point->action);
5457          }
5458          break;
5459       case RARCH_MENU_CTL_OSK_PTR_AT_POS:
5460          {
5461             unsigned width            = 0;
5462             unsigned height           = 0;
5463             menu_ctx_pointer_t *point = (menu_ctx_pointer_t*)data;
5464             if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->osk_ptr_at_pos)
5465             {
5466                point->retcode = 0;
5467                return false;
5468             }
5469             video_driver_get_size(&width, &height);
5470             point->retcode = p_rarch->menu_driver_ctx->osk_ptr_at_pos(
5471                   p_rarch->menu_userdata,
5472                   point->x, point->y, width, height);
5473          }
5474          break;
5475       case RARCH_MENU_CTL_UPDATE_THUMBNAIL_PATH:
5476          {
5477             size_t selection = menu_st->selection_ptr;
5478 
5479             if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->update_thumbnail_path)
5480                return false;
5481             p_rarch->menu_driver_ctx->update_thumbnail_path(
5482                   p_rarch->menu_userdata, (unsigned)selection, 'L');
5483             p_rarch->menu_driver_ctx->update_thumbnail_path(
5484                   p_rarch->menu_userdata, (unsigned)selection, 'R');
5485          }
5486          break;
5487       case RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE:
5488          {
5489             if (!p_rarch->menu_driver_ctx || !p_rarch->menu_driver_ctx->update_thumbnail_image)
5490                return false;
5491             p_rarch->menu_driver_ctx->update_thumbnail_image(p_rarch->menu_userdata);
5492          }
5493          break;
5494       case RARCH_MENU_CTL_REFRESH_THUMBNAIL_IMAGE:
5495          {
5496             unsigned *i = (unsigned*)data;
5497 
5498             if (!i || !p_rarch->menu_driver_ctx ||
5499                   !p_rarch->menu_driver_ctx->refresh_thumbnail_image)
5500                return false;
5501             p_rarch->menu_driver_ctx->refresh_thumbnail_image(
5502                   p_rarch->menu_userdata, *i);
5503          }
5504          break;
5505       case RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_PATH:
5506          {
5507             size_t selection = menu_st->selection_ptr;
5508 
5509             if (  !p_rarch->menu_driver_ctx ||
5510                   !p_rarch->menu_driver_ctx->update_savestate_thumbnail_path)
5511                return false;
5512             p_rarch->menu_driver_ctx->update_savestate_thumbnail_path(
5513                   p_rarch->menu_userdata, (unsigned)selection);
5514          }
5515          break;
5516       case RARCH_MENU_CTL_UPDATE_SAVESTATE_THUMBNAIL_IMAGE:
5517          if (  !p_rarch->menu_driver_ctx ||
5518                !p_rarch->menu_driver_ctx->update_savestate_thumbnail_image)
5519             return false;
5520          p_rarch->menu_driver_ctx->update_savestate_thumbnail_image(
5521                p_rarch->menu_userdata);
5522          break;
5523       case MENU_NAVIGATION_CTL_CLEAR:
5524          {
5525             bool *pending_push     = (bool*)data;
5526 
5527             /* Always set current selection to first entry */
5528             menu_st->selection_ptr = 0;
5529 
5530             /* menu_driver_navigation_set() will be called
5531              * at the next 'push'.
5532              * If a push is *not* pending, have to do it here
5533              * instead */
5534             if (!(*pending_push))
5535             {
5536                menu_driver_navigation_set(true);
5537 
5538                if (p_rarch->menu_driver_ctx->navigation_clear)
5539                   p_rarch->menu_driver_ctx->navigation_clear(
5540                         p_rarch->menu_userdata, *pending_push);
5541             }
5542          }
5543          break;
5544       case MENU_NAVIGATION_CTL_SET_LAST:
5545          {
5546             size_t menu_list_size     = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0;
5547             size_t new_selection      = menu_list_size - 1;
5548 
5549             menu_st->selection_ptr    = new_selection;
5550 
5551             if (p_rarch->menu_driver_ctx->navigation_set_last)
5552                p_rarch->menu_driver_ctx->navigation_set_last(p_rarch->menu_userdata);
5553          }
5554          break;
5555       case MENU_NAVIGATION_CTL_GET_SCROLL_ACCEL:
5556          {
5557             size_t *sel = (size_t*)data;
5558             if (!sel)
5559                return false;
5560             *sel = menu_st->scroll.acceleration;
5561          }
5562          break;
5563       default:
5564       case RARCH_MENU_CTL_NONE:
5565          break;
5566    }
5567 
5568    return true;
5569 }
5570 #endif
5571 
5572 /**
5573  * find_driver_nonempty:
5574  * @label              : string of driver type to be found.
5575  * @i                  : index of driver.
5576  * @str                : identifier name of the found driver
5577  *                       gets written to this string.
5578  * @len                : size of @str.
5579  *
5580  * Find driver based on @label.
5581  *
5582  * Returns: NULL if no driver based on @label found, otherwise
5583  * pointer to driver.
5584  **/
find_driver_nonempty(const char * label,int i,char * s,size_t len)5585 static const void *find_driver_nonempty(
5586       const char *label, int i,
5587       char *s, size_t len)
5588 {
5589    if (string_is_equal(label, "camera_driver"))
5590    {
5591       if (camera_drivers[i])
5592       {
5593          const char *ident = camera_drivers[i]->ident;
5594 
5595          strlcpy(s, ident, len);
5596          return camera_drivers[i];
5597       }
5598    }
5599    else if (string_is_equal(label, "location_driver"))
5600    {
5601       if (location_drivers[i])
5602       {
5603          const char *ident = location_drivers[i]->ident;
5604 
5605          strlcpy(s, ident, len);
5606          return location_drivers[i];
5607       }
5608    }
5609 #ifdef HAVE_MENU
5610    else if (string_is_equal(label, "menu_driver"))
5611    {
5612       if (menu_ctx_drivers[i])
5613       {
5614          const char *ident = menu_ctx_drivers[i]->ident;
5615 
5616          strlcpy(s, ident, len);
5617          return menu_ctx_drivers[i];
5618       }
5619    }
5620 #endif
5621    else if (string_is_equal(label, "input_driver"))
5622    {
5623       if (input_drivers[i])
5624       {
5625          const char *ident = input_drivers[i]->ident;
5626 
5627          strlcpy(s, ident, len);
5628          return input_drivers[i];
5629       }
5630    }
5631    else if (string_is_equal(label, "input_joypad_driver"))
5632    {
5633       if (joypad_drivers[i])
5634       {
5635          const char *ident = joypad_drivers[i]->ident;
5636 
5637          strlcpy(s, ident, len);
5638          return joypad_drivers[i];
5639       }
5640    }
5641    else if (string_is_equal(label, "video_driver"))
5642    {
5643       if (video_drivers[i])
5644       {
5645          const char *ident = video_drivers[i]->ident;
5646 
5647          strlcpy(s, ident, len);
5648          return video_drivers[i];
5649       }
5650    }
5651    else if (string_is_equal(label, "audio_driver"))
5652    {
5653       if (audio_drivers[i])
5654       {
5655          const char *ident = audio_drivers[i]->ident;
5656 
5657          strlcpy(s, ident, len);
5658          return audio_drivers[i];
5659       }
5660    }
5661    else if (string_is_equal(label, "record_driver"))
5662    {
5663       if (record_drivers[i])
5664       {
5665          const char *ident = record_drivers[i]->ident;
5666 
5667          strlcpy(s, ident, len);
5668          return record_drivers[i];
5669       }
5670    }
5671    else if (string_is_equal(label, "midi_driver"))
5672    {
5673       if (midi_driver_find_handle(i))
5674       {
5675          const char *ident = midi_drivers[i]->ident;
5676 
5677          strlcpy(s, ident, len);
5678          return midi_drivers[i];
5679       }
5680    }
5681    else if (string_is_equal(label, "audio_resampler_driver"))
5682    {
5683       if (audio_resampler_driver_find_handle(i))
5684       {
5685          const char *ident = audio_resampler_driver_find_ident(i);
5686 
5687          strlcpy(s, ident, len);
5688          return audio_resampler_driver_find_handle(i);
5689       }
5690    }
5691    else if (string_is_equal(label, "bluetooth_driver"))
5692    {
5693       if (bluetooth_drivers[i])
5694       {
5695          const char *ident = bluetooth_drivers[i]->ident;
5696 
5697          strlcpy(s, ident, len);
5698          return bluetooth_drivers[i];
5699       }
5700    }
5701    else if (string_is_equal(label, "wifi_driver"))
5702    {
5703       if (wifi_drivers[i])
5704       {
5705          const char *ident = wifi_drivers[i]->ident;
5706 
5707          strlcpy(s, ident, len);
5708          return wifi_drivers[i];
5709       }
5710    }
5711 
5712    return NULL;
5713 }
5714 
5715 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
menu_shader_get(void)5716 struct video_shader *menu_shader_get(void)
5717 {
5718    struct rarch_state *p_rarch = &rarch_st;
5719    if (video_shader_any_supported())
5720       if (p_rarch)
5721          return p_rarch->menu_driver_shader;
5722    return NULL;
5723 }
5724 
menu_shader_manager_free(void * data)5725 void menu_shader_manager_free(void *data)
5726 {
5727    struct rarch_state *p_rarch = (struct rarch_state*)data;
5728    if (p_rarch->menu_driver_shader)
5729       free(p_rarch->menu_driver_shader);
5730    p_rarch->menu_driver_shader = NULL;
5731 }
5732 
5733 /**
5734  * menu_shader_manager_init:
5735  *
5736  * Initializes shader manager.
5737  **/
menu_shader_manager_init(void)5738 bool menu_shader_manager_init(void)
5739 {
5740    struct rarch_state *p_rarch      = &rarch_st;
5741    enum rarch_shader_type type      = RARCH_SHADER_NONE;
5742    bool ret                         = true;
5743    bool is_preset                   = false;
5744    const char *path_shader          = NULL;
5745    struct video_shader *menu_shader = NULL;
5746 
5747    /* We get the shader preset directly from the video driver, so that
5748     * we are in sync with it (it could fail loading an auto-shader)
5749     * If we can't (e.g. get_current_shader is not implemented),
5750     * we'll load retroarch_get_shader_preset() like always */
5751    video_shader_ctx_t shader_info = {0};
5752 
5753    video_shader_driver_get_current_shader(&shader_info);
5754 
5755    if (shader_info.data)
5756       /* Use the path of the originally loaded preset because it could
5757        * have been a preset with a #reference in it to another preset */
5758       path_shader = shader_info.data->loaded_preset_path;
5759    else
5760       path_shader = retroarch_get_shader_preset();
5761 
5762    menu_shader_manager_free(p_rarch);
5763 
5764    menu_shader          = (struct video_shader*)
5765       calloc(1, sizeof(*menu_shader));
5766 
5767    if (!menu_shader)
5768    {
5769       ret = false;
5770       goto end;
5771    }
5772 
5773    if (string_is_empty(path_shader))
5774       goto end;
5775 
5776    type = video_shader_get_type_from_ext(path_get_extension(path_shader),
5777          &is_preset);
5778 
5779    if (!video_shader_is_supported(type))
5780    {
5781       ret = false;
5782       goto end;
5783    }
5784 
5785    if (is_preset)
5786    {
5787       if (!video_shader_load_preset_into_shader(path_shader, menu_shader))
5788       {
5789          ret = false;
5790          goto end;
5791       }
5792       menu_shader->modified = false;
5793    }
5794    else
5795    {
5796       strlcpy(menu_shader->pass[0].source.path, path_shader,
5797             sizeof(menu_shader->pass[0].source.path));
5798       menu_shader->passes = 1;
5799    }
5800 
5801 end:
5802    p_rarch->menu_driver_shader = menu_shader;
5803    command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL);
5804    return ret;
5805 }
5806 
5807 /**
5808  * menu_shader_manager_set_preset:
5809  * @shader                   : Shader handle.
5810  * @type                     : Type of shader.
5811  * @preset_path              : Preset path to load from.
5812  * @apply                    : Whether to apply the shader or just update shader information
5813  *
5814  * Sets shader preset.
5815  **/
menu_shader_manager_set_preset(struct video_shader * shader,enum rarch_shader_type type,const char * preset_path,bool apply)5816 bool menu_shader_manager_set_preset(struct video_shader *shader,
5817       enum rarch_shader_type type, const char *preset_path, bool apply)
5818 {
5819    bool refresh                  = false;
5820    bool ret                      = false;
5821    struct rarch_state  *p_rarch  = &rarch_st;
5822    settings_t *settings          = p_rarch->configuration_settings;
5823 
5824    if (apply && !retroarch_apply_shader(p_rarch, settings,
5825             type, preset_path, true))
5826       goto clear;
5827 
5828    if (string_is_empty(preset_path))
5829    {
5830       ret = true;
5831       goto clear;
5832    }
5833 
5834    /* Load stored Preset into menu on success.
5835     * Used when a preset is directly loaded.
5836     * No point in updating when the Preset was
5837     * created from the menu itself. */
5838    if (  !shader ||
5839          !(video_shader_load_preset_into_shader(preset_path, shader)))
5840       goto end;
5841 
5842    RARCH_LOG("Menu shader set to: %s.\n", preset_path);
5843 
5844    ret = true;
5845 
5846 end:
5847 #ifdef HAVE_MENU
5848    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
5849 #endif
5850    command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL);
5851    return ret;
5852 
5853 clear:
5854    /* We don't want to disable shaders entirely here,
5855     * just reset number of passes
5856     * > Note: Disabling shaders at this point would in
5857     *   fact be dangerous, since it changes the number of
5858     *   entries in the shader options menu which can in
5859     *   turn lead to the menu selection pointer going out
5860     *   of bounds. This causes undefined behaviour/segfaults */
5861    menu_shader_manager_clear_num_passes(shader);
5862    command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL);
5863    return ret;
5864 }
5865 
menu_shader_manager_save_preset_internal(struct rarch_state * p_rarch,bool save_reference,const struct video_shader * shader,const char * basename,const char * dir_video_shader,bool apply,const char ** target_dirs,size_t num_target_dirs)5866 static bool menu_shader_manager_save_preset_internal(
5867       struct rarch_state *p_rarch,
5868       bool save_reference,
5869       const struct video_shader *shader,
5870       const char *basename,
5871       const char *dir_video_shader,
5872       bool apply,
5873       const char **target_dirs,
5874       size_t num_target_dirs)
5875 {
5876    char fullname[PATH_MAX_LENGTH];
5877    char buffer[PATH_MAX_LENGTH];
5878    bool ret                       = false;
5879    enum rarch_shader_type type    = RARCH_SHADER_NONE;
5880    char *preset_path              = NULL;
5881    size_t i                       = 0;
5882 
5883    fullname[0] = buffer[0]        = '\0';
5884 
5885    if (!shader || !shader->passes)
5886       return false;
5887 
5888    type = menu_shader_manager_get_type(shader);
5889 
5890    if (type == RARCH_SHADER_NONE)
5891       return false;
5892 
5893    if (!string_is_empty(basename))
5894    {
5895       /* We are comparing against a fixed list of file
5896        * extensions, the longest (slangp) being 6 characters
5897        * in length. We therefore only need to extract the first
5898        * 7 characters from the extension of the input path
5899        * to correctly validate a match */
5900       char ext_lower[8];
5901       const char *ext = NULL;
5902 
5903       ext_lower[0]    = '\0';
5904 
5905       strlcpy(fullname, basename, sizeof(fullname));
5906 
5907       /* Get file extension */
5908       ext = strrchr(basename, '.');
5909 
5910       /* Copy and convert to lower case */
5911       if (ext && (*(++ext) != '\0'))
5912       {
5913          strlcpy(ext_lower, ext, sizeof(ext_lower));
5914          string_to_lower(ext_lower);
5915       }
5916 
5917       /* Append extension automatically as appropriate. */
5918       if (     !string_is_equal(ext_lower, "cgp")
5919             && !string_is_equal(ext_lower, "glslp")
5920             && !string_is_equal(ext_lower, "slangp"))
5921       {
5922          const char *preset_ext = video_shader_get_preset_extension(type);
5923          strlcat(fullname, preset_ext, sizeof(fullname));
5924       }
5925    }
5926    else
5927       snprintf(fullname, sizeof(fullname), "retroarch%s",
5928             video_shader_get_preset_extension(type));
5929 
5930    if (path_is_absolute(fullname))
5931    {
5932       preset_path = fullname;
5933       ret         = video_shader_write_preset(preset_path,
5934             dir_video_shader,
5935             shader, save_reference);
5936 
5937       if (ret)
5938          RARCH_LOG("[Shaders - Save Preset]: Saved shader preset to %s.\n", preset_path);
5939       else
5940          RARCH_ERR("[Shaders - Save Preset]: Failed writing shader preset to %s.\n", preset_path);
5941    }
5942    else
5943    {
5944       char basedir[PATH_MAX_LENGTH];
5945 
5946       for (i = 0; i < num_target_dirs; i++)
5947       {
5948          if (string_is_empty(target_dirs[i]))
5949             continue;
5950 
5951          fill_pathname_join(buffer, target_dirs[i],
5952                fullname, sizeof(buffer));
5953 
5954          strlcpy(basedir, buffer, sizeof(basedir));
5955          path_basedir(basedir);
5956 
5957          if (!path_is_directory(basedir))
5958          {
5959             ret = path_mkdir(basedir);
5960 
5961             if (!ret)
5962             {
5963                RARCH_WARN("[Shaders - Save Preset]: Failed to create preset directory %s.\n", basedir);
5964                continue;
5965             }
5966          }
5967 
5968          preset_path = buffer;
5969 
5970          ret = video_shader_write_preset(preset_path,
5971                dir_video_shader,
5972                shader, save_reference);
5973 
5974          if (ret)
5975          {
5976             RARCH_LOG("[Shaders - Save Preset]: Saved shader preset to %s.\n", preset_path);
5977             break;
5978          }
5979          else
5980             RARCH_WARN("[Shaders - Save Preset]: Failed writing shader preset to %s.\n", preset_path);
5981       }
5982 
5983       if (!ret)
5984          RARCH_ERR("[Shaders - Save Preset]: Failed to write shader preset. Make sure shader directory"
5985                " and/or config directory are writable.\n");
5986    }
5987 
5988    if (ret && apply)
5989       menu_shader_manager_set_preset(NULL, type, preset_path, true);
5990 
5991    return ret;
5992 }
5993 
menu_shader_manager_operate_auto_preset(struct rarch_state * p_rarch,struct retro_system_info * system,settings_t * settings,enum auto_shader_operation op,const struct video_shader * shader,const char * dir_video_shader,const char * dir_menu_config,enum auto_shader_type type,bool apply)5994 static bool menu_shader_manager_operate_auto_preset(
5995       struct rarch_state *p_rarch,
5996       struct retro_system_info *system,
5997       settings_t *settings,
5998       enum auto_shader_operation op,
5999       const struct video_shader *shader,
6000       const char *dir_video_shader,
6001       const char *dir_menu_config,
6002       enum auto_shader_type type, bool apply)
6003 {
6004    char old_presets_directory[PATH_MAX_LENGTH];
6005    char config_directory[PATH_MAX_LENGTH];
6006    char tmp[PATH_MAX_LENGTH];
6007    char file[PATH_MAX_LENGTH];
6008    static enum rarch_shader_type shader_types[] =
6009    {
6010       RARCH_SHADER_GLSL, RARCH_SHADER_SLANG, RARCH_SHADER_CG
6011    };
6012    const char *core_name            = system ? system->library_name : NULL;
6013    const char *auto_preset_dirs[3]  = {0};
6014 
6015    old_presets_directory[0] = config_directory[0] = tmp[0] = file[0] = '\0';
6016 
6017    if (type != SHADER_PRESET_GLOBAL && string_is_empty(core_name))
6018       return false;
6019 
6020    if (!path_is_empty(RARCH_PATH_CONFIG))
6021       fill_pathname_basedir(
6022             config_directory,
6023             path_get(RARCH_PATH_CONFIG),
6024             sizeof(config_directory));
6025 
6026    /* We are only including this directory for compatibility purposes with
6027     * versions 1.8.7 and older. */
6028    if (op != AUTO_SHADER_OP_SAVE && !string_is_empty(dir_video_shader))
6029       fill_pathname_join(
6030             old_presets_directory,
6031             dir_video_shader,
6032             "presets",
6033             sizeof(old_presets_directory));
6034 
6035    auto_preset_dirs[0] = dir_menu_config;
6036    auto_preset_dirs[1] = config_directory;
6037    auto_preset_dirs[2] = old_presets_directory;
6038 
6039    switch (type)
6040    {
6041       case SHADER_PRESET_GLOBAL:
6042          strcpy_literal(file, "global");
6043          break;
6044       case SHADER_PRESET_CORE:
6045          fill_pathname_join(file, core_name, core_name, sizeof(file));
6046          break;
6047       case SHADER_PRESET_PARENT:
6048          fill_pathname_parent_dir_name(tmp,
6049                path_get(RARCH_PATH_BASENAME), sizeof(tmp));
6050          fill_pathname_join(file, core_name, tmp, sizeof(file));
6051          break;
6052       case SHADER_PRESET_GAME:
6053          {
6054             const char *game_name =
6055                path_basename(path_get(RARCH_PATH_BASENAME));
6056             if (string_is_empty(game_name))
6057                return false;
6058             fill_pathname_join(file, core_name, game_name, sizeof(file));
6059             break;
6060          }
6061       default:
6062          return false;
6063    }
6064 
6065    switch (op)
6066    {
6067       case AUTO_SHADER_OP_SAVE:
6068          return menu_shader_manager_save_preset_internal(
6069                p_rarch,
6070                settings->bools.video_shader_preset_save_reference_enable,
6071                shader, file,
6072                dir_video_shader,
6073                apply,
6074                auto_preset_dirs,
6075                ARRAY_SIZE(auto_preset_dirs));
6076       case AUTO_SHADER_OP_REMOVE:
6077          {
6078             /* remove all supported auto-shaders of given type */
6079             char *end;
6080             size_t i, j, m;
6081 
6082             char preset_path[PATH_MAX_LENGTH];
6083 
6084             /* n = amount of relevant shader presets found
6085              * m = amount of successfully deleted shader presets */
6086             size_t n = m = 0;
6087 
6088             for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++)
6089             {
6090                if (string_is_empty(auto_preset_dirs[i]))
6091                   continue;
6092 
6093                fill_pathname_join(preset_path,
6094                      auto_preset_dirs[i], file, sizeof(preset_path));
6095                end = preset_path + strlen(preset_path);
6096 
6097                for (j = 0; j < ARRAY_SIZE(shader_types); j++)
6098                {
6099                   const char *preset_ext;
6100 
6101                   if (!video_shader_is_supported(shader_types[j]))
6102                      continue;
6103 
6104                   preset_ext = video_shader_get_preset_extension(shader_types[j]);
6105                   strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path));
6106 
6107                   if (path_is_valid(preset_path))
6108                   {
6109                      n++;
6110 
6111                      if (!filestream_delete(preset_path))
6112                      {
6113                         m++;
6114                         RARCH_LOG("[Shaders]: Deleted shader preset from \"%s\".\n", preset_path);
6115                      }
6116                      else
6117                         RARCH_WARN("[Shaders]: Failed to remove shader preset at \"%s\".\n", preset_path);
6118                   }
6119                }
6120             }
6121 
6122             return n == m;
6123          }
6124       case AUTO_SHADER_OP_EXISTS:
6125          {
6126             /* test if any supported auto-shaders of given type exists */
6127             char *end;
6128             size_t i, j;
6129 
6130             char preset_path[PATH_MAX_LENGTH];
6131 
6132             for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++)
6133             {
6134                if (string_is_empty(auto_preset_dirs[i]))
6135                   continue;
6136 
6137                fill_pathname_join(preset_path,
6138                      auto_preset_dirs[i], file, sizeof(preset_path));
6139                end = preset_path + strlen(preset_path);
6140 
6141                for (j = 0; j < ARRAY_SIZE(shader_types); j++)
6142                {
6143                   const char *preset_ext;
6144 
6145                   if (!video_shader_is_supported(shader_types[j]))
6146                      continue;
6147 
6148                   preset_ext = video_shader_get_preset_extension(shader_types[j]);
6149                   strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path));
6150 
6151                   if (path_is_valid(preset_path))
6152                      return true;
6153                }
6154             }
6155          }
6156          break;
6157    }
6158 
6159    return false;
6160 }
6161 
6162 /**
6163  * menu_shader_manager_save_auto_preset:
6164  * @shader                   : shader to save
6165  * @type                     : type of shader preset which determines save path
6166  * @apply                    : immediately set preset after saving
6167  *
6168  * Save a shader as an auto-shader to it's appropriate path:
6169  *    SHADER_PRESET_GLOBAL: <target dir>/global
6170  *    SHADER_PRESET_CORE:   <target dir>/<core name>/<core name>
6171  *    SHADER_PRESET_PARENT: <target dir>/<core name>/<parent>
6172  *    SHADER_PRESET_GAME:   <target dir>/<core name>/<game name>
6173  * Needs to be consistent with retroarch_load_shader_preset()
6174  * Auto-shaders will be saved as a reference if possible
6175  **/
menu_shader_manager_save_auto_preset(const struct video_shader * shader,enum auto_shader_type type,const char * dir_video_shader,const char * dir_menu_config,bool apply)6176 bool menu_shader_manager_save_auto_preset(
6177       const struct video_shader *shader,
6178       enum auto_shader_type type,
6179       const char *dir_video_shader,
6180       const char *dir_menu_config,
6181       bool apply)
6182 {
6183    struct rarch_state *p_rarch      = &rarch_st;
6184    struct retro_system_info *system = &runloop_state.system.info;
6185    settings_t *settings             = p_rarch->configuration_settings;
6186    return menu_shader_manager_operate_auto_preset(
6187          p_rarch, system, settings,
6188          AUTO_SHADER_OP_SAVE, shader,
6189          dir_video_shader,
6190          dir_menu_config,
6191          type, apply);
6192 }
6193 
6194 /**
6195  * menu_shader_manager_save_preset:
6196  * @shader                   : shader to save
6197  * @type                     : type of shader preset which determines save path
6198  * @basename                 : basename of preset
6199  * @apply                    : immediately set preset after saving
6200  *
6201  * Save a shader preset to disk.
6202  **/
menu_shader_manager_save_preset(const struct video_shader * shader,const char * basename,const char * dir_video_shader,const char * dir_menu_config,bool apply)6203 bool menu_shader_manager_save_preset(const struct video_shader *shader,
6204       const char *basename,
6205       const char *dir_video_shader,
6206       const char *dir_menu_config,
6207       bool apply)
6208 {
6209    char config_directory[PATH_MAX_LENGTH];
6210    const char *preset_dirs[3]  = {0};
6211    struct rarch_state *p_rarch = &rarch_st;
6212    settings_t *settings        = p_rarch->configuration_settings;
6213 
6214    config_directory[0]         = '\0';
6215 
6216    if (!path_is_empty(RARCH_PATH_CONFIG))
6217       fill_pathname_basedir(
6218             config_directory,
6219             path_get(RARCH_PATH_CONFIG),
6220             sizeof(config_directory));
6221 
6222    preset_dirs[0] = dir_video_shader;
6223    preset_dirs[1] = dir_menu_config;
6224    preset_dirs[2] = config_directory;
6225 
6226    return menu_shader_manager_save_preset_internal(
6227          p_rarch,
6228          settings->bools.video_shader_preset_save_reference_enable,
6229          shader, basename,
6230          dir_video_shader,
6231          apply,
6232          preset_dirs,
6233          ARRAY_SIZE(preset_dirs));
6234 }
6235 
6236 /**
6237  * menu_shader_manager_remove_auto_preset:
6238  * @type                     : type of shader preset to delete
6239  *
6240  * Deletes an auto-shader.
6241  **/
menu_shader_manager_remove_auto_preset(enum auto_shader_type type,const char * dir_video_shader,const char * dir_menu_config)6242 bool menu_shader_manager_remove_auto_preset(
6243       enum auto_shader_type type,
6244       const char *dir_video_shader,
6245       const char *dir_menu_config)
6246 {
6247    struct rarch_state *p_rarch      = &rarch_st;
6248    struct retro_system_info *system = &runloop_state.system.info;
6249    settings_t *settings             = p_rarch->configuration_settings;
6250    return menu_shader_manager_operate_auto_preset(
6251          p_rarch, system, settings,
6252          AUTO_SHADER_OP_REMOVE, NULL,
6253          dir_video_shader,
6254          dir_menu_config,
6255          type, false);
6256 }
6257 
6258 /**
6259  * menu_shader_manager_auto_preset_exists:
6260  * @type                     : type of shader preset
6261  *
6262  * Tests if an auto-shader of the given type exists.
6263  **/
menu_shader_manager_auto_preset_exists(enum auto_shader_type type,const char * dir_video_shader,const char * dir_menu_config)6264 bool menu_shader_manager_auto_preset_exists(
6265       enum auto_shader_type type,
6266       const char *dir_video_shader,
6267       const char *dir_menu_config)
6268 {
6269    struct rarch_state *p_rarch      = &rarch_st;
6270    struct retro_system_info *system = &runloop_state.system.info;
6271    settings_t *settings             = p_rarch->configuration_settings;
6272    return menu_shader_manager_operate_auto_preset(
6273          p_rarch, system, settings,
6274          AUTO_SHADER_OP_EXISTS, NULL,
6275          dir_video_shader,
6276          dir_menu_config,
6277          type, false);
6278 }
6279 
menu_shader_manager_clear_num_passes(struct video_shader * shader)6280 int menu_shader_manager_clear_num_passes(struct video_shader *shader)
6281 {
6282    bool refresh                = false;
6283 
6284    if (!shader)
6285       return 0;
6286 
6287    shader->passes = 0;
6288 
6289 #ifdef HAVE_MENU
6290    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
6291 #endif
6292 
6293    video_shader_resolve_parameters(shader);
6294 
6295    shader->modified = true;
6296 
6297    return 0;
6298 }
6299 
menu_shader_manager_clear_parameter(struct video_shader * shader,unsigned i)6300 int menu_shader_manager_clear_parameter(struct video_shader *shader,
6301       unsigned i)
6302 {
6303    struct video_shader_parameter *param = shader ?
6304       &shader->parameters[i] : NULL;
6305 
6306    if (!param)
6307       return 0;
6308 
6309    param->current = param->initial;
6310    param->current = MIN(MAX(param->minimum,
6311             param->current), param->maximum);
6312 
6313    shader->modified = true;
6314 
6315    return 0;
6316 }
6317 
menu_shader_manager_clear_pass_filter(struct video_shader * shader,unsigned i)6318 int menu_shader_manager_clear_pass_filter(struct video_shader *shader,
6319       unsigned i)
6320 {
6321    struct video_shader_pass *shader_pass = shader ?
6322       &shader->pass[i] : NULL;
6323 
6324    if (!shader_pass)
6325       return -1;
6326 
6327    shader_pass->filter = RARCH_FILTER_UNSPEC;
6328 
6329    shader->modified = true;
6330 
6331    return 0;
6332 }
6333 
menu_shader_manager_clear_pass_scale(struct video_shader * shader,unsigned i)6334 void menu_shader_manager_clear_pass_scale(struct video_shader *shader,
6335       unsigned i)
6336 {
6337    struct video_shader_pass *shader_pass = shader ?
6338       &shader->pass[i] : NULL;
6339 
6340    if (!shader_pass)
6341       return;
6342 
6343    shader_pass->fbo.scale_x = 0;
6344    shader_pass->fbo.scale_y = 0;
6345    shader_pass->fbo.valid   = false;
6346 
6347    shader->modified         = true;
6348 }
6349 
menu_shader_manager_clear_pass_path(struct video_shader * shader,unsigned i)6350 void menu_shader_manager_clear_pass_path(struct video_shader *shader,
6351       unsigned i)
6352 {
6353    struct video_shader_pass
6354       *shader_pass              = shader
6355       ? &shader->pass[i]
6356       : NULL;
6357 
6358    if (shader_pass)
6359       *shader_pass->source.path = '\0';
6360 
6361    if (shader)
6362       shader->modified          = true;
6363 }
6364 
6365 /**
6366  * menu_shader_manager_get_type:
6367  * @shader                   : shader handle
6368  *
6369  * Gets type of shader.
6370  *
6371  * Returns: type of shader.
6372  **/
menu_shader_manager_get_type(const struct video_shader * shader)6373 enum rarch_shader_type menu_shader_manager_get_type(
6374       const struct video_shader *shader)
6375 {
6376    enum rarch_shader_type type       = RARCH_SHADER_NONE;
6377    /* All shader types must be the same, or we cannot use it. */
6378    size_t i                         = 0;
6379 
6380    if (!shader)
6381       return RARCH_SHADER_NONE;
6382 
6383    type = video_shader_parse_type(shader->path);
6384 
6385    if (!shader->passes)
6386       return type;
6387 
6388    if (type == RARCH_SHADER_NONE)
6389    {
6390       type = video_shader_parse_type(shader->pass[0].source.path);
6391       i    = 1;
6392    }
6393 
6394    for (; i < shader->passes; i++)
6395    {
6396       enum rarch_shader_type pass_type =
6397          video_shader_parse_type(shader->pass[i].source.path);
6398 
6399       switch (pass_type)
6400       {
6401          case RARCH_SHADER_CG:
6402          case RARCH_SHADER_GLSL:
6403          case RARCH_SHADER_SLANG:
6404             if (type != pass_type)
6405                return RARCH_SHADER_NONE;
6406             break;
6407          default:
6408             break;
6409       }
6410    }
6411 
6412    return type;
6413 }
6414 
6415 /**
6416  * menu_shader_manager_apply_changes:
6417  *
6418  * Apply shader state changes.
6419  **/
menu_shader_manager_apply_changes(struct video_shader * shader,const char * dir_video_shader,const char * dir_menu_config)6420 void menu_shader_manager_apply_changes(
6421       struct video_shader *shader,
6422       const char *dir_video_shader,
6423       const char *dir_menu_config)
6424 {
6425    enum rarch_shader_type type = RARCH_SHADER_NONE;
6426 
6427    if (!shader)
6428       return;
6429 
6430    type = menu_shader_manager_get_type(shader);
6431 
6432    if (shader->passes && type != RARCH_SHADER_NONE)
6433    {
6434       menu_shader_manager_save_preset(shader, NULL,
6435             dir_video_shader, dir_menu_config, true);
6436       return;
6437    }
6438 
6439    menu_shader_manager_set_preset(NULL, type, NULL, true);
6440 }
6441 #endif
6442 
6443 #ifdef HAVE_DISCORD
discord_is_ready(void)6444 bool discord_is_ready(void)
6445 {
6446    struct rarch_state *p_rarch = &rarch_st;
6447    discord_state_t *discord_st = &p_rarch->discord_st;
6448    return discord_st->ready;
6449 }
6450 
discord_get_own_username(struct rarch_state * p_rarch)6451 static char *discord_get_own_username(struct rarch_state *p_rarch)
6452 {
6453    discord_state_t *discord_st = &p_rarch->discord_st;
6454 
6455    if (discord_st->ready)
6456       return discord_st->user_name;
6457    return NULL;
6458 }
6459 
discord_get_own_avatar(void)6460 char *discord_get_own_avatar(void)
6461 {
6462    struct rarch_state *p_rarch = &rarch_st;
6463    discord_state_t *discord_st = &p_rarch->discord_st;
6464    if (discord_st->ready)
6465       return discord_st->user_avatar;
6466    return NULL;
6467 }
6468 
discord_avatar_is_ready(void)6469 bool discord_avatar_is_ready(void)
6470 {
6471    return false;
6472 }
6473 
discord_avatar_set_ready(bool ready)6474 void discord_avatar_set_ready(bool ready)
6475 {
6476    struct rarch_state *p_rarch = &rarch_st;
6477    discord_state_t *discord_st = &p_rarch->discord_st;
6478    discord_st->avatar_ready    = ready;
6479 }
6480 
6481 #ifdef HAVE_MENU
discord_download_avatar(discord_state_t * discord_st,const char * user_id,const char * avatar_id)6482 static bool discord_download_avatar(
6483       discord_state_t *discord_st,
6484       const char* user_id, const char* avatar_id)
6485 {
6486    static char url[PATH_MAX_LENGTH];
6487    static char url_encoded[PATH_MAX_LENGTH];
6488    static char full_path[PATH_MAX_LENGTH];
6489    static char buf[PATH_MAX_LENGTH];
6490    file_transfer_t     *transf = NULL;
6491 
6492    RARCH_LOG("[DISCORD]: User avatar ID: %s\n", user_id);
6493 
6494    fill_pathname_application_special(buf,
6495             sizeof(buf),
6496             APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS);
6497    fill_pathname_join(full_path, buf, avatar_id, sizeof(full_path));
6498    strlcpy(discord_st->user_avatar,
6499          avatar_id, sizeof(discord_st->user_avatar));
6500 
6501    if (path_is_valid(full_path))
6502       return true;
6503 
6504    if (string_is_empty(avatar_id))
6505       return false;
6506 
6507    snprintf(url, sizeof(url), "%s/%s/%s" FILE_PATH_PNG_EXTENSION, CDN_URL, user_id, avatar_id);
6508    net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
6509    snprintf(buf, sizeof(buf), "%s" FILE_PATH_PNG_EXTENSION, avatar_id);
6510 
6511    transf           = (file_transfer_t*)malloc(sizeof(*transf));
6512 
6513    transf->enum_idx  = MENU_ENUM_LABEL_CB_DISCORD_AVATAR;
6514    strlcpy(transf->path, buf, sizeof(transf->path));
6515    transf->user_data = NULL;
6516 
6517    RARCH_LOG("[DISCORD]: Downloading avatar from: %s\n", url_encoded);
6518    task_push_http_transfer_file(url_encoded, true, NULL, cb_generic_download, transf);
6519 
6520    return false;
6521 }
6522 #endif
6523 
handle_discord_ready(const DiscordUser * connectedUser)6524 static void handle_discord_ready(const DiscordUser* connectedUser)
6525 {
6526    struct rarch_state *p_rarch = &rarch_st;
6527    discord_state_t *discord_st = &p_rarch->discord_st;
6528 
6529    strlcpy(discord_st->user_name,
6530          connectedUser->username, sizeof(discord_st->user_name));
6531 
6532    RARCH_LOG("[DISCORD]: Connected to user: %s#%s\n",
6533       connectedUser->username,
6534       connectedUser->discriminator);
6535 
6536 #ifdef HAVE_MENU
6537    discord_download_avatar(discord_st,
6538          connectedUser->userId, connectedUser->avatar);
6539 #endif
6540 }
6541 
handle_discord_disconnected(int errcode,const char * message)6542 static void handle_discord_disconnected(int errcode, const char* message)
6543 {
6544    RARCH_LOG("[DISCORD]: Disconnected (%d: %s)\n", errcode, message);
6545 }
6546 
handle_discord_error(int errcode,const char * message)6547 static void handle_discord_error(int errcode, const char* message)
6548 {
6549    RARCH_LOG("[DISCORD]: Error (%d: %s)\n", errcode, message);
6550 }
6551 
handle_discord_join_cb(retro_task_t * task,void * task_data,void * user_data,const char * err)6552 static void handle_discord_join_cb(retro_task_t *task,
6553       void *task_data, void *user_data, const char *err)
6554 {
6555    char join_hostname[PATH_MAX_LENGTH];
6556    struct netplay_room *room         = NULL;
6557    http_transfer_data_t *data        = (http_transfer_data_t*)task_data;
6558    struct rarch_state *p_rarch       = &rarch_st;
6559    discord_state_t *discord_st       = &p_rarch->discord_st;
6560 
6561    if (!data || err || !data->data)
6562       goto finish;
6563 
6564    data->data                        = (char*)realloc(data->data, data->len + 1);
6565    data->data[data->len]             = '\0';
6566 
6567    netplay_rooms_parse(data->data);
6568    room                              = netplay_room_get(0);
6569 
6570    if (room)
6571    {
6572       bool host_method_is_mitm = room->host_method == NETPLAY_HOST_METHOD_MITM;
6573       const char *srv_address  = host_method_is_mitm ? room->mitm_address : room->address;
6574       unsigned srv_port        = host_method_is_mitm ? room->mitm_port : room->port;
6575 
6576       if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
6577          deinit_netplay(p_rarch);
6578       netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
6579 
6580       snprintf(join_hostname, sizeof(join_hostname), "%s|%d",
6581             srv_address, srv_port);
6582 
6583       RARCH_LOG("[DISCORD]: Joining lobby at: %s\n", join_hostname);
6584       task_push_netplay_crc_scan(room->gamecrc,
6585          room->gamename, join_hostname, room->corename, room->subsystem_name);
6586       discord_st->connecting = true;
6587       if (discord_st->ready)
6588          discord_update(DISCORD_PRESENCE_NETPLAY_CLIENT);
6589    }
6590 
6591 finish:
6592 
6593    if (err)
6594       RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED), err);
6595 
6596    if (user_data)
6597       free(user_data);
6598 }
6599 
handle_discord_join(const char * secret)6600 static void handle_discord_join(const char* secret)
6601 {
6602    char url[2048];
6603    struct string_list    *list = string_split(secret, "|");
6604    struct rarch_state *p_rarch = &rarch_st;
6605    discord_state_t *discord_st = &p_rarch->discord_st;
6606 
6607    strlcpy(discord_st->peer_party_id,
6608          list->elems[0].data, sizeof(discord_st->peer_party_id));
6609    snprintf(url, sizeof(url), FILE_PATH_LOBBY_LIBRETRO_URL "%s/",
6610          discord_st->peer_party_id);
6611 
6612    RARCH_LOG("[DISCORD]: Querying lobby id: %s at %s\n",
6613          discord_st->peer_party_id, url);
6614    task_push_http_transfer(url, true, NULL, handle_discord_join_cb, NULL);
6615 }
6616 
handle_discord_spectate(const char * secret)6617 static void handle_discord_spectate(const char* secret)
6618 {
6619    RARCH_LOG("[DISCORD]: Spectate (%s)\n", secret);
6620 }
6621 
6622 #ifdef HAVE_MENU
6623 #if 0
6624 static void handle_discord_join_response(void *ignore, const char *line)
6625 {
6626    /* TODO/FIXME: needs in-game widgets */
6627    if (strstr(line, "yes"))
6628       Discord_Respond(user_id, DISCORD_REPLY_YES);
6629 
6630 #ifdef HAVE_MENU
6631    menu_input_dialog_end();
6632    retroarch_menu_running_finished(false);
6633 #endif
6634 }
6635 #endif
6636 #endif
6637 
handle_discord_join_request(const DiscordUser * request)6638 static void handle_discord_join_request(const DiscordUser* request)
6639 {
6640 #ifdef HAVE_MENU
6641 #if 0
6642    char buf[PATH_MAX_LENGTH];
6643 #endif
6644    menu_input_ctx_line_t line;
6645    struct rarch_state *p_rarch = &rarch_st;
6646 
6647    RARCH_LOG("[DISCORD]: Join request from %s#%s - %s %s\n",
6648       request->username,
6649       request->discriminator,
6650       request->userId,
6651       request->avatar);
6652 
6653    discord_download_avatar(&p_rarch->discord_st,
6654          request->userId, request->avatar);
6655 
6656 #if 0
6657    /* TODO/FIXME: Needs in-game widgets */
6658    retroarch_menu_running();
6659 
6660    memset(&line, 0, sizeof(line));
6661    snprintf(buf, sizeof(buf), "%s %s?",
6662          msg_hash_to_str(MSG_DISCORD_CONNECTION_REQUEST), request->username);
6663    line.label         = buf;
6664    line.label_setting = "no_setting";
6665    line.cb            = handle_discord_join_response;
6666 
6667    /* TODO/FIXME: needs in-game widgets
6668     * TODO/FIXME: bespoke dialog, should show while in-game
6669     * and have a hotkey to accept
6670     * TODO/FIXME: show avatar of the user connecting
6671     */
6672    if (!menu_input_dialog_start(&line))
6673       return;
6674 #endif
6675 #endif
6676 }
6677 
discord_update(enum discord_presence presence)6678 void discord_update(enum discord_presence presence)
6679 {
6680    struct rarch_state *p_rarch = &rarch_st;
6681    discord_state_t *discord_st = &p_rarch->discord_st;
6682 #ifdef HAVE_CHEEVOS
6683    char cheevos_richpresence[256];
6684 #endif
6685 
6686    if (presence == discord_st->status)
6687       return;
6688 
6689    if (!discord_st->connecting
6690          &&
6691          (   presence == DISCORD_PRESENCE_NONE
6692           || presence == DISCORD_PRESENCE_MENU))
6693    {
6694       memset(&discord_st->presence,
6695             0, sizeof(discord_st->presence));
6696       discord_st->peer_party_id[0] = '\0';
6697    }
6698 
6699    switch (presence)
6700    {
6701       case DISCORD_PRESENCE_MENU:
6702          discord_st->presence.details        = msg_hash_to_str(
6703                MENU_ENUM_LABEL_VALUE_DISCORD_IN_MENU);
6704          discord_st->presence.largeImageKey  = "base";
6705          discord_st->presence.largeImageText = msg_hash_to_str(
6706                MENU_ENUM_LABEL_VALUE_NO_CORE);
6707          discord_st->presence.instance       = 0;
6708          break;
6709       case DISCORD_PRESENCE_GAME_PAUSED:
6710          discord_st->presence.smallImageKey  = "paused";
6711          discord_st->presence.smallImageText = msg_hash_to_str(
6712                MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED);
6713          discord_st->presence.details        = msg_hash_to_str(
6714                MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED);
6715          discord_st->pause_time              = time(0);
6716          discord_st->elapsed_time            = difftime(discord_st->pause_time,
6717                discord_st->start_time);
6718          discord_st->presence.startTimestamp = discord_st->pause_time;
6719          break;
6720       case DISCORD_PRESENCE_GAME:
6721          {
6722             core_info_t      *core_info     = NULL;
6723             core_info_get_current_core(&core_info);
6724 
6725             if (core_info)
6726             {
6727                const char *system_id               =
6728                     core_info->system_id
6729                   ? core_info->system_id
6730                   : "core";
6731                const char *label                   = NULL;
6732                const struct playlist_entry *entry  = NULL;
6733                playlist_t *current_playlist        = playlist_get_cached();
6734 
6735                if (current_playlist)
6736                {
6737                   playlist_get_index_by_path(
6738                         current_playlist,
6739                         path_get(RARCH_PATH_CONTENT),
6740                         &entry);
6741 
6742                   if (entry && !string_is_empty(entry->label))
6743                      label = entry->label;
6744                }
6745 
6746                if (!label)
6747                   label = path_basename(path_get(RARCH_PATH_BASENAME));
6748                discord_st->presence.largeImageKey = system_id;
6749 
6750                if (core_info->display_name)
6751                   discord_st->presence.largeImageText =
6752                      core_info->display_name;
6753 
6754                discord_st->start_time              = time(0);
6755                if (discord_st->pause_time != 0)
6756                   discord_st->start_time           = time(0) -
6757                      discord_st->elapsed_time;
6758 
6759                discord_st->pause_time              = 0;
6760                discord_st->elapsed_time            = 0;
6761 
6762                discord_st->presence.smallImageKey  = "playing";
6763                discord_st->presence.smallImageText = msg_hash_to_str(
6764                      MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING);
6765                discord_st->presence.startTimestamp = discord_st->start_time;
6766 
6767 #ifdef HAVE_CHEEVOS
6768                if (rcheevos_get_richpresence(cheevos_richpresence, sizeof(cheevos_richpresence)) > 0)
6769                   discord_st->presence.details     = cheevos_richpresence;
6770                else
6771 #endif
6772                    discord_st->presence.details    = msg_hash_to_str(
6773                      MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME);
6774 
6775                discord_st->presence.state          = label;
6776                discord_st->presence.instance       = 0;
6777 
6778                if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
6779                {
6780                   discord_st->peer_party_id[0]     = '\0';
6781                   discord_st->connecting           = false;
6782                   discord_st->presence.partyId     = NULL;
6783                   discord_st->presence.partyMax    = 0;
6784                   discord_st->presence.partySize   = 0;
6785                   discord_st->presence.joinSecret  = (const char*)'\0';
6786                }
6787             }
6788          }
6789          break;
6790       case DISCORD_PRESENCE_NETPLAY_HOSTING:
6791          {
6792             char join_secret[128];
6793             struct netplay_room *room = &p_rarch->netplay_host_room;
6794             bool host_method_is_mitm  = room->host_method == NETPLAY_HOST_METHOD_MITM;
6795             const char *srv_address   = host_method_is_mitm ? room->mitm_address : room->address;
6796             unsigned srv_port         = host_method_is_mitm ? room->mitm_port : room->port;
6797             if (room->id == 0)
6798                return;
6799 
6800             RARCH_LOG("[DISCORD]: Netplay room details: ID=%d"
6801                   ", Nick=%s IP=%s Port=%d\n",
6802                   room->id, room->nickname,
6803                   srv_address, srv_port);
6804 
6805             snprintf(discord_st->self_party_id,
6806                   sizeof(discord_st->self_party_id), "%d", room->id);
6807             snprintf(join_secret,
6808                   sizeof(join_secret), "%d|%" PRId64,
6809                   room->id, cpu_features_get_time_usec());
6810 
6811             discord_st->presence.joinSecret     = strdup(join_secret);
6812 #if 0
6813             discord_st->presence.spectateSecret = "SPECSPECSPEC";
6814 #endif
6815             discord_st->presence.partyId        = strdup(discord_st->self_party_id);
6816             discord_st->presence.partyMax       = 2;
6817             discord_st->presence.partySize      = 1;
6818 
6819             RARCH_LOG("[DISCORD]: Join secret: %s\n", join_secret);
6820             RARCH_LOG("[DISCORD]: Party ID: %s\n", discord_st->self_party_id);
6821          }
6822          break;
6823       case DISCORD_PRESENCE_NETPLAY_CLIENT:
6824          RARCH_LOG("[DISCORD]: Party ID: %s\n", discord_st->peer_party_id);
6825          discord_st->presence.partyId    = strdup(discord_st->peer_party_id);
6826          break;
6827       case DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED:
6828          {
6829             if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
6830             !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
6831             {
6832                discord_st->peer_party_id[0]     = '\0';
6833                discord_st->connecting           = false;
6834                discord_st->presence.partyId     = NULL;
6835                discord_st->presence.partyMax    = 0;
6836                discord_st->presence.partySize   = 0;
6837                discord_st->presence.joinSecret  = (const char*)'\0';
6838             }
6839          }
6840          break;
6841 #ifdef HAVE_CHEEVOS
6842       case DISCORD_PRESENCE_RETROACHIEVEMENTS:
6843          if (discord_st->pause_time)
6844             return;
6845 
6846          if (rcheevos_get_richpresence(cheevos_richpresence, sizeof(cheevos_richpresence)) > 0)
6847             discord_st->presence.details = cheevos_richpresence;
6848          presence = DISCORD_PRESENCE_GAME;
6849          break;
6850 #endif
6851       case DISCORD_PRESENCE_SHUTDOWN:
6852             discord_st->presence.partyId    = NULL;
6853             discord_st->presence.partyMax   = 0;
6854             discord_st->presence.partySize  = 0;
6855             discord_st->presence.joinSecret = (const char*)'\0';
6856             discord_st->connecting          = false;
6857       default:
6858          break;
6859    }
6860 
6861 #ifdef DEBUG
6862    RARCH_LOG("[DISCORD]: Updating (%d)\n", presence);
6863 #endif
6864 
6865    Discord_UpdatePresence(&discord_st->presence);
6866 #ifdef DISCORD_DISABLE_IO_THREAD
6867    Discord_UpdateConnection();
6868 #endif
6869    discord_st->status = presence;
6870 }
6871 
discord_init(discord_state_t * discord_st,const char * discord_app_id,char * args)6872 static void discord_init(
6873       discord_state_t *discord_st,
6874       const char *discord_app_id, char *args)
6875 {
6876    DiscordEventHandlers handlers;
6877    char full_path[PATH_MAX_LENGTH];
6878    char command[PATH_MAX_LENGTH];
6879 
6880    discord_st->start_time      = time(0);
6881 
6882    handlers.ready              = handle_discord_ready;
6883    handlers.disconnected       = handle_discord_disconnected;
6884    handlers.errored            = handle_discord_error;
6885    handlers.joinGame           = handle_discord_join;
6886    handlers.spectateGame       = handle_discord_spectate;
6887    handlers.joinRequest        = handle_discord_join_request;
6888 
6889    Discord_Initialize(discord_app_id, &handlers, 0, NULL);
6890 #ifdef DISCORD_DISABLE_IO_THREAD
6891    Discord_UpdateConnection();
6892 #endif
6893 
6894 #ifdef _WIN32
6895    fill_pathname_application_path(full_path, sizeof(full_path));
6896    if (strstr(args, full_path))
6897       strlcpy(command, args, sizeof(command));
6898    else
6899    {
6900       path_basedir(full_path);
6901       strlcpy(command, full_path, sizeof(command));
6902       strlcat(command, args,      sizeof(command));
6903    }
6904 #else
6905    strcpy_literal(command, "sh -c ");
6906    strlcat(command, args,     sizeof(command));
6907 #endif
6908    RARCH_LOG("[DISCORD]: Registering startup command: %s\n", command);
6909    Discord_Register(discord_app_id, command);
6910 #ifdef DISCORD_DISABLE_IO_THREAD
6911    Discord_UpdateConnection();
6912 #endif
6913    discord_st->ready = true;
6914 }
6915 #endif
6916 
6917 #ifdef HAVE_NETWORKING
6918 /**
6919  * netplay_is_alive:
6920  * @netplay              : pointer to netplay object
6921  *
6922  * Checks if input port/index is controlled by netplay or not.
6923  *
6924  * Returns: true (1) if alive, otherwise false (0).
6925  **/
netplay_is_alive(netplay_t * netplay)6926 static bool netplay_is_alive(netplay_t *netplay)
6927 {
6928    return (netplay->is_server) ||
6929           (!netplay->is_server &&
6930            netplay->self_mode >= NETPLAY_CONNECTION_CONNECTED);
6931 }
6932 
6933 /**
6934  * netplay_should_skip:
6935  * @netplay              : pointer to netplay object
6936  *
6937  * If we're fast-forward replaying to resync, check if we
6938  * should actually show frame.
6939  *
6940  * Returns: bool (1) if we should skip this frame, otherwise
6941  * false (0).
6942  **/
netplay_should_skip(netplay_t * netplay)6943 static bool netplay_should_skip(netplay_t *netplay)
6944 {
6945    if (!netplay)
6946       return false;
6947    return netplay->is_replay
6948       && (netplay->self_mode >= NETPLAY_CONNECTION_CONNECTED);
6949 }
6950 
6951 /**
6952  * get_self_input_state:
6953  * @netplay              : pointer to netplay object
6954  *
6955  * Grab our own input state and send this frame's input state (self and remote)
6956  * over the network
6957  *
6958  * Returns: true (1) if successful, otherwise false (0).
6959  */
get_self_input_state(bool block_libretro_input,netplay_t * netplay)6960 static bool get_self_input_state(
6961       bool block_libretro_input,
6962       netplay_t *netplay)
6963 {
6964    unsigned i;
6965    struct delta_frame *ptr        = &netplay->buffer[netplay->self_ptr];
6966    netplay_input_state_t istate   = NULL;
6967    uint32_t devices, used_devices = 0, devi, dev_type, local_device;
6968 
6969    if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count))
6970       return false;
6971 
6972    /* We've already read this frame! */
6973    if (ptr->have_local)
6974       return true;
6975 
6976    devices      = netplay->self_devices;
6977    used_devices = 0;
6978 
6979    for (devi = 0; devi < MAX_INPUT_DEVICES; devi++)
6980    {
6981       if (!(devices & (1 << devi)))
6982          continue;
6983 
6984       /* Find an appropriate local device */
6985       dev_type = netplay->config_devices[devi]&RETRO_DEVICE_MASK;
6986 
6987       for (local_device = 0; local_device < MAX_INPUT_DEVICES; local_device++)
6988       {
6989          if (used_devices & (1 << local_device))
6990             continue;
6991          if ((netplay->config_devices[local_device]&RETRO_DEVICE_MASK) == dev_type)
6992             break;
6993       }
6994 
6995       if (local_device == MAX_INPUT_DEVICES)
6996          local_device = 0;
6997       used_devices |= (1 << local_device);
6998 
6999       istate = netplay_input_state_for(&ptr->real_input[devi],
7000             /* If we're a slave, we write our own input to MAX_CLIENTS to keep it separate */
7001             (netplay->self_mode==NETPLAY_CONNECTION_SLAVE)?MAX_CLIENTS:netplay->self_client_num,
7002             netplay_expected_input_size(netplay, 1 << devi),
7003             true, false);
7004       if (!istate)
7005          continue; /* FIXME: More severe? */
7006 
7007       /* First frame we always give zero input since relying on
7008        * input from first frame screws up when we use -F 0. */
7009       if (     !block_libretro_input
7010             &&  netplay->self_frame_count > 0)
7011       {
7012          uint32_t *state        = istate->data;
7013          retro_input_state_t cb = netplay->cbs.state_cb;
7014          unsigned dtype         = netplay->config_devices[devi]&RETRO_DEVICE_MASK;
7015 
7016          switch (dtype)
7017          {
7018             case RETRO_DEVICE_ANALOG:
7019                for (i = 0; i < 2; i++)
7020                {
7021                   int16_t tmp_x = cb(local_device,
7022                         RETRO_DEVICE_ANALOG, (unsigned)i, 0);
7023                   int16_t tmp_y = cb(local_device,
7024                         RETRO_DEVICE_ANALOG, (unsigned)i, 1);
7025                   state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
7026                }
7027                /* no break */
7028 
7029             case RETRO_DEVICE_JOYPAD:
7030                for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++)
7031                {
7032                   int16_t tmp = cb(local_device,
7033                         RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
7034                   state[0] |= tmp ? 1 << i : 0;
7035                }
7036                break;
7037 
7038             case RETRO_DEVICE_MOUSE:
7039             case RETRO_DEVICE_LIGHTGUN:
7040             {
7041                int16_t tmp_x = cb(local_device, dtype, 0, 0);
7042                int16_t tmp_y = cb(local_device, dtype, 0, 1);
7043                state[1] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
7044                for (i = 2;
7045                      i <= (unsigned)((dtype == RETRO_DEVICE_MOUSE) ?
7046                            RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN :
7047                            RETRO_DEVICE_ID_LIGHTGUN_START);
7048                      i++)
7049                {
7050                   int16_t tmp = cb(local_device, dtype, 0,
7051                         (unsigned) i);
7052                   state[0] |= tmp ? 1 << i : 0;
7053                }
7054                break;
7055             }
7056 
7057             case RETRO_DEVICE_KEYBOARD:
7058             {
7059                unsigned key, word = 0, bit = 1;
7060                for (key = 1; key < NETPLAY_KEY_LAST; key++)
7061                {
7062                   state[word] |=
7063                         cb(local_device, RETRO_DEVICE_KEYBOARD, 0,
7064                               NETPLAY_KEY_NTOH(key)) ?
7065                               (UINT32_C(1) << bit) : 0;
7066                   bit++;
7067                   if (bit >= 32)
7068                   {
7069                      bit = 0;
7070                      word++;
7071                      if (word >= istate->size)
7072                         break;
7073                   }
7074                }
7075                break;
7076             }
7077          }
7078       }
7079    }
7080 
7081    ptr->have_local = true;
7082    if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
7083    {
7084       ptr->have_real[netplay->self_client_num] = true;
7085       netplay->read_ptr[netplay->self_client_num] = NEXT_PTR(netplay->self_ptr);
7086       netplay->read_frame_count[netplay->self_client_num] = netplay->self_frame_count + 1;
7087    }
7088 
7089    /* And send this input to our peers */
7090    for (i = 0; i < netplay->connections_size; i++)
7091    {
7092       struct netplay_connection *connection = &netplay->connections[i];
7093       if (connection->active && connection->mode >= NETPLAY_CONNECTION_CONNECTED)
7094          netplay_send_cur_input(netplay, &netplay->connections[i]);
7095    }
7096 
7097    /* Handle any delayed state changes */
7098    if (netplay->is_server)
7099       netplay_delayed_state_change(netplay);
7100 
7101    return true;
7102 }
7103 
init_netplay_deferred(struct rarch_state * p_rarch,const char * server,unsigned port)7104 static bool init_netplay_deferred(
7105       struct rarch_state *p_rarch,
7106       const char* server, unsigned port)
7107 {
7108    if (!string_is_empty(server) && port != 0)
7109    {
7110       strlcpy(p_rarch->server_address_deferred, server,
7111             sizeof(p_rarch->server_address_deferred));
7112       p_rarch->server_port_deferred    = port;
7113       p_rarch->netplay_client_deferred = true;
7114    }
7115    else
7116       p_rarch->netplay_client_deferred = false;
7117 
7118    return p_rarch->netplay_client_deferred;
7119 }
7120 
7121 /**
7122  * netplay_poll:
7123  * @netplay              : pointer to netplay object
7124  *
7125  * Polls network to see if we have anything new. If our
7126  * network buffer is full, we simply have to block
7127  * for new input data.
7128  *
7129  * Returns: true (1) if successful, otherwise false (0).
7130  **/
netplay_poll(bool block_libretro_input,settings_t * settings,netplay_t * netplay)7131 static bool netplay_poll(
7132       bool block_libretro_input,
7133       settings_t *settings,
7134       netplay_t *netplay)
7135 {
7136    int res;
7137    uint32_t client;
7138    size_t i;
7139 
7140    if (!get_self_input_state(block_libretro_input, netplay))
7141       goto catastrophe;
7142 
7143    /* If we're not connected, we're done */
7144    if (netplay->self_mode == NETPLAY_CONNECTION_NONE)
7145       return true;
7146 
7147    /* Read Netplay input, block if we're configured to stall for input every
7148     * frame */
7149    netplay_update_unread_ptr(netplay);
7150    if (netplay->stateless_mode &&
7151        (netplay->connected_players>1) &&
7152        netplay->unread_frame_count <= netplay->run_frame_count)
7153       res = netplay_poll_net_input(netplay, true);
7154    else
7155       res = netplay_poll_net_input(netplay, false);
7156    if (res == -1)
7157       goto catastrophe;
7158 
7159    /* Resolve and/or simulate the input if we don't have real input */
7160    netplay_resolve_input(netplay, netplay->run_ptr, false);
7161 
7162    /* Handle any slaves */
7163    if (netplay->is_server && netplay->connected_slaves)
7164       netplay_handle_slaves(netplay);
7165 
7166    netplay_update_unread_ptr(netplay);
7167 
7168    /* Figure out how many frames of input latency we should be using to hide
7169     * network latency */
7170    if (netplay->frame_run_time_avg || netplay->stateless_mode)
7171    {
7172       /* FIXME: Using fixed 60fps for this calculation */
7173       unsigned frames_per_frame    = netplay->frame_run_time_avg ?
7174          (16666 / netplay->frame_run_time_avg) :
7175          0;
7176       unsigned frames_ahead        = (netplay->run_frame_count > netplay->unread_frame_count) ?
7177          (netplay->run_frame_count - netplay->unread_frame_count) :
7178          0;
7179       int input_latency_frames_min = settings->uints.netplay_input_latency_frames_min -
7180             (settings->bools.run_ahead_enabled ? settings->uints.run_ahead_frames : 0);
7181       int input_latency_frames_max = input_latency_frames_min + settings->uints.netplay_input_latency_frames_range;
7182 
7183       /* Assume we need a couple frames worth of time to actually run the
7184        * current frame */
7185       if (frames_per_frame > 2)
7186          frames_per_frame -= 2;
7187       else
7188          frames_per_frame = 0;
7189 
7190       /* Shall we adjust our latency? */
7191       if (netplay->stateless_mode)
7192       {
7193          /* In stateless mode, we adjust up if we're "close" and down if we
7194           * have a lot of slack */
7195          if (netplay->input_latency_frames < input_latency_frames_min ||
7196                (netplay->unread_frame_count == netplay->run_frame_count + 1 &&
7197                 netplay->input_latency_frames < input_latency_frames_max))
7198             netplay->input_latency_frames++;
7199          else if (netplay->input_latency_frames > input_latency_frames_max ||
7200                (netplay->unread_frame_count > netplay->run_frame_count + 2 &&
7201                 netplay->input_latency_frames > input_latency_frames_min))
7202             netplay->input_latency_frames--;
7203       }
7204       else if (netplay->input_latency_frames < input_latency_frames_min ||
7205                (frames_per_frame < frames_ahead &&
7206                 netplay->input_latency_frames < input_latency_frames_max))
7207       {
7208          /* We can't hide this much network latency with replay, so hide some
7209           * with input latency */
7210          netplay->input_latency_frames++;
7211       }
7212       else if (netplay->input_latency_frames > input_latency_frames_max ||
7213                (frames_per_frame > frames_ahead + 2 &&
7214                 netplay->input_latency_frames > input_latency_frames_min))
7215       {
7216          /* We don't need this much latency (any more) */
7217          netplay->input_latency_frames--;
7218       }
7219    }
7220 
7221    /* If we're stalled, consider unstalling */
7222    switch (netplay->stall)
7223    {
7224       case NETPLAY_STALL_RUNNING_FAST:
7225          if (netplay->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2
7226                > netplay->self_frame_count)
7227          {
7228             netplay->stall = NETPLAY_STALL_NONE;
7229             for (i = 0; i < netplay->connections_size; i++)
7230             {
7231                struct netplay_connection *connection = &netplay->connections[i];
7232                if (connection->active && connection->stall)
7233                   connection->stall = NETPLAY_STALL_NONE;
7234             }
7235          }
7236          break;
7237 
7238       case NETPLAY_STALL_SPECTATOR_WAIT:
7239          if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING || netplay->unread_frame_count > netplay->self_frame_count)
7240             netplay->stall = NETPLAY_STALL_NONE;
7241          break;
7242 
7243       case NETPLAY_STALL_INPUT_LATENCY:
7244          /* Just let it recalculate momentarily */
7245          netplay->stall = NETPLAY_STALL_NONE;
7246          break;
7247 
7248       case NETPLAY_STALL_SERVER_REQUESTED:
7249          /* See if the stall is done */
7250          if (netplay->connections[0].stall_frame == 0)
7251          {
7252             /* Stop stalling! */
7253             netplay->connections[0].stall = NETPLAY_STALL_NONE;
7254             netplay->stall = NETPLAY_STALL_NONE;
7255          }
7256          else
7257             netplay->connections[0].stall_frame--;
7258          break;
7259       case NETPLAY_STALL_NO_CONNECTION:
7260          /* We certainly haven't fixed this */
7261          break;
7262       default: /* not stalling */
7263          break;
7264    }
7265 
7266    /* If we're not stalled, consider stalling */
7267    if (!netplay->stall)
7268    {
7269       /* Have we not read enough latency frames? */
7270       if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING &&
7271           netplay->connected_players &&
7272           netplay->run_frame_count + netplay->input_latency_frames > netplay->self_frame_count)
7273       {
7274          netplay->stall = NETPLAY_STALL_INPUT_LATENCY;
7275          netplay->stall_time = 0;
7276       }
7277 
7278       /* Are we too far ahead? */
7279       if (netplay->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
7280             <= netplay->self_frame_count)
7281       {
7282          netplay->stall      = NETPLAY_STALL_RUNNING_FAST;
7283          netplay->stall_time = cpu_features_get_time_usec();
7284 
7285          /* Figure out who to blame */
7286          if (netplay->is_server)
7287          {
7288             for (client = 1; client < MAX_CLIENTS; client++)
7289             {
7290                struct netplay_connection *connection;
7291                if (!(netplay->connected_players & (1 << client)))
7292                   continue;
7293                if (netplay->read_frame_count[client] > netplay->unread_frame_count)
7294                   continue;
7295                connection = &netplay->connections[client-1];
7296                if (connection->active &&
7297                    connection->mode == NETPLAY_CONNECTION_PLAYING)
7298                {
7299                   connection->stall = NETPLAY_STALL_RUNNING_FAST;
7300                   connection->stall_time = netplay->stall_time;
7301                }
7302             }
7303          }
7304 
7305       }
7306 
7307       /* If we're a spectator, are we ahead at all? */
7308       if (!netplay->is_server &&
7309           (netplay->self_mode == NETPLAY_CONNECTION_SPECTATING ||
7310            netplay->self_mode == NETPLAY_CONNECTION_SLAVE) &&
7311           netplay->unread_frame_count <= netplay->self_frame_count)
7312       {
7313          netplay->stall = NETPLAY_STALL_SPECTATOR_WAIT;
7314          netplay->stall_time = cpu_features_get_time_usec();
7315       }
7316    }
7317 
7318    /* If we're stalling, consider disconnection */
7319    if (netplay->stall && netplay->stall_time)
7320    {
7321       retro_time_t now = cpu_features_get_time_usec();
7322 
7323       /* Don't stall out while they're paused */
7324       if (netplay->remote_paused)
7325          netplay->stall_time = now;
7326       else if (now - netplay->stall_time >=
7327                (netplay->is_server ? MAX_SERVER_STALL_TIME_USEC :
7328                                           MAX_CLIENT_STALL_TIME_USEC))
7329       {
7330          /* Stalled out! */
7331          if (netplay->is_server)
7332          {
7333             bool fixed = false;
7334             for (i = 0; i < netplay->connections_size; i++)
7335             {
7336                struct netplay_connection *connection = &netplay->connections[i];
7337                if (connection->active &&
7338                    connection->mode == NETPLAY_CONNECTION_PLAYING &&
7339                    connection->stall)
7340                {
7341                   netplay_hangup(netplay, connection);
7342                   fixed = true;
7343                }
7344             }
7345 
7346             if (fixed)
7347             {
7348                /* Not stalled now :) */
7349                netplay->stall = NETPLAY_STALL_NONE;
7350                return true;
7351             }
7352          }
7353          else
7354             goto catastrophe;
7355          return false;
7356       }
7357    }
7358 
7359    return true;
7360 
7361 catastrophe:
7362    for (i = 0; i < netplay->connections_size; i++)
7363       netplay_hangup(netplay, &netplay->connections[i]);
7364    return false;
7365 }
7366 
7367 /**
7368  * input_poll_net
7369  *
7370  * Poll the network if necessary.
7371  */
input_poll_net(void)7372 void input_poll_net(void)
7373 {
7374    struct rarch_state *p_rarch = &rarch_st;
7375    netplay_t          *netplay = p_rarch->netplay_data;
7376    if (!netplay_should_skip(netplay) && netplay && netplay->can_poll)
7377    {
7378       netplay->can_poll = false;
7379       netplay_poll(
7380             p_rarch->input_driver_block_libretro_input,
7381             p_rarch->configuration_settings,
7382             netplay);
7383    }
7384 }
7385 
7386 /* Netplay polling callbacks */
video_frame_net(const void * data,unsigned width,unsigned height,size_t pitch)7387 static void video_frame_net(const void *data, unsigned width,
7388       unsigned height, size_t pitch)
7389 {
7390    struct rarch_state *p_rarch = &rarch_st;
7391    netplay_t          *netplay = p_rarch->netplay_data;
7392    if (!netplay_should_skip(netplay))
7393       netplay->cbs.frame_cb(data, width, height, pitch);
7394 }
7395 
audio_sample_net(int16_t left,int16_t right)7396 static void audio_sample_net(int16_t left, int16_t right)
7397 {
7398    struct rarch_state *p_rarch = &rarch_st;
7399    netplay_t          *netplay = p_rarch->netplay_data;
7400    if (!netplay_should_skip(netplay) && !netplay->stall)
7401       netplay->cbs.sample_cb(left, right);
7402 }
7403 
audio_sample_batch_net(const int16_t * data,size_t frames)7404 static size_t audio_sample_batch_net(const int16_t *data, size_t frames)
7405 {
7406    struct rarch_state *p_rarch = &rarch_st;
7407    netplay_t          *netplay = p_rarch->netplay_data;
7408    if (!netplay_should_skip(netplay) && !netplay->stall)
7409       return netplay->cbs.sample_batch_cb(data, frames);
7410    return frames;
7411 }
7412 
netplay_input_state(netplay_t * netplay,unsigned port,unsigned device,unsigned idx,unsigned id)7413 static int16_t netplay_input_state(netplay_t *netplay,
7414       unsigned port, unsigned device,
7415       unsigned idx, unsigned id)
7416 {
7417    struct delta_frame *delta;
7418    netplay_input_state_t istate;
7419    const uint32_t *curr_input_state = NULL;
7420    size_t ptr                       =
7421       netplay->is_replay
7422       ? netplay->replay_ptr
7423       : netplay->run_ptr;
7424 
7425    if (port >= MAX_INPUT_DEVICES)
7426       return 0;
7427 
7428    /* If the port doesn't seem to correspond to the device, "correct" it. This
7429     * is common with devices that typically only have one instance, such as
7430     * keyboards, mice and lightguns. */
7431    if (device != RETRO_DEVICE_JOYPAD &&
7432        (netplay->config_devices[port]&RETRO_DEVICE_MASK) != device)
7433    {
7434       for (port = 0; port < MAX_INPUT_DEVICES; port++)
7435       {
7436          if ((netplay->config_devices[port]&RETRO_DEVICE_MASK) == device)
7437             break;
7438       }
7439       if (port == MAX_INPUT_DEVICES)
7440          return 0;
7441    }
7442 
7443    delta  = &netplay->buffer[ptr];
7444    istate = delta->resolved_input[port];
7445    if (!istate || !istate->used || istate->size == 0)
7446       return 0;
7447 
7448    curr_input_state = istate->data;
7449 
7450    switch (device)
7451    {
7452       case RETRO_DEVICE_JOYPAD:
7453          if (id == RETRO_DEVICE_ID_JOYPAD_MASK)
7454             return curr_input_state[0];
7455          return ((1 << id) & curr_input_state[0]) ? 1 : 0;
7456 
7457       case RETRO_DEVICE_ANALOG:
7458          if (istate->size == 3)
7459          {
7460             uint32_t state = curr_input_state[1 + idx];
7461             return (int16_t)(uint16_t)(state >> (id * 16));
7462          }
7463          break;
7464       case RETRO_DEVICE_MOUSE:
7465       case RETRO_DEVICE_LIGHTGUN:
7466          if (istate->size == 2)
7467          {
7468             if (id <= RETRO_DEVICE_ID_MOUSE_Y)
7469                return (int16_t)(uint16_t)(curr_input_state[1] >> (id * 16));
7470             return ((1 << id) & curr_input_state[0]) ? 1 : 0;
7471          }
7472          break;
7473       case RETRO_DEVICE_KEYBOARD:
7474          {
7475             unsigned key = netplay_key_hton(id);
7476             if (key != NETPLAY_KEY_UNKNOWN)
7477             {
7478                unsigned word = key / 32;
7479                unsigned bit  = key % 32;
7480                if (word <= istate->size)
7481                   return ((UINT32_C(1) << bit) & curr_input_state[word]) ? 1 : 0;
7482             }
7483          }
7484          break;
7485       default:
7486          break;
7487    }
7488 
7489    return 0;
7490 }
7491 
netplay_announce_cb(retro_task_t * task,void * task_data,void * user_data,const char * error)7492 static void netplay_announce_cb(retro_task_t *task,
7493       void *task_data, void *user_data, const char *error)
7494 {
7495    if (task_data)
7496    {
7497       unsigned i, ip_len, port_len;
7498       struct rarch_state *p_rarch    = &rarch_st;
7499       http_transfer_data_t *data     = (http_transfer_data_t*)task_data;
7500       struct netplay_room *host_room = &p_rarch->netplay_host_room;
7501       struct string_list *lines      = NULL;
7502       char *mitm_ip                  = NULL;
7503       char *mitm_port                = NULL;
7504       char *buf                      = NULL;
7505       char *host_string              = NULL;
7506 
7507       if (data->len == 0)
7508          return;
7509 
7510       buf = (char*)calloc(1, data->len + 1);
7511 
7512       memcpy(buf, data->data, data->len);
7513 
7514       lines = string_split(buf, "\n");
7515 
7516       if (lines->size == 0)
7517       {
7518          string_list_free(lines);
7519          free(buf);
7520          return;
7521       }
7522 
7523       memset(host_room, 0, sizeof(*host_room));
7524 
7525       for (i = 0; i < lines->size; i++)
7526       {
7527          const char *line = lines->elems[i].data;
7528 
7529          if (!string_is_empty(line))
7530          {
7531             struct string_list *kv = string_split(line, "=");
7532             const char *key = NULL;
7533             const char *val = NULL;
7534 
7535             if (!kv)
7536                continue;
7537 
7538             if (kv->size != 2)
7539             {
7540                string_list_free(kv);
7541                continue;
7542             }
7543 
7544             key = kv->elems[0].data;
7545             val = kv->elems[1].data;
7546 
7547             if (string_is_equal(key, "id"))
7548                sscanf(val, "%i", &host_room->id);
7549             if (string_is_equal(key, "username"))
7550                strlcpy(host_room->nickname, val, sizeof(host_room->nickname));
7551             if (string_is_equal(key, "ip"))
7552                strlcpy(host_room->address, val, sizeof(host_room->address));
7553             if (string_is_equal(key, "mitm_ip"))
7554             {
7555                mitm_ip = strdup(val);
7556                strlcpy(host_room->mitm_address, val, sizeof(host_room->mitm_address));
7557             }
7558             if (string_is_equal(key, "port"))
7559                sscanf(val, "%i", &host_room->port);
7560             if (string_is_equal(key, "mitm_port"))
7561             {
7562                mitm_port = strdup(val);
7563                sscanf(mitm_port, "%i", &host_room->mitm_port);
7564             }
7565             if (string_is_equal(key, "core_name"))
7566                strlcpy(host_room->corename, val, sizeof(host_room->corename));
7567             if (string_is_equal(key, "frontend"))
7568                strlcpy(host_room->frontend, val, sizeof(host_room->frontend));
7569             if (string_is_equal(key, "core_version"))
7570                strlcpy(host_room->coreversion, val, sizeof(host_room->coreversion));
7571             if (string_is_equal(key, "game_name"))
7572                strlcpy(host_room->gamename, val, sizeof(host_room->gamename));
7573             if (string_is_equal(key, "game_crc"))
7574                sscanf(val, "%08d", &host_room->gamecrc);
7575             if (string_is_equal(key, "host_method"))
7576                sscanf(val, "%i", &host_room->host_method);
7577             if (string_is_equal(key, "has_password"))
7578             {
7579                if (string_is_equal_noncase(val, "true") || string_is_equal(val, "1"))
7580                   host_room->has_password = true;
7581                else
7582                   host_room->has_password = false;
7583             }
7584             if (string_is_equal(key, "has_spectate_password"))
7585             {
7586                if (string_is_equal_noncase(val, "true") || string_is_equal(val, "1"))
7587                   host_room->has_spectate_password = true;
7588                else
7589                   host_room->has_spectate_password = false;
7590             }
7591             if (string_is_equal(key, "fixed"))
7592             {
7593                if (string_is_equal_noncase(val, "true") || string_is_equal(val, "1"))
7594                   host_room->fixed = true;
7595                else
7596                   host_room->fixed = false;
7597             }
7598             if (string_is_equal(key, "retroarch_version"))
7599                strlcpy(host_room->retroarch_version, val, sizeof(host_room->retroarch_version));
7600             if (string_is_equal(key, "country"))
7601                strlcpy(host_room->country, val, sizeof(host_room->country));
7602 
7603             string_list_free(kv);
7604          }
7605       }
7606 
7607       if (mitm_ip && mitm_port)
7608       {
7609          ip_len   = (unsigned)strlen(mitm_ip);
7610          port_len = (unsigned)strlen(mitm_port);
7611 
7612          /* Enable Netplay client mode */
7613          if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
7614          {
7615             command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
7616             p_rarch->is_mitm       = true;
7617             host_room->host_method = NETPLAY_HOST_METHOD_MITM;
7618          }
7619 
7620          netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
7621 
7622          host_string = (char*)calloc(1, ip_len + port_len + 2);
7623 
7624          memcpy(host_string, mitm_ip, ip_len);
7625          memcpy(host_string + ip_len, "|", 1);
7626          memcpy(host_string + ip_len + 1, mitm_port, port_len);
7627 
7628          /* Enable Netplay */
7629          command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, (void*)host_string);
7630          command_event(CMD_EVENT_NETPLAY_INIT, (void*)host_string);
7631 
7632          free(host_string);
7633       }
7634 
7635 #ifdef HAVE_DISCORD
7636       if (discord_is_inited)
7637       {
7638          discord_userdata_t userdata;
7639          userdata.status = DISCORD_PRESENCE_NETPLAY_HOSTING;
7640          command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
7641       }
7642 #endif
7643 
7644       string_list_free(lines);
7645       free(buf);
7646 
7647       if (mitm_ip)
7648          free(mitm_ip);
7649       if (mitm_port)
7650          free(mitm_port);
7651    }
7652 }
7653 
netplay_announce(struct rarch_state * p_rarch)7654 static void netplay_announce(struct rarch_state *p_rarch)
7655 {
7656    char buf[4600];
7657    char frontend_architecture[PATH_MAX_LENGTH];
7658    char frontend_architecture_tmp[32];
7659    const frontend_ctx_driver_t
7660       *frontend_drv                 =  NULL;
7661    char url[2048]                   = "http://lobby.libretro.com/add/";
7662    char *username                   = NULL;
7663    char *corename                   = NULL;
7664    char *gamename                   = NULL;
7665    char *subsystemname              = NULL;
7666    char *coreversion                = NULL;
7667    char *frontend_ident             = NULL;
7668    settings_t *settings             = p_rarch->configuration_settings;
7669    struct retro_system_info *system = &runloop_state.system.info;
7670    uint32_t content_crc             = content_get_crc();
7671    struct string_list *subsystem    = path_get_subsystem_list();
7672 
7673    frontend_architecture[0]         = '\0';
7674    buf[0]                           = '\0';
7675 
7676    if (subsystem)
7677    {
7678       unsigned i;
7679 
7680       for (i = 0; i < subsystem->size; i++)
7681       {
7682          strlcat(buf, path_basename(subsystem->elems[i].data), sizeof(buf));
7683          if (i < subsystem->size - 1)
7684             strlcat(buf, "|", sizeof(buf));
7685       }
7686       net_http_urlencode(&gamename, buf);
7687       net_http_urlencode(&subsystemname, path_get(RARCH_PATH_SUBSYSTEM));
7688       content_crc = 0;
7689    }
7690    else
7691    {
7692       const char *base = path_basename(path_get(RARCH_PATH_BASENAME));
7693 
7694       net_http_urlencode(&gamename,
7695          !string_is_empty(base) ? base : "N/A");
7696       /* TODO/FIXME - subsystem should be implemented later? */
7697       net_http_urlencode(&subsystemname, "N/A");
7698    }
7699 
7700    frontend_drv =
7701       (const frontend_ctx_driver_t*)frontend_driver_get_cpu_architecture_str(
7702             frontend_architecture_tmp, sizeof(frontend_architecture_tmp));
7703    snprintf(frontend_architecture,
7704          sizeof(frontend_architecture),
7705          "%s %s",
7706          frontend_drv->ident,
7707          frontend_architecture_tmp);
7708 
7709 #ifdef HAVE_DISCORD
7710    if (discord_is_ready())
7711       net_http_urlencode(&username, discord_get_own_username(p_rarch));
7712    else
7713 #endif
7714    net_http_urlencode(&username, settings->paths.username);
7715    net_http_urlencode(&corename, system->library_name);
7716    net_http_urlencode(&coreversion, system->library_version);
7717    net_http_urlencode(&frontend_ident, frontend_architecture);
7718 
7719    buf[0] = '\0';
7720 
7721    snprintf(buf, sizeof(buf), "username=%s&core_name=%s&core_version=%s&"
7722       "game_name=%s&game_crc=%08X&port=%d&mitm_server=%s"
7723       "&has_password=%d&has_spectate_password=%d&force_mitm=%d"
7724       "&retroarch_version=%s&frontend=%s&subsystem_name=%s",
7725       username, corename, coreversion, gamename, content_crc,
7726       settings->uints.netplay_port,
7727       settings->arrays.netplay_mitm_server,
7728       *settings->paths.netplay_password ? 1 : 0,
7729       *settings->paths.netplay_spectate_password ? 1 : 0,
7730       settings->bools.netplay_use_mitm_server,
7731       PACKAGE_VERSION, frontend_architecture, subsystemname);
7732    task_push_http_post_transfer(url, buf, true, NULL,
7733          netplay_announce_cb, NULL);
7734 
7735    if (username)
7736       free(username);
7737    if (corename)
7738       free(corename);
7739    if (gamename)
7740       free(gamename);
7741    if (coreversion)
7742       free(coreversion);
7743    if (frontend_ident)
7744       free(frontend_ident);
7745 }
7746 
input_state_net(unsigned port,unsigned device,unsigned idx,unsigned id)7747 static int16_t input_state_net(unsigned port, unsigned device,
7748       unsigned idx, unsigned id)
7749 {
7750    struct rarch_state *p_rarch = &rarch_st;
7751    netplay_t          *netplay = p_rarch->netplay_data;
7752    if (netplay)
7753    {
7754       if (netplay_is_alive(netplay))
7755          return netplay_input_state(netplay, port, device, idx, id);
7756       return netplay->cbs.state_cb(port, device, idx, id);
7757    }
7758    return 0;
7759 }
7760 
7761 /* ^^^ Netplay polling callbacks */
7762 
7763 /**
7764 * netplay_frontend_paused
7765  * @netplay              : pointer to netplay object
7766  * @paused               : true if frontend is paused
7767  *
7768  * Inform Netplay of the frontend's pause state (paused or otherwise)
7769  */
netplay_frontend_paused(netplay_t * netplay,bool paused)7770 static void netplay_frontend_paused(netplay_t *netplay, bool paused)
7771 {
7772    size_t i;
7773    uint32_t paused_ct    = 0;
7774 
7775    netplay->local_paused = paused;
7776 
7777    /* Communicating this is a bit odd: If exactly one other connection is
7778     * paused, then we must tell them that we're unpaused, as from their
7779     * perspective we are. If more than one other connection is paused, then our
7780     * status as proxy means we are NOT unpaused to either of them. */
7781    for (i = 0; i < netplay->connections_size; i++)
7782    {
7783       struct netplay_connection *connection = &netplay->connections[i];
7784       if (connection->active && connection->paused)
7785          paused_ct++;
7786    }
7787 
7788    if (paused_ct > 1)
7789       return;
7790 
7791    /* Send our unpaused status. Must send manually because we must immediately
7792     * flush the buffer: If we're paused, we won't be polled. */
7793    for (i = 0; i < netplay->connections_size; i++)
7794    {
7795       struct netplay_connection *connection = &netplay->connections[i];
7796       if (     connection->active
7797             && connection->mode >= NETPLAY_CONNECTION_CONNECTED)
7798       {
7799          if (paused)
7800             netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_PAUSE,
7801                netplay->nick, NETPLAY_NICK_LEN);
7802          else
7803             netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_RESUME,
7804                NULL, 0);
7805 
7806          /* We're not going to be polled, so we need to
7807           * flush this command now */
7808          netplay_send_flush(&connection->send_packet_buffer,
7809                connection->fd, true);
7810       }
7811    }
7812 }
7813 
7814 /**
7815  * netplay_disconnect
7816  * @netplay              : pointer to netplay object
7817  *
7818  * Disconnect netplay.
7819  *
7820  * Returns: true (1) if successful. At present, cannot fail.
7821  **/
netplay_disconnect(struct rarch_state * p_rarch,netplay_t * netplay)7822 static void netplay_disconnect(
7823       struct rarch_state *p_rarch,
7824       netplay_t *netplay)
7825 {
7826    size_t i;
7827 
7828    for (i = 0; i < netplay->connections_size; i++)
7829       netplay_hangup(netplay, &netplay->connections[i]);
7830 
7831    deinit_netplay(p_rarch);
7832 
7833 #ifdef HAVE_DISCORD
7834    if (discord_is_inited)
7835    {
7836       discord_userdata_t userdata;
7837       userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
7838       command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
7839    }
7840 #endif
7841 }
7842 
7843 /**
7844  * netplay_pre_frame:
7845  * @netplay              : pointer to netplay object
7846  *
7847  * Pre-frame for Netplay.
7848  * Call this before running retro_run().
7849  *
7850  * Returns: true (1) if the frontend is cleared to emulate the frame, false (0)
7851  * if we're stalled or paused
7852  **/
netplay_pre_frame(struct rarch_state * p_rarch,bool netplay_public_announce,bool netplay_use_mitm_server,netplay_t * netplay)7853 static bool netplay_pre_frame(
7854       struct rarch_state *p_rarch,
7855       bool netplay_public_announce,
7856       bool netplay_use_mitm_server,
7857       netplay_t *netplay)
7858 {
7859    bool sync_stalled     = false;
7860 
7861    retro_assert(netplay);
7862 
7863    if (netplay_public_announce)
7864    {
7865       p_rarch->reannounce++;
7866       if (
7867             (netplay->is_server || p_rarch->is_mitm) &&
7868             (p_rarch->reannounce % 300 == 0))
7869          netplay_announce(p_rarch);
7870    }
7871    /* Make sure that if announcement is turned on mid-game, it gets announced */
7872    else
7873       p_rarch->reannounce = -1;
7874 
7875    /* FIXME: This is an ugly way to learn we're not paused anymore */
7876    if (netplay->local_paused)
7877       if (netplay->local_paused != false)
7878          netplay_frontend_paused(netplay, false);
7879 
7880    /* Are we ready now? */
7881    if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
7882       netplay_try_init_serialization(netplay);
7883 
7884    if (netplay->is_server && !netplay_use_mitm_server)
7885    {
7886       /* Advertise our server */
7887       netplay_lan_ad_server(netplay);
7888 
7889       /* NAT traversal if applicable */
7890       if (netplay->nat_traversal &&
7891           !netplay->nat_traversal_task_oustanding &&
7892           netplay->nat_traversal_state.request_outstanding &&
7893           !netplay->nat_traversal_state.have_inet4)
7894       {
7895          struct timeval tmptv = {0};
7896          fd_set fds = netplay->nat_traversal_state.fds;
7897          if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0)
7898             natt_read(&netplay->nat_traversal_state);
7899 
7900 #ifndef HAVE_SOCKET_LEGACY
7901          if (!netplay->nat_traversal_state.request_outstanding ||
7902              netplay->nat_traversal_state.have_inet4)
7903             netplay_announce_nat_traversal(netplay);
7904 #endif
7905       }
7906    }
7907 
7908    sync_stalled = !netplay_sync_pre_frame(netplay);
7909 
7910    /* If we're disconnected, deinitialize */
7911    if (!netplay->is_server && !netplay->connections[0].active)
7912    {
7913       netplay_disconnect(p_rarch, netplay);
7914       return true;
7915    }
7916 
7917    if (sync_stalled ||
7918        ((!netplay->is_server || (netplay->connected_players>1)) &&
7919         (netplay->stall || netplay->remote_paused)))
7920    {
7921       /* We may have received data even if we're stalled, so run post-frame
7922        * sync */
7923       netplay_sync_post_frame(netplay, true);
7924       return false;
7925    }
7926    return true;
7927 }
7928 
7929 /**
7930  * netplay_post_frame:
7931  * @netplay              : pointer to netplay object
7932  *
7933  * Post-frame for Netplay.
7934  * We check if we have new input and replay from recorded input.
7935  * Call this after running retro_run().
7936  **/
netplay_post_frame(struct rarch_state * p_rarch,netplay_t * netplay)7937 static void netplay_post_frame(
7938       struct rarch_state *p_rarch,
7939       netplay_t *netplay)
7940 {
7941    size_t i;
7942    retro_assert(netplay);
7943    netplay_update_unread_ptr(netplay);
7944    netplay_sync_post_frame(netplay, false);
7945 
7946    for (i = 0; i < netplay->connections_size; i++)
7947    {
7948       struct netplay_connection *connection = &netplay->connections[i];
7949       if (connection->active &&
7950           !netplay_send_flush(&connection->send_packet_buffer, connection->fd,
7951             false))
7952          netplay_hangup(netplay, connection);
7953    }
7954 
7955    /* If we're disconnected, deinitialize */
7956    if (!netplay->is_server && !netplay->connections[0].active)
7957       netplay_disconnect(p_rarch, netplay);
7958 }
7959 
7960 /**
7961  * netplay_force_future
7962  * @netplay              : pointer to netplay object
7963  *
7964  * Force netplay to ignore all past input, typically because we've just loaded
7965  * a state or reset.
7966  */
netplay_force_future(netplay_t * netplay)7967 static void netplay_force_future(netplay_t *netplay)
7968 {
7969    /* Wherever we're inputting, that's where we consider our state to be loaded */
7970    netplay->run_ptr         = netplay->self_ptr;
7971    netplay->run_frame_count = netplay->self_frame_count;
7972 
7973    /* We need to ignore any intervening data from the other side,
7974     * and never rewind past this */
7975    netplay_update_unread_ptr(netplay);
7976 
7977    if (netplay->unread_frame_count < netplay->run_frame_count)
7978    {
7979       uint32_t client;
7980       for (client = 0; client < MAX_CLIENTS; client++)
7981       {
7982          if (!(netplay->connected_players & (1 << client)))
7983             continue;
7984 
7985          if (netplay->read_frame_count[client] < netplay->run_frame_count)
7986          {
7987             netplay->read_ptr[client] = netplay->run_ptr;
7988             netplay->read_frame_count[client] = netplay->run_frame_count;
7989          }
7990       }
7991       if (netplay->server_frame_count < netplay->run_frame_count)
7992       {
7993          netplay->server_ptr = netplay->run_ptr;
7994          netplay->server_frame_count = netplay->run_frame_count;
7995       }
7996       netplay_update_unread_ptr(netplay);
7997    }
7998    if (netplay->other_frame_count < netplay->run_frame_count)
7999    {
8000       netplay->other_ptr = netplay->run_ptr;
8001       netplay->other_frame_count = netplay->run_frame_count;
8002    }
8003 }
8004 
8005 /**
8006  * netplay_send_savestate
8007  * @netplay              : pointer to netplay object
8008  * @serial_info          : the savestate being loaded
8009  * @cx                   : compression type
8010  * @z                    : compression backend to use
8011  *
8012  * Send a loaded savestate to those connected peers using the given compression
8013  * scheme.
8014  */
netplay_send_savestate(netplay_t * netplay,retro_ctx_serialize_info_t * serial_info,uint32_t cx,struct compression_transcoder * z)8015 static void netplay_send_savestate(netplay_t *netplay,
8016    retro_ctx_serialize_info_t *serial_info, uint32_t cx,
8017    struct compression_transcoder *z)
8018 {
8019    uint32_t header[4];
8020    uint32_t rd, wn;
8021    size_t i;
8022 
8023    /* Compress it */
8024    z->compression_backend->set_in(z->compression_stream,
8025       (const uint8_t*)serial_info->data_const, (uint32_t)serial_info->size);
8026    z->compression_backend->set_out(z->compression_stream,
8027       netplay->zbuffer, (uint32_t)netplay->zbuffer_size);
8028    if (!z->compression_backend->trans(z->compression_stream, true, &rd,
8029          &wn, NULL))
8030    {
8031       /* Catastrophe! */
8032       for (i = 0; i < netplay->connections_size; i++)
8033          netplay_hangup(netplay, &netplay->connections[i]);
8034       return;
8035    }
8036 
8037    /* Send it to relevant peers */
8038    header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE);
8039    header[1] = htonl(wn + 2*sizeof(uint32_t));
8040    header[2] = htonl(netplay->run_frame_count);
8041    header[3] = htonl(serial_info->size);
8042 
8043    for (i = 0; i < netplay->connections_size; i++)
8044    {
8045       struct netplay_connection *connection = &netplay->connections[i];
8046       if (!connection->active ||
8047           connection->mode < NETPLAY_CONNECTION_CONNECTED ||
8048           connection->compression_supported != cx) continue;
8049 
8050       if (!netplay_send(&connection->send_packet_buffer, connection->fd, header,
8051             sizeof(header)) ||
8052           !netplay_send(&connection->send_packet_buffer, connection->fd,
8053             netplay->zbuffer, wn))
8054          netplay_hangup(netplay, connection);
8055    }
8056 }
8057 
8058 /**
8059  * netplay_load_savestate
8060  * @netplay              : pointer to netplay object
8061  * @serial_info          : the savestate being loaded, NULL means
8062  *                         "load it yourself"
8063  * @save                 : Whether to save the provided serial_info
8064  *                         into the frame buffer
8065  *
8066  * Inform Netplay of a savestate load and send it to the other side
8067  **/
netplay_load_savestate(netplay_t * netplay,retro_ctx_serialize_info_t * serial_info,bool save)8068 void netplay_load_savestate(netplay_t *netplay,
8069       retro_ctx_serialize_info_t *serial_info, bool save)
8070 {
8071    retro_ctx_serialize_info_t tmp_serial_info;
8072 
8073    netplay_force_future(netplay);
8074 
8075    /* Record it in our own buffer */
8076    if (save || !serial_info)
8077    {
8078       /* TODO/FIXME: This is a critical failure! */
8079       if (!netplay_delta_frame_ready(netplay,
8080                &netplay->buffer[netplay->run_ptr], netplay->run_frame_count))
8081          return;
8082 
8083       if (!serial_info)
8084       {
8085          tmp_serial_info.size = netplay->state_size;
8086          tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
8087          if (!core_serialize(&tmp_serial_info))
8088             return;
8089          tmp_serial_info.data_const = tmp_serial_info.data;
8090          serial_info = &tmp_serial_info;
8091       }
8092       else
8093       {
8094          if (serial_info->size <= netplay->state_size)
8095             memcpy(netplay->buffer[netplay->run_ptr].state,
8096                   serial_info->data_const, serial_info->size);
8097       }
8098    }
8099 
8100    /* Don't send it if we're expected to be desynced */
8101    if (netplay->desync)
8102       return;
8103 
8104    /* If we can't send it to the peer, loading a state was a bad idea */
8105    if (netplay->quirks & (
8106               NETPLAY_QUIRK_NO_SAVESTATES
8107             | NETPLAY_QUIRK_NO_TRANSMISSION))
8108       return;
8109 
8110    /* Send this to every peer */
8111    if (netplay->compress_nil.compression_backend)
8112       netplay_send_savestate(netplay, serial_info, 0, &netplay->compress_nil);
8113    if (netplay->compress_zlib.compression_backend)
8114       netplay_send_savestate(netplay, serial_info, NETPLAY_COMPRESSION_ZLIB,
8115          &netplay->compress_zlib);
8116 }
8117 
8118 /**
8119  * netplay_core_reset
8120  * @netplay              : pointer to netplay object
8121  *
8122  * Indicate that the core has been reset to netplay peers
8123  **/
netplay_core_reset(netplay_t * netplay)8124 static void netplay_core_reset(netplay_t *netplay)
8125 {
8126    size_t i;
8127    uint32_t cmd[3];
8128 
8129    /* Ignore past input */
8130    netplay_force_future(netplay);
8131 
8132    /* Request that our peers reset */
8133    cmd[0] = htonl(NETPLAY_CMD_RESET);
8134    cmd[1] = htonl(sizeof(uint32_t));
8135    cmd[2] = htonl(netplay->self_frame_count);
8136 
8137    for (i = 0; i < netplay->connections_size; i++)
8138    {
8139       struct netplay_connection *connection = &netplay->connections[i];
8140       if (!connection->active ||
8141             connection->mode < NETPLAY_CONNECTION_CONNECTED) continue;
8142 
8143       if (!netplay_send(&connection->send_packet_buffer, connection->fd, cmd,
8144                sizeof(cmd)))
8145          netplay_hangup(netplay, connection);
8146    }
8147 }
8148 
8149 /**
8150  * netplay_toggle_play_spectate
8151  *
8152  * Toggle between play mode and spectate mode
8153  */
netplay_toggle_play_spectate(netplay_t * netplay)8154 static void netplay_toggle_play_spectate(netplay_t *netplay)
8155 {
8156    switch (netplay->self_mode)
8157    {
8158       case NETPLAY_CONNECTION_PLAYING:
8159       case NETPLAY_CONNECTION_SLAVE:
8160          /* Switch to spectator mode immediately */
8161          netplay->self_mode = NETPLAY_CONNECTION_SPECTATING;
8162          netplay_cmd_mode(netplay, NETPLAY_CONNECTION_SPECTATING);
8163          break;
8164       case NETPLAY_CONNECTION_SPECTATING:
8165          /* Switch only after getting permission */
8166          netplay_cmd_mode(netplay, NETPLAY_CONNECTION_PLAYING);
8167          break;
8168       default:
8169          break;
8170    }
8171 }
8172 
deinit_netplay(struct rarch_state * p_rarch)8173 static void deinit_netplay(struct rarch_state *p_rarch)
8174 {
8175    if (p_rarch->netplay_data)
8176    {
8177       netplay_free(p_rarch->netplay_data);
8178       p_rarch->netplay_enabled   = false;
8179       p_rarch->netplay_is_client = false;
8180       p_rarch->is_mitm           = false;
8181    }
8182    p_rarch->netplay_data         = NULL;
8183    core_unset_netplay_callbacks();
8184 }
8185 
8186 /**
8187  * init_netplay
8188  * @direct_host          : Host to connect to directly, if applicable (client only)
8189  * @server               : server address to connect to (client only)
8190  * @port                 : TCP port to host on/connect to
8191  *
8192  * Initializes netplay.
8193  *
8194  * If netplay is already initialized, will return false (0).
8195  *
8196  * Returns: true (1) if successful, otherwise false (0).
8197  **/
init_netplay(struct rarch_state * p_rarch,settings_t * settings,void * direct_host,const char * server,unsigned port)8198 static bool init_netplay(
8199       struct rarch_state *p_rarch,
8200       settings_t *settings,
8201       void *direct_host,
8202       const char *server, unsigned port)
8203 {
8204    struct retro_callbacks cbs    = {0};
8205    uint64_t serialization_quirks = 0;
8206    uint64_t quirks               = 0;
8207    bool _netplay_is_client       = p_rarch->netplay_is_client;
8208    bool _netplay_enabled         = p_rarch->netplay_enabled;
8209 
8210    if (!_netplay_enabled)
8211       return false;
8212 
8213    core_set_default_callbacks(&cbs);
8214    if (!core_set_netplay_callbacks())
8215       return false;
8216 
8217    /* Map the core's quirks to our quirks */
8218    serialization_quirks = core_serialization_quirks();
8219 
8220    /* Quirks we don't support! Just disable everything. */
8221    if (serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))
8222       quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
8223 
8224    if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES)
8225       quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
8226    if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION)
8227       quirks |= NETPLAY_QUIRK_NO_TRANSMISSION;
8228    if (serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)
8229       quirks |= NETPLAY_QUIRK_INITIALIZATION;
8230    if (serialization_quirks & NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT)
8231       quirks |= NETPLAY_QUIRK_ENDIAN_DEPENDENT;
8232    if (serialization_quirks & NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT)
8233       quirks |= NETPLAY_QUIRK_PLATFORM_DEPENDENT;
8234 
8235    if (_netplay_is_client)
8236    {
8237       RARCH_LOG("[Netplay]: %s\n", msg_hash_to_str(MSG_CONNECTING_TO_NETPLAY_HOST));
8238    }
8239    else
8240    {
8241       RARCH_LOG("[Netplay]: %s\n", msg_hash_to_str(MSG_WAITING_FOR_CLIENT));
8242       runloop_msg_queue_push(
8243          msg_hash_to_str(MSG_WAITING_FOR_CLIENT),
8244          0, 180, false,
8245          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
8246 
8247       if (settings->bools.netplay_public_announce)
8248          netplay_announce(p_rarch);
8249    }
8250 
8251    p_rarch->netplay_data = (netplay_t*)netplay_new(
8252          _netplay_is_client
8253          ? direct_host
8254          : NULL,
8255          _netplay_is_client
8256          ? (!p_rarch->netplay_client_deferred
8257             ? server
8258             : p_rarch->server_address_deferred)
8259             : NULL,
8260          _netplay_is_client ? (!p_rarch->netplay_client_deferred
8261             ? port
8262             : p_rarch->server_port_deferred)
8263             : (port != 0 ? port : RARCH_DEFAULT_PORT),
8264          settings->bools.netplay_stateless_mode,
8265          settings->ints.netplay_check_frames,
8266          &cbs,
8267          settings->bools.netplay_nat_traversal && !settings->bools.netplay_use_mitm_server,
8268 #ifdef HAVE_DISCORD
8269          discord_get_own_username(p_rarch)
8270          ? discord_get_own_username(p_rarch)
8271          :
8272 #endif
8273          settings->paths.username,
8274          quirks);
8275 
8276    if (p_rarch->netplay_data)
8277    {
8278       if (      p_rarch->netplay_data->is_server
8279             && !settings->bools.netplay_start_as_spectator)
8280          netplay_toggle_play_spectate(p_rarch->netplay_data);
8281       return true;
8282    }
8283 
8284    RARCH_WARN("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED));
8285 
8286    runloop_msg_queue_push(
8287          msg_hash_to_str(MSG_NETPLAY_FAILED),
8288          0, 180, false,
8289          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
8290    return false;
8291 }
8292 
8293 /**
8294  * netplay_driver_ctl
8295  *
8296  * Frontend access to Netplay functionality
8297  */
netplay_driver_ctl(enum rarch_netplay_ctl_state state,void * data)8298 bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data)
8299 {
8300    struct rarch_state *p_rarch = &rarch_st;
8301    netplay_t *netplay          = p_rarch->netplay_data;
8302    bool ret                    = true;
8303 
8304    if (p_rarch->in_netplay)
8305       return true;
8306    p_rarch->in_netplay         = true;
8307 
8308    if (!netplay)
8309    {
8310       switch (state)
8311       {
8312          case RARCH_NETPLAY_CTL_ENABLE_SERVER:
8313             p_rarch->netplay_enabled    = true;
8314             p_rarch->netplay_is_client  = false;
8315             goto done;
8316 
8317          case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
8318             p_rarch->netplay_enabled    = true;
8319             p_rarch->netplay_is_client  = true;
8320             break;
8321 
8322          case RARCH_NETPLAY_CTL_DISABLE:
8323             p_rarch->netplay_enabled    = false;
8324 #ifdef HAVE_DISCORD
8325             if (discord_is_inited)
8326             {
8327                discord_userdata_t userdata;
8328                userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
8329                command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
8330             }
8331 #endif
8332             goto done;
8333 
8334          case RARCH_NETPLAY_CTL_IS_ENABLED:
8335             ret = p_rarch->netplay_enabled;
8336             goto done;
8337 
8338          case RARCH_NETPLAY_CTL_IS_REPLAYING:
8339          case RARCH_NETPLAY_CTL_IS_DATA_INITED:
8340             ret = false;
8341             goto done;
8342 
8343          case RARCH_NETPLAY_CTL_IS_SERVER:
8344             ret =  p_rarch->netplay_enabled
8345                && !p_rarch->netplay_is_client;
8346             goto done;
8347 
8348          case RARCH_NETPLAY_CTL_IS_CONNECTED:
8349             ret = false;
8350             goto done;
8351 
8352          default:
8353             goto done;
8354       }
8355    }
8356 
8357    switch (state)
8358    {
8359       case RARCH_NETPLAY_CTL_ENABLE_SERVER:
8360       case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
8361       case RARCH_NETPLAY_CTL_IS_DATA_INITED:
8362          goto done;
8363       case RARCH_NETPLAY_CTL_DISABLE:
8364          ret = false;
8365          goto done;
8366       case RARCH_NETPLAY_CTL_IS_ENABLED:
8367          goto done;
8368       case RARCH_NETPLAY_CTL_IS_REPLAYING:
8369          ret = netplay->is_replay;
8370          goto done;
8371       case RARCH_NETPLAY_CTL_IS_SERVER:
8372          ret =  p_rarch->netplay_enabled
8373             && !p_rarch->netplay_is_client;
8374          goto done;
8375       case RARCH_NETPLAY_CTL_IS_CONNECTED:
8376          ret = netplay->is_connected;
8377          goto done;
8378       case RARCH_NETPLAY_CTL_POST_FRAME:
8379          netplay_post_frame(p_rarch, netplay);
8380          break;
8381       case RARCH_NETPLAY_CTL_PRE_FRAME:
8382          ret = netplay_pre_frame(p_rarch,
8383                p_rarch->configuration_settings->bools.netplay_public_announce,
8384                p_rarch->configuration_settings->bools.netplay_use_mitm_server,
8385                netplay);
8386          goto done;
8387       case RARCH_NETPLAY_CTL_GAME_WATCH:
8388          netplay_toggle_play_spectate(netplay);
8389          break;
8390       case RARCH_NETPLAY_CTL_PAUSE:
8391          if (netplay->local_paused != true)
8392             netplay_frontend_paused(netplay, true);
8393          break;
8394       case RARCH_NETPLAY_CTL_UNPAUSE:
8395          if (netplay->local_paused != false)
8396             netplay_frontend_paused(netplay, false);
8397          break;
8398       case RARCH_NETPLAY_CTL_LOAD_SAVESTATE:
8399          netplay_load_savestate(netplay, (retro_ctx_serialize_info_t*)data, true);
8400          break;
8401       case RARCH_NETPLAY_CTL_RESET:
8402          netplay_core_reset(netplay);
8403          break;
8404       case RARCH_NETPLAY_CTL_DISCONNECT:
8405          ret    = true;
8406          if (netplay)
8407             netplay_disconnect(p_rarch, netplay);
8408          goto done;
8409       case RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL:
8410          netplay->nat_traversal_task_oustanding = false;
8411 #ifndef HAVE_SOCKET_LEGACY
8412          netplay_announce_nat_traversal(netplay);
8413 #endif
8414          goto done;
8415       case RARCH_NETPLAY_CTL_DESYNC_PUSH:
8416          netplay->desync++;
8417          break;
8418       case RARCH_NETPLAY_CTL_DESYNC_POP:
8419          if (netplay->desync)
8420          {
8421             netplay->desync--;
8422             if (!netplay->desync)
8423                netplay_load_savestate(netplay, NULL, true);
8424          }
8425          break;
8426       default:
8427       case RARCH_NETPLAY_CTL_NONE:
8428          ret = false;
8429    }
8430 
8431 done:
8432    p_rarch->in_netplay = false;
8433    return ret;
8434 }
8435 #endif
8436 
log_counters(struct retro_perf_counter ** counters,unsigned num)8437 static void log_counters(
8438       struct retro_perf_counter **counters, unsigned num)
8439 {
8440    unsigned i;
8441    for (i = 0; i < num; i++)
8442    {
8443       if (counters[i]->call_cnt)
8444       {
8445          RARCH_LOG(PERF_LOG_FMT,
8446                counters[i]->ident,
8447                (uint64_t)counters[i]->total /
8448                (uint64_t)counters[i]->call_cnt,
8449                (uint64_t)counters[i]->call_cnt);
8450       }
8451    }
8452 }
8453 
retro_perf_log(void)8454 static void retro_perf_log(void)
8455 {
8456    struct rarch_state *p_rarch = &rarch_st;
8457    RARCH_LOG("[PERF]: Performance counters (libretro):\n");
8458    log_counters(p_rarch->perf_counters_libretro, p_rarch->perf_ptr_libretro);
8459 }
8460 
retro_get_perf_counter_rarch(void)8461 struct retro_perf_counter **retro_get_perf_counter_rarch(void)
8462 {
8463    struct rarch_state *p_rarch = &rarch_st;
8464    return p_rarch->perf_counters_rarch;
8465 }
8466 
retro_get_perf_counter_libretro(void)8467 struct retro_perf_counter **retro_get_perf_counter_libretro(void)
8468 {
8469    struct rarch_state *p_rarch = &rarch_st;
8470    return p_rarch->perf_counters_libretro;
8471 }
8472 
retro_get_perf_count_rarch(void)8473 unsigned retro_get_perf_count_rarch(void)
8474 {
8475    struct rarch_state *p_rarch = &rarch_st;
8476    return p_rarch->perf_ptr_rarch;
8477 }
8478 
retro_get_perf_count_libretro(void)8479 unsigned retro_get_perf_count_libretro(void)
8480 {
8481    struct rarch_state *p_rarch = &rarch_st;
8482    return p_rarch->perf_ptr_libretro;
8483 }
8484 
rarch_perf_register(struct retro_perf_counter * perf)8485 void rarch_perf_register(struct retro_perf_counter *perf)
8486 {
8487    struct rarch_state *p_rarch = &rarch_st;
8488    if (
8489             !runloop_state.perfcnt_enable
8490          || perf->registered
8491          || p_rarch->perf_ptr_rarch >= MAX_COUNTERS
8492       )
8493       return;
8494 
8495    p_rarch->perf_counters_rarch[p_rarch->perf_ptr_rarch++] = perf;
8496    perf->registered = true;
8497 }
8498 
performance_counter_register(struct retro_perf_counter * perf)8499 static void performance_counter_register(struct retro_perf_counter *perf)
8500 {
8501    struct rarch_state *p_rarch = &rarch_st;
8502    if (perf->registered || p_rarch->perf_ptr_libretro >= MAX_COUNTERS)
8503       return;
8504 
8505    p_rarch->perf_counters_libretro[p_rarch->perf_ptr_libretro++] = perf;
8506    perf->registered = true;
8507 }
8508 
dir_list_new_special(const char * input_dir,enum dir_list_type type,const char * filter,bool show_hidden_files)8509 struct string_list *dir_list_new_special(const char *input_dir,
8510       enum dir_list_type type, const char *filter,
8511       bool show_hidden_files)
8512 {
8513 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
8514    char ext_shaders[255];
8515 #endif
8516    char ext_name[255];
8517    const char *exts                  = NULL;
8518    bool recursive                    = false;
8519 
8520    switch (type)
8521    {
8522       case DIR_LIST_AUTOCONFIG:
8523          exts = filter;
8524          break;
8525       case DIR_LIST_CORES:
8526          ext_name[0]         = '\0';
8527 
8528          if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
8529             return NULL;
8530 
8531          exts = ext_name;
8532          break;
8533       case DIR_LIST_RECURSIVE:
8534          recursive = true;
8535          /* fall-through */
8536       case DIR_LIST_CORE_INFO:
8537          {
8538             core_info_list_t *list = NULL;
8539             core_info_get_list(&list);
8540 
8541             if (list)
8542                exts = list->all_ext;
8543          }
8544          break;
8545       case DIR_LIST_SHADERS:
8546 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
8547          {
8548             union string_list_elem_attr attr;
8549             struct string_list str_list;
8550 
8551             if (!string_list_initialize(&str_list))
8552                return NULL;
8553 
8554             ext_shaders[0]                   = '\0';
8555 
8556             attr.i = 0;
8557 
8558             if (video_shader_is_supported(RARCH_SHADER_CG))
8559             {
8560                string_list_append(&str_list, "cgp", attr);
8561                string_list_append(&str_list, "cg", attr);
8562             }
8563 
8564             if (video_shader_is_supported(RARCH_SHADER_GLSL))
8565             {
8566                string_list_append(&str_list, "glslp", attr);
8567                string_list_append(&str_list, "glsl", attr);
8568             }
8569 
8570             if (video_shader_is_supported(RARCH_SHADER_SLANG))
8571             {
8572                string_list_append(&str_list, "slangp", attr);
8573                string_list_append(&str_list, "slang", attr);
8574             }
8575 
8576             string_list_join_concat(ext_shaders, sizeof(ext_shaders), &str_list, "|");
8577             string_list_deinitialize(&str_list);
8578             exts = ext_shaders;
8579          }
8580          break;
8581 #else
8582          return NULL;
8583 #endif
8584       case DIR_LIST_COLLECTIONS:
8585          exts = "lpl";
8586          break;
8587       case DIR_LIST_DATABASES:
8588          exts = "rdb";
8589          break;
8590       case DIR_LIST_PLAIN:
8591          exts = filter;
8592          break;
8593       case DIR_LIST_NONE:
8594       default:
8595          return NULL;
8596    }
8597 
8598    return dir_list_new(input_dir, exts, false,
8599          show_hidden_files,
8600          type == DIR_LIST_CORE_INFO, recursive);
8601 }
8602 
string_list_new_special(enum string_list_type type,void * data,unsigned * len,size_t * list_size)8603 struct string_list *string_list_new_special(enum string_list_type type,
8604       void *data, unsigned *len, size_t *list_size)
8605 {
8606    union string_list_elem_attr attr;
8607    unsigned i;
8608    struct string_list *s = string_list_new();
8609 
8610    if (!s || !len)
8611       goto error;
8612 
8613    attr.i = 0;
8614    *len   = 0;
8615 
8616    switch (type)
8617    {
8618       case STRING_LIST_MENU_DRIVERS:
8619 #ifdef HAVE_MENU
8620          for (i = 0; menu_ctx_drivers[i]; i++)
8621          {
8622             const char *opt  = menu_ctx_drivers[i]->ident;
8623             *len            += strlen(opt) + 1;
8624 
8625             /* Don't allow the user to set menu driver to "null" using the UI.
8626              * Can prevent the user from locking him/herself out of the program. */
8627             if (string_is_not_equal(opt, "null"))
8628                string_list_append(s, opt, attr);
8629          }
8630          break;
8631 #endif
8632       case STRING_LIST_CAMERA_DRIVERS:
8633          for (i = 0; camera_drivers[i]; i++)
8634          {
8635             const char *opt  = camera_drivers[i]->ident;
8636             *len            += strlen(opt) + 1;
8637 
8638             string_list_append(s, opt, attr);
8639          }
8640          break;
8641       case STRING_LIST_BLUETOOTH_DRIVERS:
8642 #ifdef HAVE_BLUETOOTH
8643          for (i = 0; bluetooth_drivers[i]; i++)
8644          {
8645             const char *opt  = bluetooth_drivers[i]->ident;
8646             *len            += strlen(opt) + 1;
8647 
8648             string_list_append(s, opt, attr);
8649          }
8650          break;
8651 #endif
8652       case STRING_LIST_WIFI_DRIVERS:
8653 #ifdef HAVE_WIFI
8654          for (i = 0; wifi_drivers[i]; i++)
8655          {
8656             const char *opt  = wifi_drivers[i]->ident;
8657             *len            += strlen(opt) + 1;
8658 
8659             string_list_append(s, opt, attr);
8660          }
8661          break;
8662 #endif
8663       case STRING_LIST_LOCATION_DRIVERS:
8664          for (i = 0; location_drivers[i]; i++)
8665          {
8666             const char *opt  = location_drivers[i]->ident;
8667             *len            += strlen(opt) + 1;
8668 
8669             string_list_append(s, opt, attr);
8670          }
8671          break;
8672       case STRING_LIST_AUDIO_DRIVERS:
8673          for (i = 0; audio_drivers[i]; i++)
8674          {
8675             const char *opt  = audio_drivers[i]->ident;
8676             *len            += strlen(opt) + 1;
8677 
8678             string_list_append(s, opt, attr);
8679          }
8680          break;
8681       case STRING_LIST_AUDIO_RESAMPLER_DRIVERS:
8682          for (i = 0; audio_resampler_driver_find_handle(i); i++)
8683          {
8684             const char *opt  = audio_resampler_driver_find_ident(i);
8685             *len            += strlen(opt) + 1;
8686 
8687             string_list_append(s, opt, attr);
8688          }
8689          break;
8690       case STRING_LIST_VIDEO_DRIVERS:
8691          for (i = 0; video_drivers[i]; i++)
8692          {
8693             const char *opt  = video_drivers[i]->ident;
8694             *len            += strlen(opt) + 1;
8695 
8696             /* Don't allow the user to set video driver to "null" using the UI.
8697              * Can prevent the user from locking him/herself out of the program. */
8698             if (string_is_not_equal(opt, "null"))
8699                string_list_append(s, opt, attr);
8700          }
8701          break;
8702       case STRING_LIST_INPUT_DRIVERS:
8703          for (i = 0; input_drivers[i]; i++)
8704          {
8705             const char *opt  = input_drivers[i]->ident;
8706             *len            += strlen(opt) + 1;
8707 
8708             /* Don't allow the user to set input driver to "null" using the UI.
8709              * Can prevent the user from locking him/herself out of the program. */
8710             if (string_is_not_equal(opt, "null"))
8711                string_list_append(s, opt, attr);
8712          }
8713          break;
8714       case STRING_LIST_INPUT_HID_DRIVERS:
8715 #ifdef HAVE_HID
8716          for (i = 0; hid_drivers[i]; i++)
8717          {
8718             const char *opt  = hid_drivers[i]->ident;
8719             *len            += strlen(opt) + 1;
8720 
8721             /* Don't allow the user to set input HID driver to "null" using the UI.
8722              * Can prevent the user from locking him/herself out of the program. */
8723             if (string_is_not_equal(opt, "null"))
8724                string_list_append(s, opt, attr);
8725          }
8726 #endif
8727          break;
8728       case STRING_LIST_INPUT_JOYPAD_DRIVERS:
8729          for (i = 0; joypad_drivers[i]; i++)
8730          {
8731             const char *opt  = joypad_drivers[i]->ident;
8732             *len            += strlen(opt) + 1;
8733 
8734             /* Don't allow the user to set input joypad driver to "null" using the UI.
8735              * Can prevent the user from locking him/herself out of the program. */
8736             if (string_is_not_equal(opt, "null"))
8737                string_list_append(s, opt, attr);
8738          }
8739          break;
8740       case STRING_LIST_RECORD_DRIVERS:
8741          for (i = 0; record_drivers[i]; i++)
8742          {
8743             const char *opt  = record_drivers[i]->ident;
8744             *len            += strlen(opt) + 1;
8745 
8746             string_list_append(s, opt, attr);
8747          }
8748          break;
8749       case STRING_LIST_MIDI_DRIVERS:
8750          for (i = 0; midi_driver_find_handle(i); i++)
8751          {
8752             const char *opt  = midi_drivers[i]->ident;
8753             *len            += strlen(opt) + 1;
8754 
8755             string_list_append(s, opt, attr);
8756          }
8757          break;
8758 #ifdef HAVE_LAKKA
8759       case STRING_LIST_TIMEZONES:
8760          {
8761             const char *opt  = DEFAULT_TIMEZONE;
8762             *len            += strlen(opt) + 1;
8763             string_list_append(s, opt, attr);
8764 
8765             FILE *zones_file = popen("grep -v ^# /usr/share/zoneinfo/zone.tab | "
8766                                      "cut -f3 | "
8767                                      "sort", "r");
8768 
8769             if (zones_file != NULL)
8770             {
8771                char zone_desc[TIMEZONE_LENGTH];
8772                while (fgets(zone_desc, TIMEZONE_LENGTH, zones_file))
8773                {
8774                   size_t zone_desc_len = strlen(zone_desc);
8775 
8776                   if (zone_desc_len > 0)
8777                      if (zone_desc[--zone_desc_len] == '\n')
8778                         zone_desc[zone_desc_len] = '\0';
8779 
8780                   if (strlen(zone_desc) > 0)
8781                   {
8782                      const char *opt  = zone_desc;
8783                      *len            += strlen(opt) + 1;
8784                      string_list_append(s, opt, attr);
8785                   }
8786                }
8787                pclose(zones_file);
8788             }
8789          }
8790          break;
8791 #endif
8792       case STRING_LIST_NONE:
8793       default:
8794          goto error;
8795    }
8796 
8797    return s;
8798 
8799 error:
8800    string_list_free(s);
8801    s    = NULL;
8802    return NULL;
8803 }
8804 
char_list_new_special(enum string_list_type type,void * data)8805 const char *char_list_new_special(enum string_list_type type, void *data)
8806 {
8807    unsigned len = 0;
8808    size_t list_size;
8809    struct string_list *s = string_list_new_special(type, data, &len, &list_size);
8810    char         *options = (len > 0) ? (char*)calloc(len, sizeof(char)): NULL;
8811 
8812    if (options && s)
8813       string_list_join_concat(options, len, s, "|");
8814 
8815    string_list_free(s);
8816    s = NULL;
8817 
8818    return options;
8819 }
8820 
path_set_redirect(struct rarch_state * p_rarch,settings_t * settings)8821 static void path_set_redirect(struct rarch_state *p_rarch,
8822       settings_t *settings)
8823 {
8824    char content_dir_name[PATH_MAX_LENGTH];
8825    char new_savefile_dir[PATH_MAX_LENGTH];
8826    char new_savestate_dir[PATH_MAX_LENGTH];
8827    global_t   *global                          = &p_rarch->g_extern;
8828    const char *old_savefile_dir                = p_rarch->dir_savefile;
8829    const char *old_savestate_dir               = p_rarch->dir_savestate;
8830    struct retro_system_info *system            = &runloop_state.system.info;
8831    bool sort_savefiles_enable                  = settings->bools.sort_savefiles_enable;
8832    bool sort_savefiles_by_content_enable       = settings->bools.sort_savefiles_by_content_enable;
8833    bool sort_savestates_enable                 = settings->bools.sort_savestates_enable;
8834    bool sort_savestates_by_content_enable      = settings->bools.sort_savestates_by_content_enable;
8835    bool savefiles_in_content_dir               = settings->bools.savefiles_in_content_dir;
8836    bool savestates_in_content_dir              = settings->bools.savestates_in_content_dir;
8837 
8838    content_dir_name[0]  = '\0';
8839    new_savefile_dir[0]  = '\0';
8840    new_savestate_dir[0] = '\0';
8841 
8842    /* Initialize current save directories
8843     * with the values from the config. */
8844    strlcpy(new_savefile_dir,  old_savefile_dir,  sizeof(new_savefile_dir));
8845    strlcpy(new_savestate_dir, old_savestate_dir, sizeof(new_savestate_dir));
8846 
8847    /* Get content directory name, if per-content-directory
8848     * saves/states are enabled */
8849    if ((sort_savefiles_by_content_enable ||
8850          sort_savestates_by_content_enable) &&
8851        !string_is_empty(p_rarch->path_main_basename))
8852       fill_pathname_parent_dir_name(content_dir_name,
8853             p_rarch->path_main_basename, sizeof(content_dir_name));
8854 
8855    if (system && !string_is_empty(system->library_name))
8856    {
8857 #ifdef HAVE_MENU
8858       if (!string_is_equal(system->library_name,
8859                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE)))
8860 #endif
8861       {
8862          /* Per-core and/or per-content-directory saves */
8863          if ((sort_savefiles_enable || sort_savefiles_by_content_enable)
8864                && !string_is_empty(old_savefile_dir))
8865          {
8866             /* Append content directory name to save location */
8867             if (sort_savefiles_by_content_enable)
8868                fill_pathname_join(
8869                      new_savefile_dir,
8870                      old_savefile_dir,
8871                      content_dir_name,
8872                      sizeof(new_savefile_dir));
8873 
8874             /* Append library_name to the save location */
8875             if (sort_savefiles_enable)
8876                fill_pathname_join(
8877                      new_savefile_dir,
8878                      new_savefile_dir,
8879                      system->library_name,
8880                      sizeof(new_savefile_dir));
8881 
8882             /* If path doesn't exist, try to create it,
8883              * if everything fails revert to the original path. */
8884             if (!path_is_directory(new_savefile_dir))
8885                if (!path_mkdir(new_savefile_dir))
8886                {
8887                   RARCH_LOG("%s %s\n",
8888                         msg_hash_to_str(MSG_REVERTING_SAVEFILE_DIRECTORY_TO),
8889                         old_savefile_dir);
8890 
8891                   strlcpy(new_savefile_dir, old_savefile_dir, sizeof(new_savefile_dir));
8892                }
8893          }
8894 
8895          /* Per-core and/or per-content-directory savestates */
8896          if ((sort_savestates_enable || sort_savestates_by_content_enable)
8897                && !string_is_empty(old_savestate_dir))
8898          {
8899             /* Append content directory name to savestate location */
8900             if (sort_savestates_by_content_enable)
8901                fill_pathname_join(
8902                      new_savestate_dir,
8903                      old_savestate_dir,
8904                      content_dir_name,
8905                      sizeof(new_savestate_dir));
8906 
8907             /* Append library_name to the savestate location */
8908             if (sort_savestates_enable)
8909             {
8910                fill_pathname_join(
8911                      new_savestate_dir,
8912                      new_savestate_dir,
8913                      system->library_name,
8914                      sizeof(new_savestate_dir));
8915             }
8916 
8917             /* If path doesn't exist, try to create it.
8918              * If everything fails, revert to the original path. */
8919             if (!path_is_directory(new_savestate_dir))
8920                if (!path_mkdir(new_savestate_dir))
8921                {
8922                   RARCH_LOG("%s %s\n",
8923                         msg_hash_to_str(MSG_REVERTING_SAVESTATE_DIRECTORY_TO),
8924                         old_savestate_dir);
8925                   strlcpy(new_savestate_dir,
8926                         old_savestate_dir,
8927                         sizeof(new_savestate_dir));
8928                }
8929          }
8930       }
8931    }
8932 
8933    /* Set savefile directory if empty to content directory */
8934    if (string_is_empty(new_savefile_dir) || savefiles_in_content_dir)
8935    {
8936       strlcpy(new_savefile_dir, p_rarch->path_main_basename,
8937             sizeof(new_savefile_dir));
8938       path_basedir(new_savefile_dir);
8939 
8940       if (string_is_empty(new_savefile_dir))
8941          RARCH_LOG("Cannot resolve save file path.\n",
8942             msg_hash_to_str(MSG_REVERTING_SAVEFILE_DIRECTORY_TO),
8943             new_savefile_dir);
8944       else if (sort_savefiles_enable || sort_savefiles_by_content_enable)
8945          RARCH_LOG("Saving files in content directory is set. This overrides other save file directory settings.\n");
8946    }
8947 
8948    /* Set savestate directory if empty based on content directory */
8949    if (string_is_empty(new_savestate_dir) || savestates_in_content_dir)
8950    {
8951       strlcpy(new_savestate_dir, p_rarch->path_main_basename,
8952             sizeof(new_savestate_dir));
8953       path_basedir(new_savestate_dir);
8954 
8955       if (string_is_empty(new_savestate_dir))
8956          RARCH_LOG("Cannot resolve save state file path.\n",
8957             msg_hash_to_str(MSG_REVERTING_SAVESTATE_DIRECTORY_TO),
8958             new_savestate_dir);
8959       else if (sort_savestates_enable || sort_savestates_by_content_enable)
8960          RARCH_LOG("Saving save states in content directory is set. This overrides other save state file directory settings.\n");
8961    }
8962 
8963    if (global && system && !string_is_empty(system->library_name))
8964    {
8965       bool savefile_is_dir  = path_is_directory(new_savefile_dir);
8966       bool savestate_is_dir = path_is_directory(new_savestate_dir);
8967       if (savefile_is_dir)
8968          strlcpy(global->name.savefile, new_savefile_dir,
8969                sizeof(global->name.savefile));
8970       else
8971          savefile_is_dir    = path_is_directory(global->name.savefile);
8972 
8973       if (savestate_is_dir)
8974          strlcpy(global->name.savestate, new_savestate_dir,
8975                sizeof(global->name.savestate));
8976       else
8977          savestate_is_dir   = path_is_directory(global->name.savestate);
8978 
8979       if (savefile_is_dir)
8980       {
8981          fill_pathname_dir(global->name.savefile,
8982                !string_is_empty(p_rarch->path_main_basename)
8983                ? p_rarch->path_main_basename
8984                : system->library_name,
8985                FILE_PATH_SRM_EXTENSION,
8986                sizeof(global->name.savefile));
8987          RARCH_LOG("[Overrides]: %s \"%s\".\n",
8988                msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
8989                global->name.savefile);
8990       }
8991 
8992       if (savestate_is_dir)
8993       {
8994          fill_pathname_dir(global->name.savestate,
8995                !string_is_empty(p_rarch->path_main_basename)
8996                ? p_rarch->path_main_basename
8997                : system->library_name,
8998                FILE_PATH_STATE_EXTENSION,
8999                sizeof(global->name.savestate));
9000          RARCH_LOG("[Overrides]: %s \"%s\".\n",
9001                msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO),
9002                global->name.savestate);
9003       }
9004 
9005 #ifdef HAVE_CHEATS
9006       if (path_is_directory(global->name.cheatfile))
9007       {
9008          fill_pathname_dir(global->name.cheatfile,
9009                !string_is_empty(p_rarch->path_main_basename)
9010                ? p_rarch->path_main_basename
9011                : system->library_name,
9012                FILE_PATH_CHT_EXTENSION,
9013                sizeof(global->name.cheatfile));
9014          RARCH_LOG("[Overrides]: %s \"%s\".\n",
9015                msg_hash_to_str(MSG_REDIRECTING_CHEATFILE_TO),
9016                global->name.cheatfile);
9017       }
9018 #endif
9019    }
9020 
9021    dir_set(RARCH_DIR_CURRENT_SAVEFILE,  new_savefile_dir);
9022    dir_set(RARCH_DIR_CURRENT_SAVESTATE, new_savestate_dir);
9023 }
9024 
path_set_basename(struct rarch_state * p_rarch,const char * path)9025 static void path_set_basename(
9026       struct rarch_state *p_rarch,
9027       const char *path)
9028 {
9029    char *dst                   = NULL;
9030 
9031    path_set(RARCH_PATH_CONTENT,  path);
9032    path_set(RARCH_PATH_BASENAME, path);
9033 
9034 #ifdef HAVE_COMPRESSION
9035    /* Removing extension is a bit tricky for compressed files.
9036     * Basename means:
9037     * /file/to/path/game.extension should be:
9038     * /file/to/path/game
9039     *
9040     * Two things to consider here are: /file/to/path/ is expected
9041     * to be a directory and "game" is a single file. This is used for
9042     * states and srm default paths.
9043     *
9044     * For compressed files we have:
9045     *
9046     * /file/to/path/comp.7z#game.extension and
9047     * /file/to/path/comp.7z#folder/game.extension
9048     *
9049     * The choice I take here is:
9050     * /file/to/path/game as basename. We might end up in a writable
9051     * directory then and the name of srm and states are meaningful.
9052     *
9053     */
9054    path_basedir_wrapper(p_rarch->path_main_basename);
9055    if (!string_is_empty(p_rarch->path_main_basename))
9056       fill_pathname_dir(p_rarch->path_main_basename, path, "", sizeof(p_rarch->path_main_basename));
9057 #endif
9058 
9059    if ((dst = strrchr(p_rarch->path_main_basename, '.')))
9060       *dst = '\0';
9061 }
9062 
path_get_subsystem_list(void)9063 struct string_list *path_get_subsystem_list(void)
9064 {
9065    struct rarch_state       *p_rarch = &rarch_st;
9066    return p_rarch->subsystem_fullpaths;
9067 }
9068 
path_set_special(char ** argv,unsigned num_content)9069 void path_set_special(char **argv, unsigned num_content)
9070 {
9071    unsigned i;
9072    char str[PATH_MAX_LENGTH];
9073    union string_list_elem_attr attr;
9074    struct string_list subsystem_paths  = {0};
9075    struct rarch_state         *p_rarch = &rarch_st;
9076    global_t   *global                  = &p_rarch->g_extern;
9077    const char *savestate_dir           = p_rarch->current_savestate_dir;
9078 
9079 
9080    /* First content file is the significant one. */
9081    path_set_basename(p_rarch, argv[0]);
9082 
9083    string_list_initialize(&subsystem_paths);
9084 
9085    p_rarch->subsystem_fullpaths        = string_list_new();
9086    retro_assert(p_rarch->subsystem_fullpaths);
9087 
9088    attr.i = 0;
9089 
9090    for (i = 0; i < num_content; i++)
9091    {
9092       string_list_append(p_rarch->subsystem_fullpaths, argv[i], attr);
9093       strlcpy(str, argv[i], sizeof(str));
9094       path_remove_extension(str);
9095       string_list_append(&subsystem_paths, path_basename(str), attr);
9096    }
9097 
9098    str[0] = '\0';
9099    string_list_join_concat(str, sizeof(str), &subsystem_paths, " + ");
9100    string_list_deinitialize(&subsystem_paths);
9101 
9102    /* We defer SRAM path updates until we can resolve it.
9103     * It is more complicated for special content types. */
9104    if (global)
9105    {
9106       bool is_dir = path_is_directory(savestate_dir);
9107 
9108       if (is_dir)
9109          strlcpy(global->name.savestate, savestate_dir,
9110                sizeof(global->name.savestate));
9111       else
9112          is_dir   = path_is_directory(global->name.savestate);
9113 
9114       if (is_dir)
9115       {
9116          fill_pathname_dir(global->name.savestate,
9117                str,
9118                ".state",
9119                sizeof(global->name.savestate));
9120          RARCH_LOG("%s \"%s\".\n",
9121                msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO),
9122                global->name.savestate);
9123       }
9124    }
9125 }
9126 
path_init_subsystem(struct rarch_state * p_rarch)9127 static bool path_init_subsystem(struct rarch_state *p_rarch)
9128 {
9129    unsigned i, j;
9130    const struct retro_subsystem_info *info = NULL;
9131    global_t   *global                      = &p_rarch->g_extern;
9132    rarch_system_info_t             *system = &runloop_state.system;
9133    bool subsystem_path_empty               = path_is_empty(RARCH_PATH_SUBSYSTEM);
9134    const char                *savefile_dir = p_rarch->current_savefile_dir;
9135 
9136 
9137    if (!system || subsystem_path_empty)
9138       return false;
9139    /* For subsystems, we know exactly which RAM types are supported. */
9140 
9141    info = libretro_find_subsystem_info(
9142          system->subsystem.data,
9143          system->subsystem.size,
9144          path_get(RARCH_PATH_SUBSYSTEM));
9145 
9146    /* We'll handle this error gracefully later. */
9147    if (info)
9148    {
9149       unsigned num_content = MIN(info->num_roms,
9150             subsystem_path_empty ?
9151             0 : (unsigned)p_rarch->subsystem_fullpaths->size);
9152 
9153       for (i = 0; i < num_content; i++)
9154       {
9155          for (j = 0; j < info->roms[i].num_memory; j++)
9156          {
9157             char ext[32];
9158             union string_list_elem_attr attr;
9159             char savename[PATH_MAX_LENGTH];
9160             char path[PATH_MAX_LENGTH];
9161             const struct retro_subsystem_memory_info *mem =
9162                (const struct retro_subsystem_memory_info*)
9163                &info->roms[i].memory[j];
9164 
9165             path[0] = ext[0] = '\0';
9166             ext[0]  = '.';
9167             ext[1]  = '\0';
9168             strlcat(ext, mem->extension, sizeof(ext));
9169             strlcpy(savename,
9170                   p_rarch->subsystem_fullpaths->elems[i].data,
9171                   sizeof(savename));
9172             path_remove_extension(savename);
9173 
9174             if (path_is_directory(savefile_dir))
9175             {
9176                /* Use SRAM dir */
9177                /* Redirect content fullpath to save directory. */
9178                strlcpy(path, savefile_dir, sizeof(path));
9179                fill_pathname_dir(path, savename, ext, sizeof(path));
9180             }
9181             else
9182                fill_pathname(path, savename, ext, sizeof(path));
9183 
9184             RARCH_LOG("%s \"%s\".\n",
9185                msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
9186                path);
9187 
9188             attr.i = mem->type;
9189             string_list_append((struct string_list*)savefile_ptr_get(),
9190                   path, attr);
9191          }
9192       }
9193    }
9194 
9195    if (global)
9196    {
9197       /* Let other relevant paths be inferred from the main SRAM location. */
9198       if (!retroarch_override_setting_is_set(
9199                RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL))
9200          fill_pathname_noext(global->name.savefile,
9201                p_rarch->path_main_basename,
9202                ".srm",
9203                sizeof(global->name.savefile));
9204 
9205       if (path_is_directory(global->name.savefile))
9206       {
9207          fill_pathname_dir(global->name.savefile,
9208                p_rarch->path_main_basename,
9209                ".srm",
9210                sizeof(global->name.savefile));
9211          RARCH_LOG("%s \"%s\".\n",
9212                msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
9213                global->name.savefile);
9214       }
9215    }
9216 
9217    return true;
9218 }
9219 
path_init_savefile(struct rarch_state * p_rarch)9220 static void path_init_savefile(struct rarch_state *p_rarch)
9221 {
9222    bool    should_sram_be_used = p_rarch->rarch_use_sram
9223       && !p_rarch->rarch_is_sram_save_disabled;
9224 
9225    p_rarch->rarch_use_sram     = should_sram_be_used;
9226 
9227    if (!p_rarch->rarch_use_sram)
9228    {
9229       RARCH_LOG("[SRAM]: %s\n",
9230             msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED));
9231       return;
9232    }
9233 
9234    command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
9235 }
9236 
path_init_savefile_internal(global_t * global,struct rarch_state * p_rarch)9237 static void path_init_savefile_internal(
9238       global_t *global,
9239       struct rarch_state *p_rarch)
9240 {
9241    path_deinit_savefile();
9242    path_init_savefile_new();
9243 
9244    if (!path_init_subsystem(p_rarch))
9245       path_init_savefile_rtc(global->name.savefile);
9246 }
9247 
path_fill_names(struct rarch_state * p_rarch)9248 static void path_fill_names(struct rarch_state *p_rarch)
9249 {
9250    global_t            *global = &p_rarch->g_extern;
9251 
9252    path_init_savefile_internal(global, p_rarch);
9253 
9254 #ifdef HAVE_BSV_MOVIE
9255    if (global)
9256       strlcpy(p_rarch->bsv_movie_state.movie_path,
9257             global->name.savefile,
9258             sizeof(p_rarch->bsv_movie_state.movie_path));
9259 #endif
9260 
9261    if (string_is_empty(p_rarch->path_main_basename))
9262       return;
9263 
9264    if (global)
9265    {
9266       if (string_is_empty(global->name.ups))
9267          fill_pathname_noext(global->name.ups,
9268                p_rarch->path_main_basename,
9269                ".ups",
9270                sizeof(global->name.ups));
9271 
9272       if (string_is_empty(global->name.bps))
9273          fill_pathname_noext(global->name.bps,
9274                p_rarch->path_main_basename,
9275                ".bps",
9276                sizeof(global->name.bps));
9277 
9278       if (string_is_empty(global->name.ips))
9279          fill_pathname_noext(global->name.ips,
9280                p_rarch->path_main_basename,
9281                ".ips",
9282                sizeof(global->name.ips));
9283    }
9284 }
9285 
path_get_ptr(enum rarch_path_type type)9286 char *path_get_ptr(enum rarch_path_type type)
9287 {
9288    struct rarch_state *p_rarch = &rarch_st;
9289 
9290    switch (type)
9291    {
9292       case RARCH_PATH_CONTENT:
9293          return p_rarch->path_content;
9294       case RARCH_PATH_DEFAULT_SHADER_PRESET:
9295          return p_rarch->path_default_shader_preset;
9296       case RARCH_PATH_BASENAME:
9297          return p_rarch->path_main_basename;
9298       case RARCH_PATH_CORE_OPTIONS:
9299          if (!path_is_empty(RARCH_PATH_CORE_OPTIONS))
9300             return p_rarch->path_core_options_file;
9301          break;
9302       case RARCH_PATH_SUBSYSTEM:
9303          return p_rarch->subsystem_path;
9304       case RARCH_PATH_CONFIG:
9305          if (!path_is_empty(RARCH_PATH_CONFIG))
9306             return p_rarch->path_config_file;
9307          break;
9308       case RARCH_PATH_CONFIG_APPEND:
9309          if (!path_is_empty(RARCH_PATH_CONFIG_APPEND))
9310             return p_rarch->path_config_append_file;
9311          break;
9312       case RARCH_PATH_CORE:
9313          return p_rarch->path_libretro;
9314       case RARCH_PATH_NONE:
9315       case RARCH_PATH_NAMES:
9316          break;
9317    }
9318 
9319    return NULL;
9320 }
9321 
path_get(enum rarch_path_type type)9322 const char *path_get(enum rarch_path_type type)
9323 {
9324    struct rarch_state *p_rarch = &rarch_st;
9325 
9326    switch (type)
9327    {
9328       case RARCH_PATH_CONTENT:
9329          return p_rarch->path_content;
9330       case RARCH_PATH_DEFAULT_SHADER_PRESET:
9331          return p_rarch->path_default_shader_preset;
9332       case RARCH_PATH_BASENAME:
9333          return p_rarch->path_main_basename;
9334       case RARCH_PATH_CORE_OPTIONS:
9335          if (!path_is_empty(RARCH_PATH_CORE_OPTIONS))
9336             return p_rarch->path_core_options_file;
9337          break;
9338       case RARCH_PATH_SUBSYSTEM:
9339          return p_rarch->subsystem_path;
9340       case RARCH_PATH_CONFIG:
9341          if (!path_is_empty(RARCH_PATH_CONFIG))
9342             return p_rarch->path_config_file;
9343          break;
9344       case RARCH_PATH_CONFIG_APPEND:
9345          if (!path_is_empty(RARCH_PATH_CONFIG_APPEND))
9346             return p_rarch->path_config_append_file;
9347          break;
9348       case RARCH_PATH_CORE:
9349          return p_rarch->path_libretro;
9350       case RARCH_PATH_NONE:
9351       case RARCH_PATH_NAMES:
9352          break;
9353    }
9354 
9355    return NULL;
9356 }
9357 
path_get_realsize(enum rarch_path_type type)9358 size_t path_get_realsize(enum rarch_path_type type)
9359 {
9360    struct rarch_state *p_rarch = &rarch_st;
9361 
9362    switch (type)
9363    {
9364       case RARCH_PATH_CONTENT:
9365          return sizeof(p_rarch->path_content);
9366       case RARCH_PATH_DEFAULT_SHADER_PRESET:
9367          return sizeof(p_rarch->path_default_shader_preset);
9368       case RARCH_PATH_BASENAME:
9369          return sizeof(p_rarch->path_main_basename);
9370       case RARCH_PATH_CORE_OPTIONS:
9371          return sizeof(p_rarch->path_core_options_file);
9372       case RARCH_PATH_SUBSYSTEM:
9373          return sizeof(p_rarch->subsystem_path);
9374       case RARCH_PATH_CONFIG:
9375          return sizeof(p_rarch->path_config_file);
9376       case RARCH_PATH_CONFIG_APPEND:
9377          return sizeof(p_rarch->path_config_append_file);
9378       case RARCH_PATH_CORE:
9379          return sizeof(p_rarch->path_libretro);
9380       case RARCH_PATH_NONE:
9381       case RARCH_PATH_NAMES:
9382          break;
9383    }
9384 
9385    return 0;
9386 }
9387 
path_set_names(struct rarch_state * p_rarch,global_t * global)9388 static void path_set_names(struct rarch_state *p_rarch,
9389       global_t *global)
9390 {
9391    if (global)
9392    {
9393       if (!retroarch_override_setting_is_set(
9394                RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL))
9395          fill_pathname_noext(global->name.savefile,
9396                p_rarch->path_main_basename,
9397                ".srm", sizeof(global->name.savefile));
9398 
9399       if (!retroarch_override_setting_is_set(
9400                RARCH_OVERRIDE_SETTING_STATE_PATH, NULL))
9401          fill_pathname_noext(global->name.savestate,
9402                p_rarch->path_main_basename,
9403                ".state", sizeof(global->name.savestate));
9404 
9405 #ifdef HAVE_CHEATS
9406       if (!string_is_empty(p_rarch->path_main_basename))
9407          fill_pathname_noext(global->name.cheatfile,
9408                p_rarch->path_main_basename,
9409                ".cht", sizeof(global->name.cheatfile));
9410 #endif
9411    }
9412 }
9413 
path_set(enum rarch_path_type type,const char * path)9414 bool path_set(enum rarch_path_type type, const char *path)
9415 {
9416    struct rarch_state *p_rarch = &rarch_st;
9417 
9418    if (!path)
9419       return false;
9420 
9421    switch (type)
9422    {
9423       case RARCH_PATH_BASENAME:
9424          strlcpy(p_rarch->path_main_basename, path,
9425                sizeof(p_rarch->path_main_basename));
9426          break;
9427       case RARCH_PATH_NAMES:
9428          path_set_basename(p_rarch, path);
9429          path_set_names(p_rarch, &p_rarch->g_extern);
9430          path_set_redirect(p_rarch, p_rarch->configuration_settings);
9431          break;
9432       case RARCH_PATH_CORE:
9433          strlcpy(p_rarch->path_libretro, path,
9434                sizeof(p_rarch->path_libretro));
9435          break;
9436       case RARCH_PATH_DEFAULT_SHADER_PRESET:
9437          strlcpy(p_rarch->path_default_shader_preset, path,
9438                sizeof(p_rarch->path_default_shader_preset));
9439          break;
9440       case RARCH_PATH_CONFIG_APPEND:
9441          strlcpy(p_rarch->path_config_append_file, path,
9442                sizeof(p_rarch->path_config_append_file));
9443          break;
9444       case RARCH_PATH_CONFIG:
9445          strlcpy(p_rarch->path_config_file, path,
9446                sizeof(p_rarch->path_config_file));
9447          break;
9448       case RARCH_PATH_SUBSYSTEM:
9449          strlcpy(p_rarch->subsystem_path, path,
9450                sizeof(p_rarch->subsystem_path));
9451          break;
9452       case RARCH_PATH_CORE_OPTIONS:
9453          strlcpy(p_rarch->path_core_options_file, path,
9454                sizeof(p_rarch->path_core_options_file));
9455          break;
9456       case RARCH_PATH_CONTENT:
9457          strlcpy(p_rarch->path_content, path,
9458                sizeof(p_rarch->path_content));
9459          break;
9460       case RARCH_PATH_NONE:
9461          break;
9462    }
9463 
9464    return true;
9465 }
9466 
path_is_empty(enum rarch_path_type type)9467 bool path_is_empty(enum rarch_path_type type)
9468 {
9469    struct rarch_state *p_rarch = &rarch_st;
9470 
9471    switch (type)
9472    {
9473       case RARCH_PATH_DEFAULT_SHADER_PRESET:
9474          if (string_is_empty(p_rarch->path_default_shader_preset))
9475             return true;
9476          break;
9477       case RARCH_PATH_SUBSYSTEM:
9478          if (string_is_empty(p_rarch->subsystem_path))
9479             return true;
9480          break;
9481       case RARCH_PATH_CONFIG:
9482          if (string_is_empty(p_rarch->path_config_file))
9483             return true;
9484          break;
9485       case RARCH_PATH_CORE_OPTIONS:
9486          if (string_is_empty(p_rarch->path_core_options_file))
9487             return true;
9488          break;
9489       case RARCH_PATH_CONFIG_APPEND:
9490          if (string_is_empty(p_rarch->path_config_append_file))
9491             return true;
9492          break;
9493       case RARCH_PATH_CONTENT:
9494          if (string_is_empty(p_rarch->path_content))
9495             return true;
9496          break;
9497       case RARCH_PATH_CORE:
9498          if (string_is_empty(p_rarch->path_libretro))
9499             return true;
9500          break;
9501       case RARCH_PATH_BASENAME:
9502          if (string_is_empty(p_rarch->path_main_basename))
9503             return true;
9504          break;
9505       case RARCH_PATH_NONE:
9506       case RARCH_PATH_NAMES:
9507          break;
9508    }
9509 
9510    return false;
9511 }
9512 
path_clear(enum rarch_path_type type)9513 void path_clear(enum rarch_path_type type)
9514 {
9515    struct rarch_state *p_rarch = &rarch_st;
9516 
9517    switch (type)
9518    {
9519       case RARCH_PATH_SUBSYSTEM:
9520          *p_rarch->subsystem_path = '\0';
9521          break;
9522       case RARCH_PATH_CORE:
9523          *p_rarch->path_libretro = '\0';
9524          break;
9525       case RARCH_PATH_CONFIG:
9526          *p_rarch->path_config_file = '\0';
9527          break;
9528       case RARCH_PATH_CONTENT:
9529          *p_rarch->path_content = '\0';
9530          break;
9531       case RARCH_PATH_BASENAME:
9532          *p_rarch->path_main_basename = '\0';
9533          break;
9534       case RARCH_PATH_CORE_OPTIONS:
9535          *p_rarch->path_core_options_file = '\0';
9536          break;
9537       case RARCH_PATH_DEFAULT_SHADER_PRESET:
9538          *p_rarch->path_default_shader_preset = '\0';
9539          break;
9540       case RARCH_PATH_CONFIG_APPEND:
9541          *p_rarch->path_config_append_file = '\0';
9542          break;
9543       case RARCH_PATH_NONE:
9544       case RARCH_PATH_NAMES:
9545          break;
9546    }
9547 }
9548 
path_clear_all(void)9549 static void path_clear_all(void)
9550 {
9551    path_clear(RARCH_PATH_CONTENT);
9552    path_clear(RARCH_PATH_CONFIG);
9553    path_clear(RARCH_PATH_CONFIG_APPEND);
9554    path_clear(RARCH_PATH_CORE_OPTIONS);
9555    path_clear(RARCH_PATH_BASENAME);
9556 }
9557 
path_is_media_type(const char * path)9558 enum rarch_content_type path_is_media_type(const char *path)
9559 {
9560    char ext_lower[128];
9561 
9562    ext_lower[0] = '\0';
9563 
9564    strlcpy(ext_lower, path_get_extension(path), sizeof(ext_lower));
9565 
9566    string_to_lower(ext_lower);
9567 
9568    /* hack, to detect livestreams so the ffmpeg core can be started */
9569    if (string_starts_with_size(path, "udp://",   STRLEN_CONST("udp://"))   ||
9570        string_starts_with_size(path, "http://",  STRLEN_CONST("http://"))  ||
9571        string_starts_with_size(path, "https://", STRLEN_CONST("https://")) ||
9572        string_starts_with_size(path, "tcp://",   STRLEN_CONST("tcp://"))   ||
9573        string_starts_with_size(path, "rtmp://",  STRLEN_CONST("rtmp://"))  ||
9574        string_starts_with_size(path, "rtp://",   STRLEN_CONST("rtp://")))
9575       return RARCH_CONTENT_MOVIE;
9576 
9577    switch (msg_hash_to_file_type(msg_hash_calculate(ext_lower)))
9578    {
9579 #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
9580       case FILE_TYPE_OGM:
9581       case FILE_TYPE_MKV:
9582       case FILE_TYPE_AVI:
9583       case FILE_TYPE_MP4:
9584       case FILE_TYPE_FLV:
9585       case FILE_TYPE_WEBM:
9586       case FILE_TYPE_3GP:
9587       case FILE_TYPE_3G2:
9588       case FILE_TYPE_F4F:
9589       case FILE_TYPE_F4V:
9590       case FILE_TYPE_MOV:
9591       case FILE_TYPE_WMV:
9592       case FILE_TYPE_MPG:
9593       case FILE_TYPE_MPEG:
9594       case FILE_TYPE_VOB:
9595       case FILE_TYPE_ASF:
9596       case FILE_TYPE_DIVX:
9597       case FILE_TYPE_M2P:
9598       case FILE_TYPE_M2TS:
9599       case FILE_TYPE_PS:
9600       case FILE_TYPE_TS:
9601       case FILE_TYPE_MXF:
9602          return RARCH_CONTENT_MOVIE;
9603       case FILE_TYPE_WMA:
9604       case FILE_TYPE_OGG:
9605       case FILE_TYPE_MP3:
9606       case FILE_TYPE_M4A:
9607       case FILE_TYPE_FLAC:
9608       case FILE_TYPE_WAV:
9609          return RARCH_CONTENT_MUSIC;
9610 #endif
9611 #ifdef HAVE_IMAGEVIEWER
9612       case FILE_TYPE_JPEG:
9613       case FILE_TYPE_PNG:
9614       case FILE_TYPE_TGA:
9615       case FILE_TYPE_BMP:
9616          return RARCH_CONTENT_IMAGE;
9617 #endif
9618 #ifdef HAVE_IBXM
9619       case FILE_TYPE_MOD:
9620       case FILE_TYPE_S3M:
9621       case FILE_TYPE_XM:
9622          return RARCH_CONTENT_MUSIC;
9623 #endif
9624 #ifdef HAVE_GONG
9625       case FILE_TYPE_GONG:
9626          return RARCH_CONTENT_GONG;
9627 #endif
9628 
9629       case FILE_TYPE_NONE:
9630       default:
9631          break;
9632    }
9633 
9634    return RARCH_CONTENT_NONE;
9635 }
9636 
path_deinit_subsystem(struct rarch_state * p_rarch)9637 static void path_deinit_subsystem(struct rarch_state *p_rarch)
9638 {
9639    if (p_rarch->subsystem_fullpaths)
9640       string_list_free(p_rarch->subsystem_fullpaths);
9641    p_rarch->subsystem_fullpaths = NULL;
9642 }
9643 
dir_free_shader(struct rarch_dir_shader_list * dir_list,bool shader_remember_last_dir)9644 static void dir_free_shader(
9645       struct rarch_dir_shader_list *dir_list,
9646       bool shader_remember_last_dir)
9647 {
9648    if (dir_list->shader_list)
9649    {
9650       dir_list_free(dir_list->shader_list);
9651       dir_list->shader_list = NULL;
9652    }
9653 
9654    if (dir_list->directory)
9655    {
9656       free(dir_list->directory);
9657       dir_list->directory = NULL;
9658    }
9659 
9660    dir_list->selection                = 0;
9661    dir_list->shader_loaded            = false;
9662    dir_list->remember_last_preset_dir = shader_remember_last_dir;
9663 }
9664 
9665 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
dir_init_shader_internal(bool shader_remember_last_dir,struct rarch_dir_shader_list * dir_list,const char * shader_dir,const char * shader_file_name,bool show_hidden_files)9666 static bool dir_init_shader_internal(
9667       bool shader_remember_last_dir,
9668       struct rarch_dir_shader_list *dir_list,
9669       const char *shader_dir,
9670       const char *shader_file_name,
9671       bool show_hidden_files)
9672 {
9673    size_t i;
9674    struct string_list *new_list           = dir_list_new_special(
9675          shader_dir, DIR_LIST_SHADERS, NULL, show_hidden_files);
9676    bool search_file_name                  = shader_remember_last_dir &&
9677          !string_is_empty(shader_file_name);
9678 
9679    if (!new_list)
9680       return false;
9681 
9682    if (new_list->size < 1)
9683    {
9684       dir_list_free(new_list);
9685       return false;
9686    }
9687 
9688    dir_list_sort(new_list, false);
9689 
9690    dir_list->shader_list              = new_list;
9691    dir_list->directory                = strdup(shader_dir);
9692    dir_list->selection                = 0;
9693    dir_list->shader_loaded            = false;
9694    dir_list->remember_last_preset_dir = shader_remember_last_dir;
9695 
9696    if (search_file_name)
9697    {
9698       for (i = 0; i < new_list->size; i++)
9699       {
9700          const char *file_name = NULL;
9701          const char *file_path = new_list->elems[i].data;
9702 
9703          if (string_is_empty(file_path))
9704             continue;
9705 
9706          /* If a shader file name has been provided,
9707           * search the list for a match and set 'selection'
9708           * index if found */
9709          file_name = path_basename(file_path);
9710 
9711          if (!string_is_empty(file_name) &&
9712                string_is_equal(file_name, shader_file_name))
9713          {
9714             RARCH_LOG("[Shaders]: %s \"%s\"\n",
9715                   msg_hash_to_str(MSG_FOUND_SHADER),
9716                   file_path);
9717 
9718             dir_list->selection = i;
9719             break;
9720          }
9721       }
9722    }
9723 
9724    return true;
9725 }
9726 
dir_init_shader(struct rarch_state * p_rarch,settings_t * settings,struct rarch_dir_shader_list * dir_list)9727 static void dir_init_shader(
9728       struct rarch_state *p_rarch,
9729       settings_t *settings,
9730       struct rarch_dir_shader_list *dir_list)
9731 {
9732    bool show_hidden_files                         = settings->bools.show_hidden_files;
9733    bool shader_remember_last_dir                  = settings->bools.video_shader_remember_last_dir;
9734    const char *directory_video_shader             = settings->paths.directory_video_shader;
9735    const char *directory_menu_config              = settings->paths.directory_menu_config;
9736    bool video_shader_remember_last_dir            = settings->bools.video_shader_remember_last_dir;
9737    const char *last_shader_preset_dir             = NULL;
9738    const char *last_shader_preset_file_name       = NULL;
9739 #if defined(HAVE_MENU)
9740    menu_handle_t *menu                            = p_rarch->menu_driver_data;
9741    enum rarch_shader_type last_shader_preset_type = menu ? menu->last_shader_selection.preset_type : RARCH_SHADER_NONE;
9742    menu_driver_get_last_shader_preset_path(
9743          &last_shader_preset_dir, &last_shader_preset_file_name);
9744 #else
9745    enum rarch_shader_type last_shader_preset_type = RARCH_SHADER_NONE;
9746 #endif
9747 
9748    /* Always free existing shader list */
9749    dir_free_shader(dir_list,
9750          video_shader_remember_last_dir);
9751 
9752    /* Try directory of last selected shader preset */
9753    if (shader_remember_last_dir &&
9754        (last_shader_preset_type != RARCH_SHADER_NONE) &&
9755        !string_is_empty(last_shader_preset_dir) &&
9756        dir_init_shader_internal(
9757           video_shader_remember_last_dir,
9758           dir_list,
9759           last_shader_preset_dir,
9760           last_shader_preset_file_name,
9761           show_hidden_files))
9762       return;
9763 
9764    /* Try video shaders directory */
9765    if (!string_is_empty(directory_video_shader) &&
9766        dir_init_shader_internal(
9767             video_shader_remember_last_dir,
9768             dir_list,
9769             directory_video_shader, NULL, show_hidden_files))
9770       return;
9771 
9772    /* Try config directory */
9773    if (!string_is_empty(directory_menu_config) &&
9774        dir_init_shader_internal(
9775             video_shader_remember_last_dir,
9776             dir_list,
9777             directory_menu_config, NULL, show_hidden_files))
9778       return;
9779 
9780    /* Try 'top level' directory containing main
9781     * RetroArch config file */
9782    if (!path_is_empty(RARCH_PATH_CONFIG))
9783    {
9784       char *rarch_config_directory = strdup(path_get(RARCH_PATH_CONFIG));
9785       path_basedir(rarch_config_directory);
9786 
9787       if (!string_is_empty(rarch_config_directory))
9788          dir_init_shader_internal(
9789                video_shader_remember_last_dir,
9790                dir_list,
9791                rarch_config_directory, NULL, show_hidden_files);
9792 
9793       free(rarch_config_directory);
9794    }
9795 }
9796 
9797 /**
9798  * dir_check_shader:
9799  * @pressed_next         : Was next shader key pressed?
9800  * @pressed_prev         : Was previous shader key pressed?
9801  *
9802  * Checks if any one of the shader keys has been pressed for this frame:
9803  * a) Next shader index.
9804  * b) Previous shader index.
9805  *
9806  * Will also immediately apply the shader.
9807  **/
dir_check_shader(struct rarch_state * p_rarch,settings_t * settings,struct rarch_dir_shader_list * dir_list,bool pressed_next,bool pressed_prev)9808 static void dir_check_shader(
9809       struct rarch_state *p_rarch,
9810       settings_t *settings,
9811       struct rarch_dir_shader_list *dir_list,
9812       bool pressed_next,
9813       bool pressed_prev)
9814 {
9815    bool video_shader_remember_last_dir            = settings->bools.video_shader_remember_last_dir;
9816    const char *last_shader_preset_dir             = NULL;
9817    const char *last_shader_preset_file_name       = NULL;
9818    const char *set_shader_path                    = NULL;
9819    bool dir_list_initialised                      = false;
9820 #if defined(HAVE_MENU)
9821    menu_handle_t *menu                            = p_rarch->menu_driver_data;
9822    enum rarch_shader_type last_shader_preset_type = menu ? menu->last_shader_selection.preset_type : RARCH_SHADER_NONE;
9823    menu_driver_get_last_shader_preset_path(
9824          &last_shader_preset_dir, &last_shader_preset_file_name);
9825 #else
9826    enum rarch_shader_type last_shader_preset_type = RARCH_SHADER_NONE;
9827 #endif
9828 
9829    /* Check whether shader list needs to be
9830     * (re)initialised */
9831    if (!dir_list->shader_list ||
9832        (dir_list->remember_last_preset_dir != video_shader_remember_last_dir) ||
9833        (video_shader_remember_last_dir &&
9834         (last_shader_preset_type != RARCH_SHADER_NONE) &&
9835         !string_is_equal(dir_list->directory, last_shader_preset_dir)))
9836    {
9837       dir_init_shader(p_rarch, settings, dir_list);
9838       dir_list_initialised = true;
9839    }
9840 
9841    if (!dir_list->shader_list ||
9842        (dir_list->shader_list->size < 1))
9843       return;
9844 
9845    /* Check whether a 'last used' shader file
9846     * name is provided
9847     * > Note: We can end up calling
9848     *   string_is_equal(dir_list->directory, last_shader_preset_dir)
9849     *   twice. This is wasteful, but we cannot safely cache
9850     *   the first result since dir_init_shader() is called
9851     *   in-between the two invocations... */
9852    if (video_shader_remember_last_dir &&
9853        (last_shader_preset_type != RARCH_SHADER_NONE) &&
9854        string_is_equal(dir_list->directory, last_shader_preset_dir) &&
9855        !string_is_empty(last_shader_preset_file_name))
9856    {
9857       /* Ensure that we start with a dir_list selection
9858        * index matching the last used shader */
9859       if (!dir_list_initialised)
9860       {
9861          const char *current_file_path = NULL;
9862          const char *current_file_name = NULL;
9863 
9864          if (dir_list->selection < dir_list->shader_list->size)
9865             current_file_path = dir_list->shader_list->elems[dir_list->selection].data;
9866 
9867          if (!string_is_empty(current_file_path))
9868             current_file_name = path_basename(current_file_path);
9869 
9870          if (!string_is_empty(current_file_name) &&
9871              !string_is_equal(current_file_name, last_shader_preset_file_name))
9872          {
9873             size_t i;
9874             for (i = 0; i < dir_list->shader_list->size; i++)
9875             {
9876                const char *file_path = dir_list->shader_list->elems[i].data;
9877                const char *file_name = NULL;
9878 
9879                if (string_is_empty(file_path))
9880                   continue;
9881 
9882                file_name = path_basename(file_path);
9883 
9884                if (string_is_empty(file_name))
9885                   continue;
9886 
9887                if (string_is_equal(file_name, last_shader_preset_file_name))
9888                {
9889                   dir_list->selection = i;
9890                   break;
9891                }
9892             }
9893          }
9894       }
9895 
9896       /* Check whether the shader referenced by the
9897        * current selection index is already loaded */
9898       if (!dir_list->shader_loaded)
9899       {
9900          struct video_shader *shader = menu_shader_get();
9901 
9902          if (shader && !string_is_empty(shader->loaded_preset_path))
9903          {
9904             char last_shader_path[PATH_MAX_LENGTH];
9905             last_shader_path[0] = '\0';
9906 
9907             fill_pathname_join(last_shader_path,
9908                   last_shader_preset_dir, last_shader_preset_file_name,
9909                   sizeof(last_shader_path));
9910 
9911             if (string_is_equal(last_shader_path, shader->loaded_preset_path))
9912                dir_list->shader_loaded = true;
9913          }
9914       }
9915    }
9916 
9917    /* Select next shader in list */
9918    if (pressed_next)
9919    {
9920       /* Only increment selection if a shader
9921        * from this list has already been loaded
9922        * (otherwise first entry in the list may
9923        * be skipped) */
9924       if (dir_list->shader_loaded)
9925       {
9926          if (dir_list->selection < dir_list->shader_list->size - 1)
9927             dir_list->selection++;
9928          else
9929             dir_list->selection = 0;
9930       }
9931    }
9932    /* Select previous shader in list */
9933    else if (pressed_prev)
9934    {
9935       if (dir_list->selection > 0)
9936          dir_list->selection--;
9937       else
9938          dir_list->selection = dir_list->shader_list->size - 1;
9939    }
9940    else
9941       return;
9942 
9943    set_shader_path = dir_list->shader_list->elems[dir_list->selection].data;
9944 #if defined(HAVE_MENU)
9945    menu_driver_set_last_shader_preset_path(set_shader_path);
9946 #endif
9947    command_set_shader(NULL, set_shader_path);
9948    dir_list->shader_loaded = true;
9949 }
9950 #endif
9951 
9952 /* get size functions */
9953 
dir_get_size(enum rarch_dir_type type)9954 size_t dir_get_size(enum rarch_dir_type type)
9955 {
9956    struct rarch_state *p_rarch = &rarch_st;
9957 
9958    switch (type)
9959    {
9960       case RARCH_DIR_SYSTEM:
9961          return sizeof(p_rarch->dir_system);
9962       case RARCH_DIR_SAVESTATE:
9963          return sizeof(p_rarch->dir_savestate);
9964       case RARCH_DIR_CURRENT_SAVESTATE:
9965          return sizeof(p_rarch->current_savestate_dir);
9966       case RARCH_DIR_SAVEFILE:
9967          return sizeof(p_rarch->dir_savefile);
9968       case RARCH_DIR_CURRENT_SAVEFILE:
9969          return sizeof(p_rarch->current_savefile_dir);
9970       case RARCH_DIR_NONE:
9971          break;
9972    }
9973 
9974    return 0;
9975 }
9976 
9977 /* clear functions */
9978 
dir_clear(enum rarch_dir_type type)9979 void dir_clear(enum rarch_dir_type type)
9980 {
9981    struct rarch_state *p_rarch = &rarch_st;
9982 
9983    switch (type)
9984    {
9985       case RARCH_DIR_SAVEFILE:
9986          *p_rarch->dir_savefile = '\0';
9987          break;
9988       case RARCH_DIR_CURRENT_SAVEFILE:
9989          *p_rarch->current_savefile_dir = '\0';
9990          break;
9991       case RARCH_DIR_SAVESTATE:
9992          *p_rarch->dir_savestate = '\0';
9993          break;
9994       case RARCH_DIR_CURRENT_SAVESTATE:
9995          *p_rarch->current_savestate_dir = '\0';
9996          break;
9997       case RARCH_DIR_SYSTEM:
9998          *p_rarch->dir_system = '\0';
9999          break;
10000       case RARCH_DIR_NONE:
10001          break;
10002    }
10003 }
10004 
dir_clear_all(void)10005 static void dir_clear_all(void)
10006 {
10007    dir_clear(RARCH_DIR_SYSTEM);
10008    dir_clear(RARCH_DIR_SAVEFILE);
10009    dir_clear(RARCH_DIR_SAVESTATE);
10010 }
10011 
10012 /* get ptr functions */
10013 
dir_get_ptr(enum rarch_dir_type type)10014 char *dir_get_ptr(enum rarch_dir_type type)
10015 {
10016    struct rarch_state *p_rarch = &rarch_st;
10017 
10018    switch (type)
10019    {
10020       case RARCH_DIR_SAVEFILE:
10021          return p_rarch->dir_savefile;
10022       case RARCH_DIR_CURRENT_SAVEFILE:
10023          return p_rarch->current_savefile_dir;
10024       case RARCH_DIR_SAVESTATE:
10025          return p_rarch->dir_savestate;
10026       case RARCH_DIR_CURRENT_SAVESTATE:
10027          return p_rarch->current_savestate_dir;
10028       case RARCH_DIR_SYSTEM:
10029          return p_rarch->dir_system;
10030       case RARCH_DIR_NONE:
10031          break;
10032    }
10033 
10034    return NULL;
10035 }
10036 
dir_set(enum rarch_dir_type type,const char * path)10037 void dir_set(enum rarch_dir_type type, const char *path)
10038 {
10039    struct rarch_state *p_rarch = &rarch_st;
10040 
10041    switch (type)
10042    {
10043       case RARCH_DIR_CURRENT_SAVEFILE:
10044          strlcpy(p_rarch->current_savefile_dir, path,
10045                sizeof(p_rarch->current_savefile_dir));
10046          break;
10047       case RARCH_DIR_SAVEFILE:
10048          strlcpy(p_rarch->dir_savefile, path,
10049                sizeof(p_rarch->dir_savefile));
10050          break;
10051       case RARCH_DIR_CURRENT_SAVESTATE:
10052          strlcpy(p_rarch->current_savestate_dir, path,
10053                sizeof(p_rarch->current_savestate_dir));
10054          break;
10055       case RARCH_DIR_SAVESTATE:
10056          strlcpy(p_rarch->dir_savestate, path,
10057                sizeof(p_rarch->dir_savestate));
10058          break;
10059       case RARCH_DIR_SYSTEM:
10060          strlcpy(p_rarch->dir_system, path,
10061                sizeof(p_rarch->dir_system));
10062          break;
10063       case RARCH_DIR_NONE:
10064          break;
10065    }
10066 }
10067 
dir_check_defaults(const char * custom_ini_path)10068 void dir_check_defaults(const char *custom_ini_path)
10069 {
10070    size_t i;
10071 
10072    /* Early return for people with a custom folder setup
10073     * so it doesn't create unnecessary directories */
10074    if (!string_is_empty(custom_ini_path) &&
10075        path_is_valid(custom_ini_path))
10076       return;
10077 
10078    for (i = 0; i < DEFAULT_DIR_LAST; i++)
10079    {
10080       const char *dir_path = g_defaults.dirs[i];
10081       char new_path[PATH_MAX_LENGTH];
10082 
10083       if (string_is_empty(dir_path))
10084          continue;
10085 
10086       new_path[0] = '\0';
10087       fill_pathname_expand_special(new_path,
10088             dir_path, sizeof(new_path));
10089 
10090       if (!path_is_directory(new_path))
10091          path_mkdir(new_path);
10092    }
10093 }
10094 
10095 #ifdef HAVE_ACCESSIBILITY
is_accessibility_enabled(bool accessibility_enable,bool accessibility_enabled)10096 static bool is_accessibility_enabled(bool accessibility_enable,
10097       bool accessibility_enabled)
10098 {
10099    return accessibility_enabled || accessibility_enable;
10100 }
10101 #endif
10102 
gfx_widgets_ready(void)10103 bool gfx_widgets_ready(void)
10104 {
10105 #ifdef HAVE_GFX_WIDGETS
10106    struct rarch_state *p_rarch = &rarch_st;
10107    return p_rarch->widgets_active;
10108 #else
10109    return false;
10110 #endif
10111 }
10112 
osk_update_last_codepoint(unsigned * last_codepoint,unsigned * last_codepoint_len,const char * word)10113 static void osk_update_last_codepoint(
10114       unsigned *last_codepoint,
10115       unsigned *last_codepoint_len,
10116       const char *word)
10117 {
10118    const char *letter         = word;
10119    const char    *pos         = letter;
10120 
10121    for (;;)
10122    {
10123       unsigned codepoint      = utf8_walk(&letter);
10124       if (letter[0] == 0)
10125       {
10126          *last_codepoint      = codepoint;
10127          *last_codepoint_len  = (unsigned)(letter - pos);
10128          break;
10129       }
10130       pos                     = letter;
10131    }
10132 }
10133 
10134 #ifdef HAVE_MENU
menu_input_search_cb(void * userdata,const char * str)10135 static void menu_input_search_cb(void *userdata, const char *str)
10136 {
10137    const char *label           = NULL;
10138    unsigned type               = MENU_SETTINGS_NONE;
10139    struct rarch_state *p_rarch = &rarch_st;
10140    struct menu_state *menu_st  = &p_rarch->menu_driver_state;
10141 
10142    if (string_is_empty(str))
10143       goto end;
10144 
10145    /* Determine whether we are currently
10146     * viewing a menu list with 'search
10147     * filter' support */
10148    file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
10149          NULL, &label, &type, NULL);
10150 
10151    /* Do not apply search filter if string
10152     * consists of a single Latin alphabet
10153     * character */
10154    if (((str[1] != '\0') || (!ISALPHA(str[0]))) &&
10155        menu_driver_search_filter_enabled(label, type))
10156    {
10157       /* Add search term */
10158       if (menu_entries_search_push(str))
10159       {
10160          bool refresh = false;
10161 
10162          /* Reset navigation pointer */
10163          menu_st->selection_ptr = 0;
10164          menu_driver_navigation_set(false);
10165 
10166          /* Refresh menu */
10167          menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
10168          menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
10169       }
10170    }
10171    /* Perform a regular search: jump to the
10172     * first matching entry */
10173    else
10174    {
10175       size_t idx = 0;
10176 
10177       if (menu_entries_list_search(str, &idx))
10178       {
10179          menu_st->selection_ptr = idx;
10180          menu_driver_navigation_set(true);
10181       }
10182    }
10183 
10184 end:
10185    menu_input_dialog_end();
10186 }
10187 
menu_input_dialog_get_label_buffer(void)10188 const char *menu_input_dialog_get_label_buffer(void)
10189 {
10190    struct rarch_state *p_rarch                           = &rarch_st;
10191    return p_rarch->menu_input_dialog_keyboard_label;
10192 }
10193 
menu_input_dialog_get_label_setting_buffer(void)10194 const char *menu_input_dialog_get_label_setting_buffer(void)
10195 {
10196    struct rarch_state *p_rarch                           = &rarch_st;
10197    return p_rarch->menu_input_dialog_keyboard_label_setting;
10198 }
10199 
menu_input_dialog_end(void)10200 void menu_input_dialog_end(void)
10201 {
10202    struct rarch_state *p_rarch                           = &rarch_st;
10203    p_rarch->menu_input_dialog_keyboard_type              = 0;
10204    p_rarch->menu_input_dialog_keyboard_idx               = 0;
10205    p_rarch->menu_input_dialog_keyboard_display           = false;
10206    p_rarch->menu_input_dialog_keyboard_label[0]          = '\0';
10207    p_rarch->menu_input_dialog_keyboard_label_setting[0]  = '\0';
10208 
10209    /* Avoid triggering states on pressing return. */
10210    /* Inhibits input for 2 frames
10211     * > Required, since input is ignored for 1 frame
10212     *   after certain events - e.g. closing the OSK */
10213    p_rarch->input_driver_flushing_input                  = 2;
10214 }
10215 
menu_input_dialog_get_buffer(void)10216 const char *menu_input_dialog_get_buffer(void)
10217 {
10218    struct rarch_state *p_rarch = &rarch_st;
10219    if (!(*p_rarch->menu_input_dialog_keyboard_buffer))
10220       return "";
10221    return *p_rarch->menu_input_dialog_keyboard_buffer;
10222 }
10223 
menu_input_dialog_get_kb_idx(void)10224 unsigned menu_input_dialog_get_kb_idx(void)
10225 {
10226    struct rarch_state *p_rarch = &rarch_st;
10227    return p_rarch->menu_input_dialog_keyboard_idx;
10228 }
10229 
menu_input_dialog_start_search(void)10230 bool menu_input_dialog_start_search(void)
10231 {
10232    struct rarch_state *p_rarch = &rarch_st;
10233 #ifdef HAVE_ACCESSIBILITY
10234    settings_t *settings        = p_rarch->configuration_settings;
10235    bool accessibility_enable   = settings->bools.accessibility_enable;
10236    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
10237 #endif
10238    menu_handle_t         *menu = p_rarch->menu_driver_data;
10239 
10240    if (!menu)
10241       return false;
10242 
10243    p_rarch->menu_input_dialog_keyboard_display = true;
10244    strlcpy(p_rarch->menu_input_dialog_keyboard_label,
10245          msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SEARCH),
10246          sizeof(p_rarch->menu_input_dialog_keyboard_label));
10247 
10248    if (p_rarch->keyboard_line.buffer)
10249       free(p_rarch->keyboard_line.buffer);
10250    p_rarch->keyboard_line.buffer                    = NULL;
10251    p_rarch->keyboard_line.ptr                       = 0;
10252    p_rarch->keyboard_line.size                      = 0;
10253    p_rarch->keyboard_line.cb                        = NULL;
10254    p_rarch->keyboard_line.userdata                  = NULL;
10255    p_rarch->keyboard_line.enabled                   = false;
10256 
10257 #ifdef HAVE_ACCESSIBILITY
10258    if (is_accessibility_enabled(
10259             accessibility_enable,
10260             p_rarch->accessibility_enabled))
10261          accessibility_speak_priority(p_rarch,
10262             accessibility_enable,
10263             accessibility_narrator_speech_speed,
10264             (char*)msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SEARCH), 10);
10265 #endif
10266 
10267    p_rarch->menu_input_dialog_keyboard_buffer   =
10268       input_keyboard_start_line(menu,
10269             &p_rarch->keyboard_line,
10270             menu_input_search_cb);
10271    /* While reading keyboard line input, we have to block all hotkeys. */
10272    p_rarch->keyboard_mapping_blocked= true;
10273 
10274    return true;
10275 }
10276 
menu_input_dialog_start(menu_input_ctx_line_t * line)10277 bool menu_input_dialog_start(menu_input_ctx_line_t *line)
10278 {
10279    struct rarch_state *p_rarch = &rarch_st;
10280 #ifdef HAVE_ACCESSIBILITY
10281    settings_t *settings        = p_rarch->configuration_settings;
10282    bool accessibility_enable   = settings->bools.accessibility_enable;
10283    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
10284 #endif
10285    menu_handle_t         *menu = p_rarch->menu_driver_data;
10286    if (!line || !menu)
10287       return false;
10288 
10289    p_rarch->menu_input_dialog_keyboard_display = true;
10290 
10291    /* Only copy over the menu label and setting if they exist. */
10292    if (line->label)
10293       strlcpy(p_rarch->menu_input_dialog_keyboard_label,
10294             line->label,
10295             sizeof(p_rarch->menu_input_dialog_keyboard_label));
10296    if (line->label_setting)
10297       strlcpy(p_rarch->menu_input_dialog_keyboard_label_setting,
10298             line->label_setting,
10299             sizeof(p_rarch->menu_input_dialog_keyboard_label_setting));
10300 
10301    p_rarch->menu_input_dialog_keyboard_type   = line->type;
10302    p_rarch->menu_input_dialog_keyboard_idx    = line->idx;
10303 
10304    if (p_rarch->keyboard_line.buffer)
10305       free(p_rarch->keyboard_line.buffer);
10306    p_rarch->keyboard_line.buffer                    = NULL;
10307    p_rarch->keyboard_line.ptr                       = 0;
10308    p_rarch->keyboard_line.size                      = 0;
10309    p_rarch->keyboard_line.cb                        = NULL;
10310    p_rarch->keyboard_line.userdata                  = NULL;
10311    p_rarch->keyboard_line.enabled                   = false;
10312 
10313 #ifdef HAVE_ACCESSIBILITY
10314    if (is_accessibility_enabled(
10315             accessibility_enable,
10316             p_rarch->accessibility_enabled))
10317       accessibility_speak_priority(p_rarch,
10318             accessibility_enable,
10319             accessibility_narrator_speech_speed,
10320             "Keyboard input:", 10);
10321 #endif
10322 
10323    p_rarch->menu_input_dialog_keyboard_buffer =
10324       input_keyboard_start_line(menu,
10325             &p_rarch->keyboard_line,
10326             line->cb);
10327    /* While reading keyboard line input, we have to block all hotkeys. */
10328    p_rarch->keyboard_mapping_blocked= true;
10329 
10330    return true;
10331 }
10332 
menu_input_dialog_get_display_kb(void)10333 bool menu_input_dialog_get_display_kb(void)
10334 {
10335    struct rarch_state *p_rarch = &rarch_st;
10336 #ifdef HAVE_LIBNX
10337    SwkbdConfig kbd;
10338    Result rc;
10339    /* Indicates that we are "typing" from the swkbd
10340     * result to RetroArch with repeated calls to input_keyboard_event
10341     * This prevents input_keyboard_event from calling back
10342     * menu_input_dialog_get_display_kb, looping indefinintely */
10343    static bool typing = false;
10344 
10345    if (typing)
10346       return false;
10347 
10348 
10349    /* swkbd only works on "real" titles */
10350    if (     __nx_applet_type != AppletType_Application
10351          && __nx_applet_type != AppletType_SystemApplication)
10352       return p_rarch->menu_input_dialog_keyboard_display;
10353 
10354    if (!p_rarch->menu_input_dialog_keyboard_display)
10355       return false;
10356 
10357    rc = swkbdCreate(&kbd, 0);
10358 
10359    if (R_SUCCEEDED(rc))
10360    {
10361       unsigned i;
10362       char buf[LIBNX_SWKBD_LIMIT] = {'\0'};
10363       swkbdConfigMakePresetDefault(&kbd);
10364 
10365       swkbdConfigSetGuideText(&kbd,
10366             p_rarch->menu_input_dialog_keyboard_label);
10367 
10368       rc = swkbdShow(&kbd, buf, sizeof(buf));
10369 
10370       swkbdClose(&kbd);
10371 
10372       /* RetroArch uses key-by-key input
10373          so we need to simulate it */
10374       typing = true;
10375       for (i = 0; i < LIBNX_SWKBD_LIMIT; i++)
10376       {
10377          /* In case a previous "Enter" press closed the keyboard */
10378          if (!p_rarch->menu_input_dialog_keyboard_display)
10379             break;
10380 
10381          if (buf[i] == '\n' || buf[i] == '\0')
10382             input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
10383          else
10384          {
10385             const char *word = &buf[i];
10386             /* input_keyboard_line_append expects a null-terminated
10387                string, so just make one (yes, the touch keyboard is
10388                a list of "null-terminated characters") */
10389             char oldchar     = buf[i+1];
10390             buf[i+1]         = '\0';
10391 
10392             input_keyboard_line_append(&p_rarch->keyboard_line, word);
10393 
10394             if (word[0] == 0)
10395             {
10396                p_rarch->osk_last_codepoint       = 0;
10397                p_rarch->osk_last_codepoint_len   = 0;
10398             }
10399             else
10400                osk_update_last_codepoint(
10401                      &p_rarch->osk_last_codepoint,
10402                      &p_rarch->osk_last_codepoint_len,
10403                      word);
10404             buf[i+1]     = oldchar;
10405          }
10406       }
10407 
10408       /* fail-safe */
10409       if (p_rarch->menu_input_dialog_keyboard_display)
10410          input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
10411 
10412       typing = false;
10413       libnx_apply_overclock();
10414       return false;
10415    }
10416    libnx_apply_overclock();
10417 #endif
10418    return p_rarch->menu_input_dialog_keyboard_display;
10419 }
10420 
10421 /* Checks if the menu is still running */
menu_driver_is_alive(void)10422 bool menu_driver_is_alive(void)
10423 {
10424    struct rarch_state *p_rarch = &rarch_st;
10425    return p_rarch->menu_driver_alive;
10426 }
10427 #endif
10428 
10429 /* MESSAGE QUEUE */
10430 
retroarch_msg_queue_deinit(void)10431 static void retroarch_msg_queue_deinit(void)
10432 {
10433    RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
10434 
10435    msg_queue_deinitialize(&runloop_state.msg_queue);
10436 
10437    RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
10438 #ifdef HAVE_THREADS
10439    slock_free(runloop_state.msg_queue_lock);
10440    runloop_state.msg_queue_lock = NULL;
10441 #endif
10442 
10443    runloop_state.msg_queue_size = 0;
10444 }
10445 
retroarch_msg_queue_init(void)10446 static void retroarch_msg_queue_init(void)
10447 {
10448    retroarch_msg_queue_deinit();
10449    msg_queue_initialize(&runloop_state.msg_queue, 8);
10450 
10451 #ifdef HAVE_THREADS
10452    runloop_state.msg_queue_lock   = slock_new();
10453 #endif
10454 }
10455 
10456 #ifdef HAVE_THREADS
retroarch_autosave_deinit(struct rarch_state * p_rarch)10457 static void retroarch_autosave_deinit(struct rarch_state *p_rarch)
10458 {
10459    const bool rarch_use_sram   = p_rarch->rarch_use_sram;
10460    if (rarch_use_sram)
10461       autosave_deinit();
10462 }
10463 #endif
10464 
10465 /* COMMAND */
10466 
10467 #ifdef HAVE_COMMAND
10468 
command_version(command_t * cmd,const char * arg)10469 bool command_version(command_t *cmd, const char* arg)
10470 {
10471    char reply[256]             = {0};
10472 
10473    snprintf(reply, sizeof(reply), "%s\n", PACKAGE_VERSION);
10474    cmd->replier(cmd, reply, strlen(reply));
10475 
10476    return true;
10477 }
10478 
command_get_status(command_t * cmd,const char * arg)10479 bool command_get_status(command_t *cmd, const char* arg)
10480 {
10481    char reply[4096]            = {0};
10482    bool contentless            = false;
10483    bool is_inited              = false;
10484 
10485    content_get_status(&contentless, &is_inited);
10486 
10487    if (!is_inited)
10488        strcpy_literal(reply, "GET_STATUS CONTENTLESS");
10489    else
10490    {
10491        /* add some content info */
10492        const char *status       = "PLAYING";
10493        const char *content_name = path_basename(path_get(RARCH_PATH_BASENAME));  /* filename only without ext */
10494        int content_crc32        = content_get_crc();
10495        const char* system_id    = NULL;
10496        core_info_t *core_info   = NULL;
10497 
10498        core_info_get_current_core(&core_info);
10499 
10500        if (runloop_state.paused)
10501           status                = "PAUSED";
10502        if (core_info)
10503           system_id             = core_info->system_id;
10504        if (!system_id)
10505           system_id             = runloop_state.system.info.library_name;
10506 
10507        snprintf(reply, sizeof(reply), "GET_STATUS %s %s,%s,crc32=%x\n", status, system_id, content_name, content_crc32);
10508    }
10509 
10510    cmd->replier(cmd, reply, strlen(reply));
10511 
10512    return true;
10513 }
10514 
command_show_osd_msg(command_t * cmd,const char * arg)10515 bool command_show_osd_msg(command_t *cmd, const char* arg)
10516 {
10517     runloop_msg_queue_push(arg, 1, 180, false, NULL,
10518           MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
10519     return true;
10520 }
10521 
command_get_config_param(command_t * cmd,const char * arg)10522 bool command_get_config_param(command_t *cmd, const char* arg)
10523 {
10524    char reply[8192]             = {0};
10525    struct rarch_state  *p_rarch = &rarch_st;
10526    const char      *value       = "unsupported";
10527    settings_t       *settings   = p_rarch->configuration_settings;
10528    bool       video_fullscreen  = settings->bools.video_fullscreen;
10529    const char *dir_runtime_log  = settings->paths.directory_runtime_log;
10530    const char *log_dir          = settings->paths.log_dir;
10531    const char *directory_cache  = settings->paths.directory_cache;
10532    const char *directory_system = settings->paths.directory_system;
10533    const char *path_username    = settings->paths.username;
10534 
10535    if (string_is_equal(arg, "video_fullscreen"))
10536    {
10537       if (video_fullscreen)
10538          value = "true";
10539       else
10540          value = "false";
10541    }
10542    else if (string_is_equal(arg, "savefile_directory"))
10543       value = p_rarch->dir_savefile;
10544    else if (string_is_equal(arg, "savestate_directory"))
10545       value = p_rarch->dir_savestate;
10546    else if (string_is_equal(arg, "runtime_log_directory"))
10547       value = dir_runtime_log;
10548    else if (string_is_equal(arg, "log_dir"))
10549       value = log_dir;
10550    else if (string_is_equal(arg, "cache_directory"))
10551       value = directory_cache;
10552    else if (string_is_equal(arg, "system_directory"))
10553       value = directory_system;
10554    else if (string_is_equal(arg, "netplay_nickname"))
10555       value = path_username;
10556    /* TODO: query any string */
10557 
10558    snprintf(reply, sizeof(reply), "GET_CONFIG_PARAM %s %s\n", arg, value);
10559    cmd->replier(cmd, reply, strlen(reply));
10560    return true;
10561 }
10562 
10563 #if defined(HAVE_CHEEVOS)
command_read_ram(command_t * cmd,const char * arg)10564 bool command_read_ram(command_t *cmd, const char *arg)
10565 {
10566    unsigned i;
10567    char *reply                  = NULL;
10568    const uint8_t  *data         = NULL;
10569    char *reply_at               = NULL;
10570    unsigned int nbytes          = 0;
10571    unsigned int alloc_size      = 0;
10572    unsigned int addr            = -1;
10573    unsigned int len             = 0;
10574 
10575    if (sscanf(arg, "%x %u", &addr, &nbytes) != 2)
10576       return true;
10577    /* We allocate more than needed, saving 20 bytes is not really relevant */
10578    alloc_size              = 40 + nbytes * 3;
10579    reply                   = (char*)malloc(alloc_size);
10580    reply[0]                = '\0';
10581    reply_at                = reply + snprintf(
10582          reply, alloc_size - 1, "READ_CORE_RAM" " %x", addr);
10583 
10584    if ((data = rcheevos_patch_address(addr)))
10585    {
10586       for (i = 0; i < nbytes; i++)
10587          snprintf(reply_at + 3 * i, 4, " %.2X", data[i]);
10588       reply_at[3 * nbytes] = '\n';
10589       len                  = reply_at + 3 * nbytes + 1 - reply;
10590    }
10591    else
10592    {
10593       strlcpy(reply_at, " -1\n", sizeof(reply) - strlen(reply));
10594       len                  = reply_at + STRLEN_CONST(" -1\n") - reply;
10595    }
10596    cmd->replier(cmd, reply, len);
10597    free(reply);
10598    return true;
10599 }
10600 
command_write_ram(command_t * cmd,const char * arg)10601 bool command_write_ram(command_t *cmd, const char *arg)
10602 {
10603    unsigned int addr    = (unsigned int)strtoul(arg, (char**)&arg, 16);
10604    uint8_t *data        = (uint8_t *)rcheevos_patch_address(addr);
10605 
10606    if (!data)
10607       return false;
10608 
10609    if (rcheevos_hardcore_active())
10610    {
10611       RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_RAM\n");
10612       rcheevos_pause_hardcore();
10613    }
10614 
10615    while (*arg)
10616    {
10617       *data = strtoul(arg, (char**)&arg, 16);
10618       data++;
10619    }
10620    return true;
10621 }
10622 #endif
10623 
command_memory_get_descriptor(const rarch_memory_map_t * mmap,unsigned address)10624 static const rarch_memory_descriptor_t* command_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned address)
10625 {
10626    const rarch_memory_descriptor_t* desc = mmap->descriptors;
10627    const rarch_memory_descriptor_t* end  = desc + mmap->num_descriptors;
10628 
10629    for (; desc < end; desc++)
10630    {
10631       if (desc->core.select == 0)
10632       {
10633          /* if select is 0, attempt to explicitly match the address */
10634          if (address >= desc->core.start && address < desc->core.start + desc->core.len)
10635             return desc;
10636       }
10637       else
10638       {
10639          /* otherwise, attempt to match the address by matching the select bits */
10640          if (((desc->core.start ^ address) & desc->core.select) == 0)
10641          {
10642             /* sanity check - make sure the descriptor is large enough to hold the target address */
10643             if (address - desc->core.start < desc->core.len)
10644                return desc;
10645          }
10646       }
10647    }
10648 
10649    return NULL;
10650 }
10651 
command_memory_get_pointer(unsigned address,unsigned int * max_bytes,int for_write,char * reply_at,size_t len)10652 static uint8_t* command_memory_get_pointer(unsigned address,
10653       unsigned int* max_bytes, int for_write, char* reply_at, size_t len)
10654 {
10655    const rarch_system_info_t* system = &runloop_state.system;
10656    if (!system || system->mmaps.num_descriptors == 0)
10657       strlcpy(reply_at, " -1 no memory map defined\n", len);
10658    else
10659    {
10660       const rarch_memory_descriptor_t* desc = command_memory_get_descriptor(&system->mmaps, address);
10661       if (!desc)
10662          strlcpy(reply_at, " -1 no descriptor for address\n", len);
10663       else if (!desc->core.ptr)
10664          strlcpy(reply_at, " -1 no data for descriptor\n", len);
10665       else if (for_write && (desc->core.flags & RETRO_MEMDESC_CONST))
10666          strlcpy(reply_at, " -1 descriptor data is readonly\n", len);
10667       else
10668       {
10669          const size_t offset = address - desc->core.start;
10670          *max_bytes = (desc->core.len - offset);
10671          return (uint8_t*)desc->core.ptr + desc->core.offset + offset;
10672       }
10673    }
10674 
10675    *max_bytes = 0;
10676    return NULL;
10677 }
10678 
command_read_memory(command_t * cmd,const char * arg)10679 bool command_read_memory(command_t *cmd, const char *arg)
10680 {
10681    unsigned i;
10682    char* reply                  = NULL;
10683    char* reply_at               = NULL;
10684    const uint8_t* data          = NULL;
10685    unsigned int nbytes          = 0;
10686    unsigned int alloc_size      = 0;
10687    unsigned int address         = -1;
10688    unsigned int len             = 0;
10689    unsigned int max_bytes       = 0;
10690 
10691    if (sscanf(arg, "%x %u", &address, &nbytes) != 2)
10692       return false;
10693 
10694    /* Ensure large enough to return all requested bytes or an error message */
10695    alloc_size = 64 + nbytes * 3;
10696    reply      = (char*)malloc(alloc_size);
10697    reply_at   = reply + snprintf(reply, alloc_size - 1, "READ_CORE_MEMORY %x", address);
10698 
10699    data       = command_memory_get_pointer(address, &max_bytes, 0, reply_at, alloc_size - strlen(reply));
10700 
10701    if (data)
10702    {
10703       if (nbytes > max_bytes)
10704           nbytes = max_bytes;
10705 
10706       for (i = 0; i < nbytes; i++)
10707          snprintf(reply_at + 3 * i, 4, " %02X", data[i]);
10708 
10709       reply_at[3 * nbytes] = '\n';
10710       len                  = reply_at + 3 * nbytes + 1 - reply;
10711    }
10712    else
10713       len                  = strlen(reply);
10714 
10715    cmd->replier(cmd, reply, len);
10716    free(reply);
10717    return true;
10718 }
10719 
command_write_memory(command_t * cmd,const char * arg)10720 bool command_write_memory(command_t *cmd, const char *arg)
10721 {
10722    unsigned int address         = (unsigned int)strtoul(arg, (char**)&arg, 16);
10723    unsigned int max_bytes       = 0;
10724    char reply[128]              = "";
10725    char *reply_at               = reply + snprintf(reply, sizeof(reply) - 1, "WRITE_CORE_MEMORY %x", address);
10726    uint8_t *data                = command_memory_get_pointer(address, &max_bytes, 1, reply_at, sizeof(reply) - strlen(reply) - 1);
10727 
10728    if (data)
10729    {
10730       uint8_t* start = data;
10731       while (*arg && max_bytes > 0)
10732       {
10733          --max_bytes;
10734          *data = strtoul(arg, (char**)&arg, 16);
10735          data++;
10736       }
10737 
10738       snprintf(reply_at, sizeof(reply) - strlen(reply) - 1,
10739             " %u\n", (unsigned)(data - start));
10740 
10741 #ifdef HAVE_CHEEVOS
10742       if (rcheevos_hardcore_active())
10743       {
10744          RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_MEMORY\n");
10745          rcheevos_pause_hardcore();
10746       }
10747 #endif
10748    }
10749 
10750    cmd->replier(cmd, reply, strlen(reply));
10751    return true;
10752 }
10753 #endif
10754 
retroarch_apply_shader(struct rarch_state * p_rarch,settings_t * settings,enum rarch_shader_type type,const char * preset_path,bool message)10755 static bool retroarch_apply_shader(
10756       struct rarch_state *p_rarch,
10757       settings_t *settings,
10758       enum rarch_shader_type type,
10759       const char *preset_path, bool message)
10760 {
10761 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
10762    char msg[256];
10763    const char      *core_name   = runloop_state.system.info.library_name;
10764    const char      *preset_file = NULL;
10765 #ifdef HAVE_MENU
10766    struct video_shader *shader  = menu_shader_get();
10767 #endif
10768 
10769    /* Disallow loading shaders when no core is loaded */
10770    if (string_is_empty(core_name))
10771       return false;
10772 
10773    if (!string_is_empty(preset_path))
10774       preset_file = path_basename_nocompression(preset_path);
10775 
10776    /* TODO/FIXME - This loads the shader into the video driver
10777     * But then we load the shader from disk twice more to put it in the menu
10778     * We need to reconfigure this at some point to only load it once */
10779    if (p_rarch->current_video->set_shader)
10780    {
10781       if ((p_rarch->current_video->set_shader(
10782                   p_rarch->video_driver_data, type, preset_path)))
10783       {
10784          configuration_set_bool(settings, settings->bools.video_shader_enable, true);
10785          if (!string_is_empty(preset_path))
10786          {
10787             strlcpy(p_rarch->runtime_shader_preset, preset_path,
10788                   sizeof(p_rarch->runtime_shader_preset));
10789 #ifdef HAVE_MENU
10790             /* reflect in shader manager */
10791             if (menu_shader_manager_set_preset(
10792                      shader, type, preset_path, false))
10793                shader->modified = false;
10794 #endif
10795          }
10796          else
10797             p_rarch->runtime_shader_preset[0] = '\0';
10798 
10799          if (message)
10800          {
10801             /* Display message */
10802             if (preset_file)
10803                snprintf(msg, sizeof(msg),
10804                      "%s: \"%s\"",
10805                      msg_hash_to_str(MSG_SHADER),
10806                      preset_file);
10807             else
10808                snprintf(msg, sizeof(msg),
10809                      "%s: %s",
10810                      msg_hash_to_str(MSG_SHADER),
10811                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE)
10812                      );
10813 #ifdef HAVE_GFX_WIDGETS
10814             if (p_rarch->widgets_active)
10815                gfx_widget_set_generic_message(&p_rarch->dispwidget_st,
10816                      msg, 2000);
10817             else
10818 #endif
10819                runloop_msg_queue_push(msg, 1, 120, true, NULL,
10820                      MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
10821          }
10822 
10823          RARCH_LOG("%s \"%s\".\n",
10824                msg_hash_to_str(MSG_APPLYING_SHADER),
10825                preset_path ? preset_path : "null");
10826 
10827          return true;
10828       }
10829    }
10830 
10831 #ifdef HAVE_MENU
10832    /* reflect in shader manager */
10833    menu_shader_manager_set_preset(shader, type, NULL, false);
10834 #endif
10835 
10836    /* Display error message */
10837    fill_pathname_join_delim(msg,
10838          msg_hash_to_str(MSG_FAILED_TO_APPLY_SHADER_PRESET),
10839          preset_file ? preset_file : "null",
10840          ' ',
10841          sizeof(msg));
10842 
10843    runloop_msg_queue_push(
10844          msg, 1, 180, true, NULL,
10845          MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
10846 #endif
10847    return false;
10848 }
10849 
10850 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
command_set_shader(command_t * cmd,const char * arg)10851 bool command_set_shader(command_t *cmd, const char *arg)
10852 {
10853    enum  rarch_shader_type type = video_shader_parse_type(arg);
10854    struct rarch_state  *p_rarch = &rarch_st;
10855    settings_t  *settings        = p_rarch->configuration_settings;
10856 
10857    if (!string_is_empty(arg))
10858    {
10859       if (!video_shader_is_supported(type))
10860          return false;
10861 
10862       /* rebase on shader directory */
10863       if (!path_is_absolute(arg))
10864       {
10865          static char abs_arg[PATH_MAX_LENGTH];
10866          const char *ref_path = settings->paths.directory_video_shader;
10867          fill_pathname_join(abs_arg,
10868                ref_path, arg, sizeof(abs_arg));
10869          /* TODO/FIXME - pointer to local variable -
10870           * making abs_arg static for now to workaround this
10871           */
10872          arg = abs_arg;
10873       }
10874    }
10875 
10876    return retroarch_apply_shader(p_rarch, settings, type, arg, true);
10877 }
10878 #endif
10879 
10880 /* TRANSLATION */
10881 #ifdef HAVE_TRANSLATE
task_auto_translate_callback(void)10882 static bool task_auto_translate_callback(void)
10883 {
10884    bool was_paused                   = runloop_state.paused;
10885    command_event(CMD_EVENT_AI_SERVICE_CALL, &was_paused);
10886    return true;
10887 }
10888 
10889 /* TODO/FIXME - Doesn't currently work.  Fix this. */
is_ai_service_speech_running(void)10890 static bool is_ai_service_speech_running(void)
10891 {
10892 #ifdef HAVE_AUDIOMIXER
10893    enum audio_mixer_state res = audio_driver_mixer_get_stream_state(10);
10894    bool ret = (res == AUDIO_STREAM_STATE_NONE) || (res == AUDIO_STREAM_STATE_STOPPED);
10895    if (!ret)
10896       return true;
10897 #endif
10898    return false;
10899 }
10900 
task_auto_translate_handler(retro_task_t * task)10901 static void task_auto_translate_handler(retro_task_t *task)
10902 {
10903    int               *mode_ptr = (int*)task->user_data;
10904    struct rarch_state *p_rarch = &rarch_st;
10905 #ifdef HAVE_ACCESSIBILITY
10906    settings_t *settings        = p_rarch->configuration_settings;
10907 #endif
10908 
10909    if (task_get_cancelled(task))
10910       goto task_finished;
10911 
10912    switch (*mode_ptr)
10913    {
10914       case 1: /* Speech   Mode */
10915 #ifdef HAVE_AUDIOMIXER
10916          if (!is_ai_service_speech_running())
10917             goto task_finished;
10918 #endif
10919          break;
10920       case 2: /* Narrator Mode */
10921 #ifdef HAVE_ACCESSIBILITY
10922          if (!is_narrator_running(p_rarch, settings->bools.accessibility_enable))
10923             goto task_finished;
10924 #endif
10925          break;
10926       default:
10927          break;
10928    }
10929 
10930    return;
10931 
10932 task_finished:
10933    if (p_rarch->ai_service_auto == 1)
10934       p_rarch->ai_service_auto = 2;
10935 
10936    task_set_finished(task, true);
10937 
10938    if (*mode_ptr == 1 || *mode_ptr == 2)
10939        task_auto_translate_callback();
10940    if (task->user_data)
10941        free(task->user_data);
10942 }
10943 
call_auto_translate_task(struct rarch_state * p_rarch,settings_t * settings,bool * was_paused)10944 static void call_auto_translate_task(
10945       struct rarch_state *p_rarch,
10946       settings_t *settings,
10947       bool *was_paused)
10948 {
10949    int ai_service_mode  = settings->uints.ai_service_mode;
10950 
10951    /*Image Mode*/
10952    if (ai_service_mode == 0)
10953    {
10954       if (p_rarch->ai_service_auto == 1)
10955          p_rarch->ai_service_auto = 2;
10956 
10957       command_event(CMD_EVENT_AI_SERVICE_CALL, was_paused);
10958    }
10959    else /* Speech or Narrator Mode */
10960    {
10961       int* mode                          = NULL;
10962       retro_task_t  *t                   = task_init();
10963       if (!t)
10964          return;
10965 
10966       mode                               = (int*)malloc(sizeof(int));
10967       *mode                              = ai_service_mode;
10968 
10969       t->handler                         = task_auto_translate_handler;
10970       t->user_data                       = mode;
10971       t->mute                            = true;
10972       task_queue_push(t);
10973    }
10974 }
10975 
handle_translation_cb(retro_task_t * task,void * task_data,void * user_data,const char * error)10976 static void handle_translation_cb(
10977       retro_task_t *task, void *task_data,
10978       void *user_data, const char *error)
10979 {
10980    size_t pitch;
10981    unsigned width, height;
10982    unsigned image_width, image_height;
10983    uint8_t* raw_output_data          = NULL;
10984    char* raw_image_file_data         = NULL;
10985    struct scaler_ctx* scaler         = NULL;
10986    http_transfer_data_t *data        = (http_transfer_data_t*)task_data;
10987    int new_image_size                = 0;
10988 #ifdef HAVE_AUDIOMIXER
10989    int new_sound_size                = 0;
10990 #endif
10991    const void* dummy_data            = NULL;
10992    void* raw_image_data              = NULL;
10993    void* raw_image_data_alpha        = NULL;
10994    void* raw_sound_data              = NULL;
10995    int retval                        = 0;
10996    rjson_t* json                     = NULL;
10997    int json_current_key              = 0;
10998    char* err_string                  = NULL;
10999    char* text_string                 = NULL;
11000    char* auto_string                 = NULL;
11001    char* key_string                  = NULL;
11002    struct rarch_state *p_rarch       = &rarch_st;
11003    settings_t* settings              = p_rarch->configuration_settings;
11004    bool was_paused                   = runloop_state.paused;
11005    const enum retro_pixel_format
11006       video_driver_pix_fmt           = p_rarch->video_driver_pix_fmt;
11007 #ifdef HAVE_ACCESSIBILITY
11008    bool accessibility_enable         = settings->bools.accessibility_enable;
11009    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
11010 #endif
11011 #ifdef HAVE_GFX_WIDGETS
11012    bool gfx_widgets_paused           = p_rarch->gfx_widgets_paused;
11013 
11014    /* When auto mode is on, we turn off the overlay
11015     * once we have the result for the next call.*/
11016    if (p_rarch->dispwidget_st.ai_service_overlay_state != 0
11017        && p_rarch->ai_service_auto == 2)
11018       gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
11019 #endif
11020 
11021 #ifdef DEBUG
11022    if (p_rarch->ai_service_auto != 2)
11023       RARCH_LOG("RESULT FROM AI SERVICE...\n");
11024 #endif
11025 
11026    if (!data || error || !data->data)
11027       goto finish;
11028 
11029    json = rjson_open_buffer(data->data, data->len);
11030    if (!json)
11031       goto finish;
11032 
11033    /* Parse JSON body for the image and sound data */
11034    for (;;)
11035    {
11036       static const char* keys[] = { "image", "sound", "text", "error", "auto", "press" };
11037 
11038       const char *str           = NULL;
11039       size_t str_len            = 0;
11040       enum rjson_type json_type = rjson_next(json);
11041 
11042       if (json_type == RJSON_DONE || json_type == RJSON_ERROR)
11043          break;
11044       if (json_type != RJSON_STRING)
11045          continue;
11046       if (rjson_get_context_type(json) != RJSON_OBJECT)
11047          continue;
11048       str                       = rjson_get_string(json, &str_len);
11049 
11050       if ((rjson_get_context_count(json) & 1) == 1)
11051       {
11052          int i;
11053          json_current_key = -1;
11054 
11055          for (i = 0; i < ARRAY_SIZE(keys); i++)
11056          {
11057             if (string_is_equal(str, keys[i]))
11058             {
11059                json_current_key = i;
11060                break;
11061             }
11062          }
11063       }
11064       else
11065       {
11066          switch (json_current_key)
11067          {
11068             case 0: /* image */
11069                raw_image_file_data = (char*)unbase64(str,
11070                     (int)str_len, &new_image_size);
11071                break;
11072 #ifdef HAVE_AUDIOMIXER
11073             case 1: /* sound */
11074                raw_sound_data = (void*)unbase64(str,
11075                     (int)str_len, &new_sound_size);
11076                break;
11077 #endif
11078             case 2: /* text */
11079                text_string = strdup(str);
11080                break;
11081             case 3: /* error */
11082                err_string  = strdup(str);
11083                break;
11084             case 4: /* auto */
11085                auto_string = strdup(str);
11086                break;
11087             case 5: /* press */
11088                key_string  = strdup(str);
11089                break;
11090          }
11091          json_current_key = -1;
11092       }
11093    }
11094 
11095    if (string_is_equal(err_string, "No text found."))
11096    {
11097 #ifdef DEBUG
11098       RARCH_LOG("No text found...\n");
11099 #endif
11100       if (text_string)
11101       {
11102          free(text_string);
11103          text_string = NULL;
11104       }
11105 
11106       text_string = (char*)malloc(15);
11107 
11108       strlcpy(text_string, err_string, 15);
11109 #ifdef HAVE_GFX_WIDGETS
11110       if (gfx_widgets_paused)
11111       {
11112          /* In this case we have to unpause and then repause for a frame */
11113          p_rarch->dispwidget_st.ai_service_overlay_state = 2;
11114          command_event(CMD_EVENT_UNPAUSE, NULL);
11115       }
11116 #endif
11117    }
11118 
11119    if (     !raw_image_file_data
11120          && !raw_sound_data
11121          && !text_string
11122          && (p_rarch->ai_service_auto != 2)
11123          && !key_string)
11124    {
11125       error = "Invalid JSON body.";
11126       goto finish;
11127    }
11128 
11129    if (raw_image_file_data)
11130    {
11131       /* Get the video frame dimensions reference */
11132       video_driver_cached_frame_get(&dummy_data, &width, &height, &pitch);
11133 
11134       /* try two different modes for text display *
11135        * In the first mode, we use display widget overlays, but they require
11136        * the video poke interface to be able to load image buffers.
11137        *
11138        * The other method is to draw to the video buffer directly, which needs
11139        * a software core to be running. */
11140 #ifdef HAVE_GFX_WIDGETS
11141       if (p_rarch->video_driver_poke
11142           && p_rarch->video_driver_poke->load_texture
11143           && p_rarch->video_driver_poke->unload_texture)
11144       {
11145          bool ai_res;
11146          enum image_type_enum image_type;
11147          /* Write to overlay */
11148          if (  raw_image_file_data[0] == 'B' &&
11149                raw_image_file_data[1] == 'M')
11150              image_type = IMAGE_TYPE_BMP;
11151          else if (raw_image_file_data[1] == 'P' &&
11152                   raw_image_file_data[2] == 'N' &&
11153                   raw_image_file_data[3] == 'G')
11154             image_type = IMAGE_TYPE_PNG;
11155          else
11156          {
11157             RARCH_LOG("Invalid image type returned from server.\n");
11158             goto finish;
11159          }
11160 
11161          ai_res = gfx_widgets_ai_service_overlay_load(
11162                &p_rarch->dispwidget_st,
11163                raw_image_file_data, (unsigned)new_image_size,
11164                image_type);
11165 
11166          if (!ai_res)
11167          {
11168             RARCH_LOG("Video driver not supported for AI Service.");
11169             runloop_msg_queue_push(
11170                /* msg_hash_to_str(MSG_VIDEO_DRIVER_NOT_SUPPORTED), */
11171                "Video driver not supported.",
11172                1, 180, true,
11173                NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
11174          }
11175          else if (gfx_widgets_paused)
11176          {
11177             /* In this case we have to unpause and then repause for a frame */
11178 #ifdef HAVE_TRANSLATE
11179             /* Unpausing state */
11180             p_rarch->dispwidget_st.ai_service_overlay_state = 2;
11181 #endif
11182             command_event(CMD_EVENT_UNPAUSE, NULL);
11183          }
11184       }
11185       else
11186 #endif
11187       /* Can't use display widget overlays, so try writing to video buffer */
11188       {
11189          /* Write to video buffer directly (software cores only) */
11190          if (raw_image_file_data[0] == 'B' && raw_image_file_data[1] == 'M')
11191          {
11192             /* This is a BMP file coming back. */
11193             /* Get image data (24 bit), and convert to the emulated pixel format */
11194             image_width    =
11195                ((uint32_t) ((uint8_t)raw_image_file_data[21]) << 24) +
11196                ((uint32_t) ((uint8_t)raw_image_file_data[20]) << 16) +
11197                ((uint32_t) ((uint8_t)raw_image_file_data[19]) << 8) +
11198                ((uint32_t) ((uint8_t)raw_image_file_data[18]) << 0);
11199 
11200             image_height   =
11201                ((uint32_t) ((uint8_t)raw_image_file_data[25]) << 24) +
11202                ((uint32_t) ((uint8_t)raw_image_file_data[24]) << 16) +
11203                ((uint32_t) ((uint8_t)raw_image_file_data[23]) << 8) +
11204                ((uint32_t) ((uint8_t)raw_image_file_data[22]) << 0);
11205             raw_image_data = (void*)malloc(image_width*image_height*3*sizeof(uint8_t));
11206             memcpy(raw_image_data,
11207                    raw_image_file_data+54*sizeof(uint8_t),
11208                    image_width*image_height*3*sizeof(uint8_t));
11209          }
11210          else if (raw_image_file_data[1] == 'P' && raw_image_file_data[2] == 'N' &&
11211                   raw_image_file_data[3] == 'G')
11212          {
11213             rpng_t *rpng = NULL;
11214             /* PNG coming back from the url */
11215             image_width  =
11216                 ((uint32_t) ((uint8_t)raw_image_file_data[16]) << 24)+
11217                 ((uint32_t) ((uint8_t)raw_image_file_data[17]) << 16)+
11218                 ((uint32_t) ((uint8_t)raw_image_file_data[18]) << 8)+
11219                 ((uint32_t) ((uint8_t)raw_image_file_data[19]) << 0);
11220             image_height =
11221                 ((uint32_t) ((uint8_t)raw_image_file_data[20]) << 24)+
11222                 ((uint32_t) ((uint8_t)raw_image_file_data[21]) << 16)+
11223                 ((uint32_t) ((uint8_t)raw_image_file_data[22]) << 8)+
11224                 ((uint32_t) ((uint8_t)raw_image_file_data[23]) << 0);
11225             rpng = rpng_alloc();
11226 
11227             if (!rpng)
11228             {
11229                error = "Can't allocate memory.";
11230                goto finish;
11231             }
11232 
11233             rpng_set_buf_ptr(rpng, raw_image_file_data, (size_t)new_image_size);
11234             rpng_start(rpng);
11235             while (rpng_iterate_image(rpng));
11236 
11237             do
11238             {
11239                retval = rpng_process_image(rpng, &raw_image_data_alpha,
11240                      (size_t)new_image_size, &image_width, &image_height);
11241             } while (retval == IMAGE_PROCESS_NEXT);
11242 
11243             /* Returned output from the png processor is an upside down RGBA
11244              * image, so we have to change that to RGB first.  This should
11245              * probably be replaced with a scaler call.*/
11246             {
11247                unsigned ui;
11248                int d,tw,th,tc;
11249                d=0;
11250                raw_image_data = (void*)malloc(image_width*image_height*3*sizeof(uint8_t));
11251                for (ui = 0; ui < image_width * image_height * 4; ui++)
11252                {
11253                   if (ui % 4 != 3)
11254                   {
11255                      tc = d%3;
11256                      th = image_height-d / (3*image_width)-1;
11257                      tw = (d%(image_width*3)) / 3;
11258                      ((uint8_t*) raw_image_data)[tw*3+th*3*image_width+tc] = ((uint8_t *)raw_image_data_alpha)[ui];
11259                      d+=1;
11260                   }
11261                }
11262             }
11263             rpng_free(rpng);
11264          }
11265          else
11266          {
11267             RARCH_LOG("Output from URL not a valid file type, or is not supported.\n");
11268             goto finish;
11269          }
11270 
11271          scaler = (struct scaler_ctx*)calloc(1, sizeof(struct scaler_ctx));
11272          if (!scaler)
11273             goto finish;
11274 
11275          if (dummy_data == RETRO_HW_FRAME_BUFFER_VALID)
11276          {
11277             /*
11278                In this case, we used the viewport to grab the image
11279                and translate it, and we have the translated image in
11280                the raw_image_data buffer.
11281             */
11282             RARCH_LOG("Hardware frame buffer core, but selected video driver isn't supported.\n");
11283             goto finish;
11284          }
11285 
11286          /* The assigned pitch may not be reliable.  The width of
11287             the video frame can change during run-time, but the
11288             pitch may not, so we just assign it as the width
11289             times the byte depth.
11290          */
11291 
11292          if (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
11293          {
11294             raw_output_data    = (uint8_t*)malloc(width * height * 4 * sizeof(uint8_t));
11295             scaler->out_fmt    = SCALER_FMT_ARGB8888;
11296             pitch              = width * 4;
11297             scaler->out_stride = width * 4;
11298          }
11299          else
11300          {
11301             raw_output_data    = (uint8_t*)malloc(width * height * 2 * sizeof(uint8_t));
11302             scaler->out_fmt    = SCALER_FMT_RGB565;
11303             pitch              = width * 2;
11304             scaler->out_stride = width * 1;
11305          }
11306 
11307          if (!raw_output_data)
11308             goto finish;
11309 
11310          scaler->in_fmt        = SCALER_FMT_BGR24;
11311          scaler->in_width      = image_width;
11312          scaler->in_height     = image_height;
11313          scaler->out_width     = width;
11314          scaler->out_height    = height;
11315          scaler->scaler_type   = SCALER_TYPE_POINT;
11316          scaler_ctx_gen_filter(scaler);
11317          scaler->in_stride     = -1 * width * 3;
11318 
11319          scaler_ctx_scale_direct(scaler, raw_output_data,
11320                (uint8_t*)raw_image_data + (image_height - 1) * width * 3);
11321          video_driver_frame(raw_output_data, image_width, image_height, pitch);
11322       }
11323    }
11324 
11325 #ifdef HAVE_AUDIOMIXER
11326    if (raw_sound_data)
11327    {
11328       audio_mixer_stream_params_t params;
11329 
11330       params.volume               = 1.0f;
11331       params.slot_selection_type  = AUDIO_MIXER_SLOT_SELECTION_MANUAL; /* user->slot_selection_type; */
11332       params.slot_selection_idx   = 10;
11333       params.stream_type          = AUDIO_STREAM_TYPE_SYSTEM; /* user->stream_type; */
11334       params.type                 = AUDIO_MIXER_TYPE_WAV;
11335       params.state                = AUDIO_STREAM_STATE_PLAYING;
11336       params.buf                  = raw_sound_data;
11337       params.bufsize              = new_sound_size;
11338       params.cb                   = NULL;
11339       params.basename             = NULL;
11340 
11341       audio_driver_mixer_add_stream(&params);
11342 
11343       if (raw_sound_data)
11344       {
11345          free(raw_sound_data);
11346          raw_sound_data = NULL;
11347       }
11348    }
11349 #endif
11350 
11351    if (key_string)
11352    {
11353       char key[8];
11354       size_t length = strlen(key_string);
11355       int i         = 0;
11356       int start     = 0;
11357       char t        = ' ';
11358 
11359       for (i = 1; i < (int)length; i++)
11360       {
11361          t = key_string[i];
11362          if (i == length-1 || t == ' ' || t == ',')
11363          {
11364             if (i == length-1 && t != ' ' && t!= ',')
11365                i++;
11366 
11367             if (i-start > 7)
11368             {
11369                start = i;
11370                continue;
11371             }
11372 
11373             strncpy(key, key_string+start, i-start);
11374             key[i-start] = '\0';
11375 
11376 #ifdef HAVE_ACCESSIBILITY
11377 #ifdef HAVE_TRANSLATE
11378             if (string_is_equal(key, "b"))
11379                p_rarch->ai_gamepad_state[0] = 2;
11380             if (string_is_equal(key, "y"))
11381                p_rarch->ai_gamepad_state[1] = 2;
11382             if (string_is_equal(key, "select"))
11383                p_rarch->ai_gamepad_state[2] = 2;
11384             if (string_is_equal(key, "start"))
11385                p_rarch->ai_gamepad_state[3] = 2;
11386 
11387             if (string_is_equal(key, "up"))
11388                p_rarch->ai_gamepad_state[4] = 2;
11389             if (string_is_equal(key, "down"))
11390                p_rarch->ai_gamepad_state[5] = 2;
11391             if (string_is_equal(key, "left"))
11392                p_rarch->ai_gamepad_state[6] = 2;
11393             if (string_is_equal(key, "right"))
11394                p_rarch->ai_gamepad_state[7] = 2;
11395 
11396             if (string_is_equal(key, "a"))
11397                p_rarch->ai_gamepad_state[8] = 2;
11398             if (string_is_equal(key, "x"))
11399                p_rarch->ai_gamepad_state[9] = 2;
11400             if (string_is_equal(key, "l"))
11401                p_rarch->ai_gamepad_state[10] = 2;
11402             if (string_is_equal(key, "r"))
11403                p_rarch->ai_gamepad_state[11] = 2;
11404 
11405             if (string_is_equal(key, "l2"))
11406                p_rarch->ai_gamepad_state[12] = 2;
11407             if (string_is_equal(key, "r2"))
11408                p_rarch->ai_gamepad_state[13] = 2;
11409             if (string_is_equal(key, "l3"))
11410                p_rarch->ai_gamepad_state[14] = 2;
11411             if (string_is_equal(key, "r3"))
11412                p_rarch->ai_gamepad_state[15] = 2;
11413 #endif
11414 #endif
11415 
11416             if (string_is_equal(key, "pause"))
11417                command_event(CMD_EVENT_PAUSE, NULL);
11418             if (string_is_equal(key, "unpause"))
11419                command_event(CMD_EVENT_UNPAUSE, NULL);
11420 
11421             start = i+1;
11422          }
11423       }
11424    }
11425 
11426 #ifdef HAVE_ACCESSIBILITY
11427    if (text_string && is_accessibility_enabled(
11428             accessibility_enable,
11429             p_rarch->accessibility_enabled))
11430       accessibility_speak_priority(p_rarch,
11431             accessibility_enable,
11432             accessibility_narrator_speech_speed,
11433             text_string, 10);
11434 #endif
11435 
11436 finish:
11437    if (error)
11438       RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED), error);
11439 
11440    if (user_data)
11441       free(user_data);
11442 
11443    if (json)
11444       rjson_free(json);
11445    if (raw_image_file_data)
11446       free(raw_image_file_data);
11447    if (raw_image_data_alpha)
11448        free(raw_image_data_alpha);
11449    if (raw_image_data)
11450       free(raw_image_data);
11451    if (scaler)
11452       free(scaler);
11453    if (err_string)
11454       free(err_string);
11455    if (text_string)
11456       free(text_string);
11457    if (raw_output_data)
11458       free(raw_output_data);
11459 
11460    if (string_is_equal(auto_string, "auto"))
11461    {
11462       if (     (p_rarch->ai_service_auto != 0)
11463             && !settings->bools.ai_service_pause)
11464          call_auto_translate_task(p_rarch, settings, &was_paused);
11465    }
11466    if (auto_string)
11467       free(auto_string);
11468    if (key_string)
11469       free(key_string);
11470 }
11471 
ai_service_get_str(enum translation_lang id)11472 static const char *ai_service_get_str(enum translation_lang id)
11473 {
11474    switch (id)
11475    {
11476       case TRANSLATION_LANG_EN:
11477          return "en";
11478       case TRANSLATION_LANG_ES:
11479          return "es";
11480       case TRANSLATION_LANG_FR:
11481          return "fr";
11482       case TRANSLATION_LANG_IT:
11483          return "it";
11484       case TRANSLATION_LANG_DE:
11485          return "de";
11486       case TRANSLATION_LANG_JP:
11487          return "ja";
11488       case TRANSLATION_LANG_NL:
11489          return "nl";
11490       case TRANSLATION_LANG_CS:
11491          return "cs";
11492       case TRANSLATION_LANG_DA:
11493          return "da";
11494       case TRANSLATION_LANG_SV:
11495          return "sv";
11496       case TRANSLATION_LANG_HR:
11497          return "hr";
11498       case TRANSLATION_LANG_KO:
11499          return "ko";
11500       case TRANSLATION_LANG_ZH_CN:
11501          return "zh-CN";
11502       case TRANSLATION_LANG_ZH_TW:
11503          return "zh-TW";
11504       case TRANSLATION_LANG_CA:
11505          return "ca";
11506       case TRANSLATION_LANG_BG:
11507          return "bg";
11508       case TRANSLATION_LANG_BN:
11509          return "bn";
11510       case TRANSLATION_LANG_EU:
11511          return "eu";
11512       case TRANSLATION_LANG_AZ:
11513          return "az";
11514       case TRANSLATION_LANG_AR:
11515          return "ar";
11516       case TRANSLATION_LANG_AST:
11517          return "ast";
11518       case TRANSLATION_LANG_SQ:
11519          return "sq";
11520       case TRANSLATION_LANG_AF:
11521          return "af";
11522       case TRANSLATION_LANG_EO:
11523          return "eo";
11524       case TRANSLATION_LANG_ET:
11525          return "et";
11526       case TRANSLATION_LANG_TL:
11527          return "tl";
11528       case TRANSLATION_LANG_FI:
11529          return "fi";
11530       case TRANSLATION_LANG_GL:
11531          return "gl";
11532       case TRANSLATION_LANG_KA:
11533          return "ka";
11534       case TRANSLATION_LANG_EL:
11535          return "el";
11536       case TRANSLATION_LANG_GU:
11537          return "gu";
11538       case TRANSLATION_LANG_HT:
11539          return "ht";
11540       case TRANSLATION_LANG_HE:
11541          return "he";
11542       case TRANSLATION_LANG_HI:
11543          return "hi";
11544       case TRANSLATION_LANG_HU:
11545          return "hu";
11546       case TRANSLATION_LANG_IS:
11547          return "is";
11548       case TRANSLATION_LANG_ID:
11549          return "id";
11550       case TRANSLATION_LANG_GA:
11551          return "ga";
11552       case TRANSLATION_LANG_KN:
11553          return "kn";
11554       case TRANSLATION_LANG_LA:
11555          return "la";
11556       case TRANSLATION_LANG_LV:
11557          return "lv";
11558       case TRANSLATION_LANG_LT:
11559          return "lt";
11560       case TRANSLATION_LANG_MK:
11561          return "mk";
11562       case TRANSLATION_LANG_MS:
11563          return "ms";
11564       case TRANSLATION_LANG_MT:
11565          return "mt";
11566       case TRANSLATION_LANG_NO:
11567          return "no";
11568       case TRANSLATION_LANG_FA:
11569          return "fa";
11570       case TRANSLATION_LANG_PL:
11571          return "pl";
11572       case TRANSLATION_LANG_PT:
11573          return "pt";
11574       case TRANSLATION_LANG_RO:
11575          return "ro";
11576       case TRANSLATION_LANG_RU:
11577          return "ru";
11578       case TRANSLATION_LANG_SR:
11579          return "sr";
11580       case TRANSLATION_LANG_SK:
11581          return "sk";
11582       case TRANSLATION_LANG_SL:
11583          return "sl";
11584       case TRANSLATION_LANG_SW:
11585          return "sw";
11586       case TRANSLATION_LANG_TA:
11587          return "ta";
11588       case TRANSLATION_LANG_TE:
11589          return "te";
11590       case TRANSLATION_LANG_TH:
11591          return "th";
11592       case TRANSLATION_LANG_TR:
11593          return "tr";
11594       case TRANSLATION_LANG_UK:
11595          return "uk";
11596       case TRANSLATION_LANG_UR:
11597          return "ur";
11598       case TRANSLATION_LANG_VI:
11599          return "vi";
11600       case TRANSLATION_LANG_CY:
11601          return "cy";
11602       case TRANSLATION_LANG_YI:
11603          return "yi";
11604       case TRANSLATION_LANG_DONT_CARE:
11605       case TRANSLATION_LANG_LAST:
11606          break;
11607    }
11608 
11609    return "";
11610 }
11611 
11612 
11613 /*
11614    This function does all the stuff needed to translate the game screen,
11615    using the URL given in the settings.  Once the image from the frame
11616    buffer is sent to the server, the callback will write the translated
11617    image to the screen.
11618 
11619    Supported client/services (thus far)
11620    -VGTranslate client ( www.gitlab.com/spherebeaker/vg_translate )
11621    -Ztranslate client/service ( www.ztranslate.net/docs/service )
11622 
11623    To use a client, download the relevant code/release, configure
11624    them, and run them on your local machine, or network.  Set the
11625    retroarch configuration to point to your local client (usually
11626    listening on localhost:4404 ) and enable translation service.
11627 
11628    If you don't want to run a client, you can also use a service,
11629    which is basically like someone running a client for you.  The
11630    downside here is that your retroarch device will have to have
11631    an internet connection, and you may have to sign up for it.
11632 
11633    To make your own server, it must listen for a POST request, which
11634    will consist of a JSON body, with the "image" field as a base64
11635    encoded string of a 24bit-BMP/PNG that the will be translated.
11636    The server must output the translated image in the form of a
11637    JSON body, with the "image" field also as a base64 encoded
11638    24bit-BMP, or as an alpha channel png.
11639 
11640   "paused" boolean is passed in to indicate if the current call
11641    was made during a paused frame.  Due to how the menu widgets work,
11642    if the ai service is called in "auto" mode, then this call will
11643    be made while the menu widgets unpause the core for a frame to update
11644    the on-screen widgets.  To tell the ai service what the pause
11645    mode is honestly, we store the runloop_paused variable from before
11646    the handle_translation_cb wipes the widgets, and pass that in here.
11647 */
11648 
run_translation_service(settings_t * settings,struct rarch_state * p_rarch,bool paused)11649 static bool run_translation_service(
11650       settings_t *settings,
11651       struct rarch_state *p_rarch,
11652       bool paused)
11653 {
11654    struct video_viewport vp;
11655    uint8_t header[54];
11656    size_t pitch;
11657    unsigned width, height;
11658    const void *data                      = NULL;
11659    uint8_t *bit24_image                  = NULL;
11660    uint8_t *bit24_image_prev             = NULL;
11661    struct scaler_ctx *scaler             = (struct scaler_ctx*)
11662       calloc(1, sizeof(struct scaler_ctx));
11663    bool error                            = false;
11664 
11665    uint8_t *bmp_buffer                   = NULL;
11666    uint64_t buffer_bytes                 = 0;
11667    char *bmp64_buffer                    = NULL;
11668    rjsonwriter_t* jsonwriter             = NULL;
11669    const char *json_buffer               = NULL;
11670 
11671    int bmp64_length                      = 0;
11672    bool TRANSLATE_USE_BMP                = false;
11673    bool use_overlay                      = false;
11674 
11675    const char *label                     = NULL;
11676    char* system_label                    = NULL;
11677    core_info_t *core_info                = NULL;
11678    const enum retro_pixel_format
11679       video_driver_pix_fmt               = p_rarch->video_driver_pix_fmt;
11680 
11681 #ifdef HAVE_GFX_WIDGETS
11682    /* For the case when ai service pause is disabled. */
11683    if (  (p_rarch->dispwidget_st.ai_service_overlay_state != 0)
11684          && (p_rarch->ai_service_auto == 1))
11685    {
11686       gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
11687       goto finish;
11688    }
11689 #endif
11690 
11691 #ifdef HAVE_GFX_WIDGETS
11692    if (     p_rarch->video_driver_poke
11693          && p_rarch->video_driver_poke->load_texture
11694          && p_rarch->video_driver_poke->unload_texture)
11695       use_overlay = true;
11696 #endif
11697 
11698    /* get the core info here so we can pass long the game name */
11699    core_info_get_current_core(&core_info);
11700 
11701    if (core_info)
11702    {
11703       size_t label_len;
11704       const char *system_id               = core_info->system_id
11705          ? core_info->system_id : "core";
11706       size_t system_id_len                = strlen(system_id);
11707       const struct playlist_entry *entry  = NULL;
11708       playlist_t *current_playlist        = playlist_get_cached();
11709 
11710       if (current_playlist)
11711       {
11712          playlist_get_index_by_path(
11713             current_playlist, path_get(RARCH_PATH_CONTENT), &entry);
11714 
11715          if (entry && !string_is_empty(entry->label))
11716             label = entry->label;
11717       }
11718 
11719       if (!label)
11720          label     = path_basename(path_get(RARCH_PATH_BASENAME));
11721       label_len    = strlen(label);
11722       system_label = (char*)malloc(label_len + system_id_len + 3);
11723       memcpy(system_label, system_id, system_id_len);
11724       memcpy(system_label + system_id_len, "__", 2);
11725       memcpy(system_label + 2 + system_id_len, label, label_len);
11726       system_label[system_id_len + 2 + label_len] = '\0';
11727    }
11728 
11729    if (!scaler)
11730       goto finish;
11731 
11732    video_driver_cached_frame_get(&data, &width, &height, &pitch);
11733 
11734    if (!data)
11735       goto finish;
11736 
11737    if (data == RETRO_HW_FRAME_BUFFER_VALID)
11738    {
11739       /*
11740         The direct frame capture didn't work, so try getting it
11741         from the viewport instead.  This isn't as good as the
11742         raw frame buffer, since the viewport may us bilinear
11743         filtering, or other shaders that will completely trash
11744         the OCR, but it's better than nothing.
11745       */
11746       vp.x                           = 0;
11747       vp.y                           = 0;
11748       vp.width                       = 0;
11749       vp.height                      = 0;
11750       vp.full_width                  = 0;
11751       vp.full_height                 = 0;
11752 
11753       video_driver_get_viewport_info(&vp);
11754 
11755       if (!vp.width || !vp.height)
11756          goto finish;
11757 
11758       bit24_image_prev = (uint8_t*)malloc(vp.width * vp.height * 3);
11759       bit24_image      = (uint8_t*)malloc(width * height * 3);
11760 
11761       if (!bit24_image_prev || !bit24_image)
11762          goto finish;
11763 
11764       if (!video_driver_read_viewport(bit24_image_prev, false))
11765       {
11766          RARCH_LOG("Could not read viewport for translation service...\n");
11767          goto finish;
11768       }
11769 
11770       /* TODO: Rescale down to regular resolution */
11771       scaler->in_fmt      = SCALER_FMT_BGR24;
11772       scaler->out_fmt     = SCALER_FMT_BGR24;
11773       scaler->scaler_type = SCALER_TYPE_POINT;
11774       scaler->in_width    = vp.width;
11775       scaler->in_height   = vp.height;
11776       scaler->out_width   = width;
11777       scaler->out_height  = height;
11778       scaler_ctx_gen_filter(scaler);
11779 
11780       scaler->in_stride   = vp.width*3;
11781       scaler->out_stride  = width*3;
11782       scaler_ctx_scale_direct(scaler, bit24_image, bit24_image_prev);
11783    }
11784    else
11785    {
11786       /* This is a software core, so just change the pixel format to 24-bit. */
11787       bit24_image = (uint8_t*)malloc(width * height * 3);
11788       if (!bit24_image)
11789           goto finish;
11790 
11791       if (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
11792          scaler->in_fmt = SCALER_FMT_ARGB8888;
11793       else
11794          scaler->in_fmt = SCALER_FMT_RGB565;
11795       video_frame_convert_to_bgr24(
11796          scaler,
11797          (uint8_t *)bit24_image,
11798          (const uint8_t*)data + ((int)height - 1)*pitch,
11799          width, height,
11800          (int)-pitch);
11801    }
11802    scaler_ctx_gen_reset(scaler);
11803 
11804    if (!bit24_image)
11805    {
11806       error = true;
11807       goto finish;
11808    }
11809 
11810    if (TRANSLATE_USE_BMP)
11811    {
11812       /*
11813         At this point, we should have a screenshot in the buffer,
11814         so allocate an array to contain the BMP image along with
11815         the BMP header as bytes, and then covert that to a
11816         b64 encoded array for transport in JSON.
11817       */
11818 
11819       form_bmp_header(header, width, height, false);
11820       bmp_buffer  = (uint8_t*)malloc(width * height * 3 + 54);
11821       if (!bmp_buffer)
11822          goto finish;
11823 
11824       memcpy(bmp_buffer, header, 54 * sizeof(uint8_t));
11825       memcpy(bmp_buffer + 54,
11826             bit24_image,
11827             width * height * 3 * sizeof(uint8_t));
11828       buffer_bytes = sizeof(uint8_t) * (width * height * 3 + 54);
11829    }
11830    else
11831    {
11832       pitch        = width * 3;
11833       bmp_buffer   = rpng_save_image_bgr24_string(
11834             bit24_image + width * (height-1) * 3,
11835             width, height, (signed)-pitch, &buffer_bytes);
11836    }
11837 
11838    bmp64_buffer    = base64((void *)bmp_buffer,
11839          sizeof(uint8_t) * buffer_bytes,
11840          &bmp64_length);
11841 
11842    if (!bmp64_buffer)
11843       goto finish;
11844 
11845    jsonwriter = rjsonwriter_open_memory();
11846    if (!jsonwriter)
11847       goto finish;
11848 
11849    rjsonwriter_add_start_object(jsonwriter);
11850    rjsonwriter_add_space(jsonwriter);
11851    rjsonwriter_add_string(jsonwriter, "image");
11852    rjsonwriter_add_colon(jsonwriter);
11853    rjsonwriter_add_space(jsonwriter);
11854    rjsonwriter_add_string_len(jsonwriter, bmp64_buffer, bmp64_length);
11855 
11856    /* Form request... */
11857    if (system_label)
11858    {
11859       rjsonwriter_add_comma(jsonwriter);
11860       rjsonwriter_add_space(jsonwriter);
11861       rjsonwriter_add_string(jsonwriter, "label");
11862       rjsonwriter_add_colon(jsonwriter);
11863       rjsonwriter_add_space(jsonwriter);
11864       rjsonwriter_add_string(jsonwriter, system_label);
11865    }
11866 
11867    rjsonwriter_add_comma(jsonwriter);
11868    rjsonwriter_add_space(jsonwriter);
11869    rjsonwriter_add_string(jsonwriter, "state");
11870    rjsonwriter_add_colon(jsonwriter);
11871    rjsonwriter_add_space(jsonwriter);
11872    rjsonwriter_add_start_object(jsonwriter);
11873    rjsonwriter_add_space(jsonwriter);
11874    rjsonwriter_add_string(jsonwriter, "paused");
11875    rjsonwriter_add_colon(jsonwriter);
11876    rjsonwriter_add_space(jsonwriter);
11877    rjsonwriter_add_unsigned(jsonwriter, (paused ? 1 : 0));
11878    {
11879       static const char* state_labels[] = { "b", "y", "select", "start", "up", "down", "left", "right", "a", "x", "l", "r", "l2", "r2", "l3", "r3" };
11880       int i;
11881       for (i = 0; i < ARRAY_SIZE(state_labels); i++)
11882       {
11883          rjsonwriter_add_comma(jsonwriter);
11884          rjsonwriter_add_space(jsonwriter);
11885          rjsonwriter_add_string(jsonwriter, state_labels[i]);
11886          rjsonwriter_add_colon(jsonwriter);
11887          rjsonwriter_add_space(jsonwriter);
11888 #ifdef HAVE_ACCESSIBILITY
11889          rjsonwriter_add_unsigned(jsonwriter,
11890                (p_rarch->ai_gamepad_state[i] ? 1 : 0)
11891                );
11892 #else
11893          rjsonwriter_add_unsigned(jsonwriter, 0);
11894 #endif
11895       }
11896    }
11897    rjsonwriter_add_space(jsonwriter);
11898    rjsonwriter_add_end_object(jsonwriter);
11899    rjsonwriter_add_space(jsonwriter);
11900    rjsonwriter_add_end_object(jsonwriter);
11901 
11902    json_buffer = rjsonwriter_get_memory_buffer(jsonwriter, NULL);
11903    if (!json_buffer)
11904       goto finish; /* ran out of memory */
11905 
11906 #ifdef DEBUG
11907    if (p_rarch->ai_service_auto != 2)
11908       RARCH_LOG("Request size: %d\n", bmp64_length);
11909 #endif
11910    {
11911       char new_ai_service_url[PATH_MAX_LENGTH];
11912       char separator                  = '?';
11913       unsigned ai_service_source_lang = settings->uints.ai_service_source_lang;
11914       unsigned ai_service_target_lang = settings->uints.ai_service_target_lang;
11915       const char *ai_service_url      = settings->arrays.ai_service_url;
11916 
11917       strlcpy(new_ai_service_url, ai_service_url, sizeof(new_ai_service_url));
11918 
11919       /* if query already exists in url, then use &'s instead */
11920       if (strrchr(new_ai_service_url, '?'))
11921           separator = '&';
11922 
11923       /* source lang */
11924       if (ai_service_source_lang != TRANSLATION_LANG_DONT_CARE)
11925       {
11926          const char *lang_source = ai_service_get_str(
11927                (enum translation_lang)ai_service_source_lang);
11928 
11929          if (!string_is_empty(lang_source))
11930          {
11931             char temp_string[PATH_MAX_LENGTH];
11932             snprintf(temp_string,
11933                   sizeof(temp_string),
11934                   "%csource_lang=%s", separator, lang_source);
11935             separator = '&';
11936             strlcat(new_ai_service_url,
11937                   temp_string, sizeof(new_ai_service_url));
11938          }
11939       }
11940 
11941       /* target lang */
11942       if (ai_service_target_lang != TRANSLATION_LANG_DONT_CARE)
11943       {
11944          const char *lang_target = ai_service_get_str(
11945                (enum translation_lang)ai_service_target_lang);
11946 
11947          if (!string_is_empty(lang_target))
11948          {
11949             char temp_string[PATH_MAX_LENGTH];
11950             snprintf(temp_string,
11951                   sizeof(temp_string),
11952                   "%ctarget_lang=%s", separator, lang_target);
11953             separator = '&';
11954 
11955             strlcat(new_ai_service_url, temp_string,
11956                   sizeof(new_ai_service_url));
11957          }
11958       }
11959 
11960       /* mode */
11961       {
11962          char temp_string[PATH_MAX_LENGTH];
11963          const char *mode_chr                    = NULL;
11964          unsigned ai_service_mode                = settings->uints.ai_service_mode;
11965          /*"image" is included for backwards compatability with
11966           * vgtranslate < 1.04 */
11967 
11968          temp_string[0] = '\0';
11969 
11970          switch (ai_service_mode)
11971          {
11972             case 0:
11973                if (use_overlay)
11974                   mode_chr = "image,png,png-a";
11975                else
11976                   mode_chr = "image,png";
11977                break;
11978             case 1:
11979                mode_chr    = "sound,wav";
11980                break;
11981             case 2:
11982                mode_chr    = "text";
11983                break;
11984             case 3:
11985                if (use_overlay)
11986                   mode_chr = "image,png,png-a,sound,wav";
11987                else
11988                   mode_chr = "image,png,sound,wav";
11989                break;
11990             default:
11991                break;
11992          }
11993 
11994          snprintf(temp_string,
11995                sizeof(temp_string),
11996                "%coutput=%s", separator, mode_chr);
11997          separator = '&';
11998 
11999          strlcat(new_ai_service_url, temp_string,
12000                  sizeof(new_ai_service_url));
12001       }
12002 #ifdef DEBUG
12003       if (p_rarch->ai_service_auto != 2)
12004          RARCH_LOG("SENDING... %s\n", new_ai_service_url);
12005 #endif
12006       task_push_http_post_transfer(new_ai_service_url,
12007             json_buffer, true, NULL, handle_translation_cb, NULL);
12008    }
12009 
12010    error = false;
12011 finish:
12012    if (bit24_image_prev)
12013       free(bit24_image_prev);
12014    if (bit24_image)
12015       free(bit24_image);
12016 
12017    if (scaler)
12018       free(scaler);
12019 
12020    if (bmp_buffer)
12021       free(bmp_buffer);
12022 
12023    if (bmp64_buffer)
12024       free(bmp64_buffer);
12025    if (system_label)
12026       free(system_label);
12027    if (jsonwriter)
12028       rjsonwriter_free(jsonwriter);
12029    return !error;
12030 }
12031 #endif
12032 
12033 /**
12034  * command_event_disk_control_append_image:
12035  * @path                 : Path to disk image.
12036  *
12037  * Appends disk image to disk image list.
12038  **/
command_event_disk_control_append_image(struct rarch_state * p_rarch,rarch_system_info_t * sys_info,const char * path)12039 static bool command_event_disk_control_append_image(
12040       struct rarch_state *p_rarch,
12041       rarch_system_info_t *sys_info,
12042       const char *path)
12043 {
12044    if (  !sys_info ||
12045          !disk_control_append_image(&sys_info->disk_control, path))
12046       return false;
12047 
12048 #ifdef HAVE_THREADS
12049    retroarch_autosave_deinit(p_rarch);
12050 #endif
12051 
12052    /* TODO/FIXME: Need to figure out what to do with subsystems case. */
12053    if (path_is_empty(RARCH_PATH_SUBSYSTEM))
12054    {
12055       /* Update paths for our new image.
12056        * If we actually use append_image, we assume that we
12057        * started out in a single disk case, and that this way
12058        * of doing it makes the most sense. */
12059       path_set(RARCH_PATH_NAMES, path);
12060       path_fill_names(p_rarch);
12061    }
12062 
12063    command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
12064 
12065    return true;
12066 }
12067 
12068 /**
12069  * event_set_volume:
12070  * @gain      : amount of gain to be applied to current volume level.
12071  *
12072  * Adjusts the current audio volume level.
12073  *
12074  **/
command_event_set_volume(settings_t * settings,float gain,bool widgets_active,bool audio_driver_mute_enable)12075 static void command_event_set_volume(
12076       settings_t *settings,
12077       float gain,
12078       bool widgets_active,
12079       bool audio_driver_mute_enable)
12080 {
12081    char msg[128];
12082    float new_volume            = settings->floats.audio_volume + gain;
12083 
12084    new_volume                  = MAX(new_volume, -80.0f);
12085    new_volume                  = MIN(new_volume, 12.0f);
12086 
12087    configuration_set_float(settings, settings->floats.audio_volume, new_volume);
12088 
12089    snprintf(msg, sizeof(msg), "%s: %.1f dB",
12090          msg_hash_to_str(MSG_AUDIO_VOLUME),
12091          new_volume);
12092 
12093 #if defined(HAVE_GFX_WIDGETS)
12094    if (widgets_active)
12095       gfx_widget_volume_update_and_show(new_volume,
12096             audio_driver_mute_enable);
12097    else
12098 #endif
12099       runloop_msg_queue_push(msg, 1, 180, true, NULL,
12100             MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
12101 
12102    RARCH_LOG("[Audio]: %s\n", msg);
12103 
12104    audio_set_float(AUDIO_ACTION_VOLUME_GAIN, new_volume);
12105 }
12106 
12107 /**
12108  * event_set_mixer_volume:
12109  * @gain      : amount of gain to be applied to current volume level.
12110  *
12111  * Adjusts the current audio volume level.
12112  *
12113  **/
command_event_set_mixer_volume(settings_t * settings,float gain)12114 static void command_event_set_mixer_volume(
12115       settings_t *settings,
12116       float gain)
12117 {
12118    char msg[128];
12119    float new_volume            = settings->floats.audio_mixer_volume + gain;
12120 
12121    new_volume                  = MAX(new_volume, -80.0f);
12122    new_volume                  = MIN(new_volume, 12.0f);
12123 
12124    configuration_set_float(settings, settings->floats.audio_mixer_volume, new_volume);
12125 
12126    snprintf(msg, sizeof(msg), "%s: %.1f dB",
12127          msg_hash_to_str(MSG_AUDIO_VOLUME),
12128          new_volume);
12129    runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
12130 
12131    RARCH_LOG("[Audio]: %s\n", msg);
12132 
12133    audio_set_float(AUDIO_ACTION_VOLUME_GAIN, new_volume);
12134 }
12135 
12136 /**
12137  * command_event_init_controllers:
12138  *
12139  * Initialize libretro controllers.
12140  **/
command_event_init_controllers(rarch_system_info_t * info,settings_t * settings,unsigned num_active_users)12141 static void command_event_init_controllers(rarch_system_info_t *info,
12142       settings_t *settings, unsigned num_active_users)
12143 {
12144    unsigned num_core_ports = info->ports.size;
12145    unsigned port;
12146 
12147    for (port = 0; port < num_core_ports; port++)
12148    {
12149       unsigned device                                 = RETRO_DEVICE_NONE;
12150       const struct retro_controller_description *desc = NULL;
12151       retro_ctx_controller_info_t pad;
12152       unsigned i;
12153 
12154       /* Check whether current core port is mapped
12155        * to an input device
12156        * > If is not, leave 'device' set to
12157        *   'RETRO_DEVICE_NONE'
12158        * > For example: if input ports 0 and 1 are
12159        *   mapped to core port 0, core port 1 will
12160        *   be unmapped and should be disabled */
12161       for (i = 0; i < num_active_users; i++)
12162       {
12163          if (i >= MAX_USERS)
12164             break;
12165 
12166          if (port == settings->uints.input_remap_ports[i])
12167          {
12168             device = input_config_get_device(port);
12169             break;
12170          }
12171       }
12172 
12173       desc = libretro_find_controller_description(
12174             &info->ports.data[port], device);
12175 
12176       if (desc && !desc->desc)
12177       {
12178          /* If we're trying to connect a completely unknown device,
12179           * revert back to JOYPAD. */
12180          if (device != RETRO_DEVICE_JOYPAD && device != RETRO_DEVICE_NONE)
12181          {
12182             /* Do not fix device,
12183              * because any use of dummy core will reset this,
12184              * which is not a good idea. */
12185             RARCH_WARN("[Input]: Input device ID %u is unknown to this "
12186                   "libretro implementation. Using RETRO_DEVICE_JOYPAD.\n",
12187                   device);
12188             device = RETRO_DEVICE_JOYPAD;
12189          }
12190       }
12191 
12192       pad.device     = device;
12193       pad.port       = port;
12194       core_set_controller_port_device(&pad);
12195    }
12196 }
12197 
12198 #ifdef HAVE_CONFIGFILE
command_event_disable_overrides(struct rarch_state * p_rarch)12199 static void command_event_disable_overrides(struct rarch_state *p_rarch)
12200 {
12201    /* reload the original config */
12202    config_unload_override();
12203    runloop_state.overrides_active = false;
12204 }
12205 #endif
12206 
command_event_deinit_core(struct rarch_state * p_rarch,bool reinit)12207 static void command_event_deinit_core(
12208       struct rarch_state *p_rarch,
12209       bool reinit)
12210 {
12211    core_unload_game(p_rarch);
12212 
12213    video_driver_set_cached_frame_ptr(NULL);
12214 
12215    if (p_rarch->current_core.inited)
12216    {
12217       RARCH_LOG("[Core]: Unloading core..\n");
12218       p_rarch->current_core.retro_deinit();
12219    }
12220 
12221    RARCH_LOG("[Core]: Unloading core symbols..\n");
12222    uninit_libretro_symbols(p_rarch, &p_rarch->current_core);
12223    p_rarch->current_core.symbols_inited = false;
12224 
12225    if (reinit)
12226       driver_uninit(p_rarch, DRIVERS_CMD_ALL);
12227 
12228 #ifdef HAVE_CONFIGFILE
12229    if (runloop_state.overrides_active)
12230       command_event_disable_overrides(p_rarch);
12231 #endif
12232 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
12233    p_rarch->runtime_shader_preset[0] = '\0';
12234 #endif
12235 
12236    if (     runloop_state.remaps_core_active
12237          || runloop_state.remaps_content_dir_active
12238          || runloop_state.remaps_game_active
12239       )
12240    {
12241       input_remapping_deinit();
12242       input_remapping_set_defaults(true);
12243    }
12244    else
12245       input_remapping_restore_global_config(true);
12246 }
12247 
12248 #ifdef HAVE_CHEATS
command_event_init_cheats(bool apply_cheats_after_load,const char * path_cheat_db,struct rarch_state * p_rarch)12249 static void command_event_init_cheats(
12250       bool apply_cheats_after_load,
12251       const char *path_cheat_db,
12252       struct rarch_state *p_rarch)
12253 {
12254 #ifdef HAVE_NETWORKING
12255    bool allow_cheats             = !netplay_driver_ctl(
12256          RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL);
12257 #else
12258    bool allow_cheats             = true;
12259 #endif
12260 #ifdef HAVE_BSV_MOVIE
12261    allow_cheats                 &= !(p_rarch->bsv_movie_state_handle != NULL);
12262 #endif
12263 
12264    if (!allow_cheats)
12265       return;
12266 
12267    cheat_manager_alloc_if_empty();
12268    cheat_manager_load_game_specific_cheats(path_cheat_db);
12269 
12270    if (apply_cheats_after_load)
12271       cheat_manager_apply_cheats();
12272 }
12273 #endif
12274 
command_event_load_auto_state(global_t * global,struct rarch_state * p_rarch)12275 static void command_event_load_auto_state(
12276       global_t *global,
12277       struct rarch_state *p_rarch)
12278 {
12279    char savestate_name_auto[PATH_MAX_LENGTH];
12280    bool ret                        = false;
12281 #ifdef HAVE_CHEEVOS
12282    if (rcheevos_hardcore_active())
12283       return;
12284 #endif
12285 #ifdef HAVE_NETWORKING
12286    if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
12287       return;
12288 #endif
12289 
12290    savestate_name_auto[0] = '\0';
12291 
12292    fill_pathname_noext(savestate_name_auto, global->name.savestate,
12293          ".auto", sizeof(savestate_name_auto));
12294 
12295    if (!path_is_valid(savestate_name_auto))
12296       return;
12297 
12298    ret = content_load_state(savestate_name_auto, false, true);
12299 
12300    RARCH_LOG("%s: %s\n%s \"%s\" %s.\n",
12301          msg_hash_to_str(MSG_FOUND_AUTO_SAVESTATE_IN),
12302          savestate_name_auto,
12303          msg_hash_to_str(MSG_AUTOLOADING_SAVESTATE_FROM),
12304          savestate_name_auto, ret ? "succeeded" : "failed"
12305          );
12306 }
12307 
command_event_set_savestate_auto_index(settings_t * settings,const global_t * global,struct rarch_state * p_rarch)12308 static void command_event_set_savestate_auto_index(
12309       settings_t *settings,
12310       const global_t *global,
12311       struct rarch_state *p_rarch)
12312 {
12313    size_t i;
12314    char state_dir[PATH_MAX_LENGTH];
12315    char state_base[PATH_MAX_LENGTH];
12316 
12317    struct string_list *dir_list      = NULL;
12318    unsigned max_idx                  = 0;
12319    bool savestate_auto_index         = settings->bools.savestate_auto_index;
12320    bool show_hidden_files            = settings->bools.show_hidden_files;
12321 
12322    if (!global || !savestate_auto_index)
12323       return;
12324 
12325    state_dir[0] = state_base[0]      = '\0';
12326 
12327    /* Find the file in the same directory as global->savestate_name
12328     * with the largest numeral suffix.
12329     *
12330     * E.g. /foo/path/content.state, will try to find
12331     * /foo/path/content.state%d, where %d is the largest number available.
12332     */
12333    fill_pathname_basedir(state_dir, global->name.savestate,
12334          sizeof(state_dir));
12335 
12336    dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL,
12337          show_hidden_files);
12338 
12339    if (!dir_list)
12340       return;
12341 
12342    fill_pathname_base(state_base, global->name.savestate,
12343          sizeof(state_base));
12344 
12345    for (i = 0; i < dir_list->size; i++)
12346    {
12347       unsigned idx;
12348       char elem_base[128]             = {0};
12349       const char *end                 = NULL;
12350       const char *dir_elem            = dir_list->elems[i].data;
12351 
12352       fill_pathname_base(elem_base, dir_elem, sizeof(elem_base));
12353 
12354       if (strstr(elem_base, state_base) != elem_base)
12355          continue;
12356 
12357       end = dir_elem + strlen(dir_elem);
12358       while ((end > dir_elem) && ISDIGIT((int)end[-1]))
12359          end--;
12360 
12361       idx = (unsigned)strtoul(end, NULL, 0);
12362       if (idx > max_idx)
12363          max_idx = idx;
12364    }
12365 
12366    dir_list_free(dir_list);
12367 
12368    configuration_set_int(settings, settings->ints.state_slot, max_idx);
12369 
12370    RARCH_LOG("%s: #%d\n",
12371          msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT),
12372          max_idx);
12373 }
12374 
command_event_set_savestate_garbage_collect(const global_t * global,struct rarch_state * p_rarch,unsigned max_to_keep,bool show_hidden_files)12375 static void command_event_set_savestate_garbage_collect(
12376       const global_t *global,
12377       struct rarch_state *p_rarch,
12378       unsigned max_to_keep,
12379       bool show_hidden_files
12380       )
12381 {
12382    size_t i, cnt = 0;
12383    char state_dir[PATH_MAX_LENGTH];
12384    char state_base[PATH_MAX_LENGTH];
12385 
12386    struct string_list *dir_list      = NULL;
12387    unsigned min_idx                  = UINT_MAX;
12388    const char *oldest_save           = NULL;
12389 
12390    state_dir[0]                      = '\0';
12391    state_base[0]                     = '\0';
12392 
12393    /* Similar to command_event_set_savestate_auto_index(),
12394     * this will find the lowest numbered save-state */
12395    fill_pathname_basedir(state_dir, global->name.savestate,
12396          sizeof(state_dir));
12397 
12398    dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL,
12399          show_hidden_files);
12400 
12401    if (!dir_list)
12402       return;
12403 
12404    fill_pathname_base(state_base, global->name.savestate,
12405          sizeof(state_base));
12406 
12407    for (i = 0; i < dir_list->size; i++)
12408    {
12409       unsigned idx;
12410       char elem_base[128];
12411       const char *ext                 = NULL;
12412       const char *end                 = NULL;
12413       const char *dir_elem            = dir_list->elems[i].data;
12414 
12415       elem_base[0]                    = '\0';
12416 
12417       if (string_is_empty(dir_elem))
12418          continue;
12419 
12420       fill_pathname_base(elem_base, dir_elem, sizeof(elem_base));
12421 
12422       /* Only consider files with a '.state' extension
12423        * > i.e. Ignore '.state.auto', '.state.bak', etc. */
12424       ext = path_get_extension(elem_base);
12425       if (string_is_empty(ext) ||
12426           !string_starts_with_size(ext, "state", STRLEN_CONST("state")))
12427          continue;
12428 
12429       /* Check whether this file is associated with
12430        * the current content */
12431       if (!string_starts_with(elem_base, state_base))
12432          continue;
12433 
12434       /* This looks like a valid save */
12435       cnt++;
12436 
12437       /* > Get index */
12438       end = dir_elem + strlen(dir_elem);
12439       while ((end > dir_elem) && ISDIGIT((int)end[-1]))
12440          end--;
12441 
12442       idx = string_to_unsigned(end);
12443 
12444       /* > Check if this is the lowest index so far */
12445       if (idx < min_idx)
12446       {
12447          min_idx     = idx;
12448          oldest_save = dir_elem;
12449       }
12450    }
12451 
12452    /* Only delete one save state per save action
12453     * > Conservative behaviour, designed to minimise
12454     *   the risk of deleting multiple incorrect files
12455     *   in case of accident */
12456    if (!string_is_empty(oldest_save) && (cnt > max_to_keep))
12457       filestream_delete(oldest_save);
12458 
12459    dir_list_free(dir_list);
12460 }
12461 
event_init_content(settings_t * settings,struct rarch_state * p_rarch)12462 static bool event_init_content(
12463       settings_t *settings,
12464       struct rarch_state *p_rarch)
12465 {
12466    bool contentless                             = false;
12467    bool is_inited                               = false;
12468 #ifdef HAVE_CHEEVOS
12469    bool cheevos_enable                          =
12470       settings->bools.cheevos_enable;
12471    bool cheevos_hardcore_mode_enable            =
12472       settings->bools.cheevos_hardcore_mode_enable;
12473 #endif
12474    global_t   *global                           = &p_rarch->g_extern;
12475    const enum rarch_core_type current_core_type = p_rarch->current_core_type;
12476 
12477    content_get_status(&contentless, &is_inited);
12478 
12479    /* TODO/FIXME - just because we have a contentless core does not
12480     * necessarily mean there should be no SRAM, try to find a solution here */
12481    p_rarch->rarch_use_sram   = (current_core_type == CORE_TYPE_PLAIN)
12482       && !contentless;
12483 
12484    /* No content to be loaded for dummy core,
12485     * just successfully exit. */
12486    if (current_core_type == CORE_TYPE_DUMMY)
12487       return true;
12488 
12489    content_set_subsystem_info();
12490 
12491    content_get_status(&contentless, &is_inited);
12492 
12493    if (!contentless)
12494       path_fill_names(p_rarch);
12495 
12496    if (!content_init())
12497    {
12498       runloop_state.core_running = false;
12499       return false;
12500    }
12501 
12502    command_event_set_savestate_auto_index(settings, global, p_rarch);
12503 
12504    if (event_load_save_files(p_rarch->rarch_is_sram_load_disabled))
12505       RARCH_LOG("[SRAM]: %s.\n",
12506             msg_hash_to_str(MSG_SKIPPING_SRAM_LOAD));
12507 
12508 /*
12509    Since the operations are asynchronous we can't
12510    guarantee users will not use auto_load_state to cheat on
12511    achievements so we forbid auto_load_state from happening
12512    if cheevos_enable and cheevos_hardcode_mode_enable
12513    are true.
12514 */
12515 #ifdef HAVE_CHEEVOS
12516    if (!cheevos_enable || !cheevos_hardcore_mode_enable)
12517 #endif
12518       if (global && settings->bools.savestate_auto_load)
12519          command_event_load_auto_state(global, p_rarch);
12520 
12521 #ifdef HAVE_BSV_MOVIE
12522    bsv_movie_deinit(p_rarch);
12523    if (bsv_movie_init(p_rarch))
12524    {
12525       /* Set granularity upon success */
12526       configuration_set_uint(settings,
12527             settings->uints.rewind_granularity, 1);
12528    }
12529 #endif
12530    command_event(CMD_EVENT_NETPLAY_INIT, NULL);
12531 
12532    return true;
12533 }
12534 
update_runtime_log(struct rarch_state * p_rarch,const char * dir_runtime_log,const char * dir_playlist,bool log_per_core)12535 static void update_runtime_log(
12536       struct rarch_state *p_rarch,
12537       const char *dir_runtime_log,
12538       const char *dir_playlist,
12539       bool log_per_core)
12540 {
12541    /* Initialise runtime log file */
12542    runtime_log_t *runtime_log   = runtime_log_init(
12543          p_rarch->runtime_content_path,
12544          p_rarch->runtime_core_path,
12545          dir_runtime_log,
12546          dir_playlist,
12547          log_per_core);
12548 
12549    if (!runtime_log)
12550       return;
12551 
12552    /* Add additional runtime */
12553    runtime_log_add_runtime_usec(runtime_log,
12554          p_rarch->libretro_core_runtime_usec);
12555 
12556    /* Update 'last played' entry */
12557    runtime_log_set_last_played_now(runtime_log);
12558 
12559    /* Save runtime log file */
12560    runtime_log_save(runtime_log);
12561 
12562    /* Clean up */
12563    free(runtime_log);
12564 }
12565 
12566 
command_event_runtime_log_deinit(struct rarch_state * p_rarch,bool content_runtime_log,bool content_runtime_log_aggregate,const char * dir_runtime_log,const char * dir_playlist)12567 static void command_event_runtime_log_deinit(
12568       struct rarch_state *p_rarch,
12569       bool content_runtime_log,
12570       bool content_runtime_log_aggregate,
12571       const char *dir_runtime_log,
12572       const char *dir_playlist)
12573 {
12574    if (verbosity_is_enabled())
12575    {
12576       int n;
12577       char log[PATH_MAX_LENGTH] = {0};
12578       unsigned hours            = 0;
12579       unsigned minutes          = 0;
12580       unsigned seconds          = 0;
12581 
12582       runtime_log_convert_usec2hms(
12583             p_rarch->libretro_core_runtime_usec,
12584             &hours, &minutes, &seconds);
12585 
12586       n                         =
12587          snprintf(log, sizeof(log),
12588                "[Core]: Content ran for a total of:"
12589                " %02u hours, %02u minutes, %02u seconds.",
12590                hours, minutes, seconds);
12591       if ((n < 0) || (n >= PATH_MAX_LENGTH))
12592          n = 0; /* Just silence any potential gcc warnings... */
12593       (void)n;
12594       RARCH_LOG("%s\n",log);
12595    }
12596 
12597    /* Only write to file if content has run for a non-zero length of time */
12598    if (p_rarch->libretro_core_runtime_usec > 0)
12599    {
12600       /* Per core logging */
12601       if (content_runtime_log)
12602          update_runtime_log(p_rarch, dir_runtime_log, dir_playlist, true);
12603 
12604       /* Aggregate logging */
12605       if (content_runtime_log_aggregate)
12606          update_runtime_log(p_rarch, dir_runtime_log, dir_playlist, false);
12607    }
12608 
12609    /* Reset runtime + content/core paths, to prevent any
12610     * possibility of duplicate logging */
12611    p_rarch->libretro_core_runtime_usec = 0;
12612    memset(p_rarch->runtime_content_path, 0, sizeof(p_rarch->runtime_content_path));
12613    memset(p_rarch->runtime_core_path,    0, sizeof(p_rarch->runtime_core_path));
12614 }
12615 
command_event_runtime_log_init(struct rarch_state * p_rarch)12616 static void command_event_runtime_log_init(struct rarch_state *p_rarch)
12617 {
12618    const char *content_path            = path_get(RARCH_PATH_CONTENT);
12619    const char *core_path               = path_get(RARCH_PATH_CORE);
12620 
12621    p_rarch->libretro_core_runtime_last = cpu_features_get_time_usec();
12622    p_rarch->libretro_core_runtime_usec = 0;
12623 
12624    /* Have to cache content and core path here, otherwise
12625     * logging fails if new content is loaded without
12626     * closing existing content
12627     * i.e. RARCH_PATH_CONTENT and RARCH_PATH_CORE get
12628     * updated when the new content is loaded, which
12629     * happens *before* command_event_runtime_log_deinit
12630     * -> using RARCH_PATH_CONTENT and RARCH_PATH_CORE
12631     *    directly in command_event_runtime_log_deinit
12632     *    can therefore lead to the runtime of the currently
12633     *    loaded content getting written to the *new*
12634     *    content's log file... */
12635    memset(p_rarch->runtime_content_path,
12636          0, sizeof(p_rarch->runtime_content_path));
12637    memset(p_rarch->runtime_core_path,
12638          0, sizeof(p_rarch->runtime_core_path));
12639 
12640    if (!string_is_empty(content_path))
12641       strlcpy(p_rarch->runtime_content_path,
12642             content_path,
12643             sizeof(p_rarch->runtime_content_path));
12644 
12645    if (!string_is_empty(core_path))
12646       strlcpy(p_rarch->runtime_core_path,
12647             core_path,
12648             sizeof(p_rarch->runtime_core_path));
12649 }
12650 
retroarch_set_frame_limit(struct rarch_state * p_rarch,float fastforward_ratio)12651 static INLINE void retroarch_set_frame_limit(
12652       struct rarch_state *p_rarch,
12653       float fastforward_ratio)
12654 {
12655    const struct retro_system_av_info* av_info = &p_rarch->video_driver_av_info;
12656 
12657    p_rarch->frame_limit_minimum_time = (fastforward_ratio < 1.0f) ? 0.0f :
12658          (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio));
12659 }
12660 
retroarch_get_runloop_fastforward_ratio(settings_t * settings,runloop_state_t * p_runloop)12661 static INLINE float retroarch_get_runloop_fastforward_ratio(
12662       settings_t *settings,
12663       runloop_state_t *p_runloop)
12664 {
12665    struct retro_fastforwarding_override *fastmotion_override =
12666          &p_runloop->fastmotion_override;
12667 
12668    return (fastmotion_override->fastforward && (fastmotion_override->ratio >= 0.0f)) ?
12669          fastmotion_override->ratio : settings->floats.fastforward_ratio;
12670 }
12671 
command_event_init_core(settings_t * settings,struct rarch_state * p_rarch,enum rarch_core_type type)12672 static bool command_event_init_core(
12673       settings_t *settings,
12674       struct rarch_state *p_rarch,
12675       enum rarch_core_type type)
12676 {
12677 #ifdef HAVE_CONFIGFILE
12678    bool auto_overrides_enable      = settings->bools.auto_overrides_enable;
12679    bool auto_remaps_enable         = false;
12680    const char *dir_input_remapping = NULL;
12681 #endif
12682    bool show_set_initial_disk_msg  = false;
12683    unsigned poll_type_behavior     = 0;
12684    float fastforward_ratio         = 0.0f;
12685    rarch_system_info_t *sys_info   = &runloop_state.system;
12686 
12687    if (!init_libretro_symbols(p_rarch,
12688             type, &p_rarch->current_core))
12689       return false;
12690    if (!p_rarch->current_core.retro_run)
12691       p_rarch->current_core.retro_run   = retro_run_null;
12692    p_rarch->current_core.symbols_inited = true;
12693 
12694    p_rarch->current_core.retro_get_system_info(&sys_info->info);
12695 
12696    if (!sys_info->info.library_name)
12697       sys_info->info.library_name = msg_hash_to_str(MSG_UNKNOWN);
12698    if (!sys_info->info.library_version)
12699       sys_info->info.library_version = "v0";
12700 
12701    fill_pathname_join_concat_noext(
12702          p_rarch->video_driver_title_buf,
12703          msg_hash_to_str(MSG_PROGRAM),
12704          " ",
12705          sys_info->info.library_name,
12706          sizeof(p_rarch->video_driver_title_buf));
12707    strlcat(p_rarch->video_driver_title_buf, " ",
12708          sizeof(p_rarch->video_driver_title_buf));
12709    strlcat(p_rarch->video_driver_title_buf,
12710          sys_info->info.library_version,
12711          sizeof(p_rarch->video_driver_title_buf));
12712 
12713    strlcpy(sys_info->valid_extensions,
12714          sys_info->info.valid_extensions ?
12715          sys_info->info.valid_extensions : DEFAULT_EXT,
12716          sizeof(sys_info->valid_extensions));
12717 
12718 #ifdef HAVE_CONFIGFILE
12719    if (auto_overrides_enable)
12720       runloop_state.overrides_active =
12721          config_load_override(&runloop_state.system);
12722 #endif
12723 
12724    /* Cannot access these settings-related parameters
12725     * until *after* config overrides have been loaded */
12726 #ifdef HAVE_CONFIGFILE
12727    auto_remaps_enable        = settings->bools.auto_remaps_enable;
12728    dir_input_remapping       = settings->paths.directory_input_remapping;
12729 #endif
12730    show_set_initial_disk_msg = settings->bools.notification_show_set_initial_disk;
12731    poll_type_behavior        = settings->uints.input_poll_type_behavior;
12732    fastforward_ratio         = retroarch_get_runloop_fastforward_ratio(
12733          settings, &runloop_state);
12734 
12735 #ifdef HAVE_CHEEVOS
12736    /* assume the core supports achievements unless it tells us otherwise */
12737    rcheevos_set_support_cheevos(true);
12738 #endif
12739 
12740    /* Load auto-shaders on the next occasion */
12741 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
12742    p_rarch->shader_presets_need_reload     = true;
12743    p_rarch->shader_delay_timer.timer_begin = false; /* not initialized */
12744    p_rarch->shader_delay_timer.timer_end   = false; /* not expired */
12745 #endif
12746 
12747    /* reset video format to libretro's default */
12748    p_rarch->video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555;
12749 
12750    p_rarch->current_core.retro_set_environment(rarch_environment_cb);
12751 
12752    /* Load any input remap files
12753     * > Note that we always cache the current global
12754     *   input settings when initialising a core
12755     *   (regardless of whether remap files are loaded)
12756     *   so settings can be restored when the core is
12757     *   unloaded - i.e. core remapping options modified
12758     *   at runtime should not 'bleed through' into the
12759     *   master config file */
12760    input_remapping_cache_global_config();
12761 #ifdef HAVE_CONFIGFILE
12762    if (auto_remaps_enable)
12763       config_load_remap(dir_input_remapping, &runloop_state.system);
12764 #endif
12765 
12766    /* Per-core saves: reset redirection paths */
12767    path_set_redirect(p_rarch, settings);
12768 
12769    video_driver_set_cached_frame_ptr(NULL);
12770 
12771    p_rarch->current_core.retro_init();
12772    p_rarch->current_core.inited          = true;
12773 
12774    /* Attempt to set initial disk index */
12775    disk_control_set_initial_index(
12776          &sys_info->disk_control,
12777          path_get(RARCH_PATH_CONTENT),
12778          p_rarch->current_savefile_dir);
12779 
12780    if (!event_init_content(settings, p_rarch))
12781       return false;
12782 
12783    /* Verify that initial disk index was set correctly */
12784    disk_control_verify_initial_index(&sys_info->disk_control,
12785          show_set_initial_disk_msg);
12786 
12787    if (!core_load(p_rarch, poll_type_behavior))
12788       return false;
12789 
12790    retroarch_set_frame_limit(p_rarch, fastforward_ratio);
12791    p_rarch->frame_limit_last_time = cpu_features_get_time_usec();
12792 
12793    command_event_runtime_log_init(p_rarch);
12794    return true;
12795 }
12796 
command_event_save_auto_state(bool savestate_auto_save,global_t * global,const enum rarch_core_type current_core_type)12797 static bool command_event_save_auto_state(
12798       bool savestate_auto_save,
12799       global_t *global,
12800       const enum rarch_core_type current_core_type)
12801 {
12802    bool ret                    = false;
12803    char savestate_name_auto[PATH_MAX_LENGTH];
12804 
12805    if (!global || !savestate_auto_save)
12806       return false;
12807    if (current_core_type == CORE_TYPE_DUMMY)
12808       return false;
12809 
12810    if (string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))))
12811       return false;
12812 
12813 #ifdef HAVE_CHEEVOS
12814    if (rcheevos_hardcore_active())
12815       return false;
12816 #endif
12817 
12818    savestate_name_auto[0]      = '\0';
12819 
12820    fill_pathname_noext(savestate_name_auto, global->name.savestate,
12821          ".auto", sizeof(savestate_name_auto));
12822 
12823    ret = content_save_state((const char*)savestate_name_auto, true, true);
12824    RARCH_LOG("%s \"%s\" %s.\n",
12825          msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO),
12826          savestate_name_auto, ret ?
12827          "succeeded" : "failed");
12828 
12829    return true;
12830 }
12831 
12832 #ifdef HAVE_CONFIGFILE
command_event_save_config(const char * config_path,char * s,size_t len)12833 static bool command_event_save_config(
12834       const char *config_path,
12835       char *s, size_t len)
12836 {
12837    bool path_exists = !string_is_empty(config_path);
12838    const char *str  = path_exists ? config_path :
12839       path_get(RARCH_PATH_CONFIG);
12840 
12841    if (path_exists && config_save_file(config_path))
12842    {
12843       snprintf(s, len, "%s \"%s\".",
12844             msg_hash_to_str(MSG_SAVED_NEW_CONFIG_TO),
12845             config_path);
12846       RARCH_LOG("[Config]: %s\n", s);
12847       return true;
12848    }
12849 
12850    if (!string_is_empty(str))
12851    {
12852       snprintf(s, len, "%s \"%s\".",
12853             msg_hash_to_str(MSG_FAILED_SAVING_CONFIG_TO),
12854             str);
12855       RARCH_ERR("[Config]: %s\n", s);
12856    }
12857 
12858    return false;
12859 }
12860 
12861 /**
12862  * command_event_save_core_config:
12863  *
12864  * Saves a new (core) configuration to a file. Filename is based
12865  * on heuristics to avoid typing.
12866  *
12867  * Returns: true (1) on success, otherwise false (0).
12868  **/
command_event_save_core_config(struct rarch_state * p_rarch,const char * dir_menu_config,const char * rarch_path_config)12869 static bool command_event_save_core_config(
12870       struct rarch_state *p_rarch,
12871       const char *dir_menu_config,
12872       const char *rarch_path_config)
12873 {
12874    char msg[128];
12875    char config_name[PATH_MAX_LENGTH];
12876    char config_path[PATH_MAX_LENGTH];
12877    char config_dir[PATH_MAX_LENGTH];
12878    bool found_path                 = false;
12879    bool overrides_active           = false;
12880    const char *core_path           = NULL;
12881 
12882    msg[0]                          = '\0';
12883    config_dir[0]                   = '\0';
12884 
12885    if (!string_is_empty(dir_menu_config))
12886       strlcpy(config_dir, dir_menu_config, sizeof(config_dir));
12887    else if (!string_is_empty(rarch_path_config)) /* Fallback */
12888       fill_pathname_basedir(config_dir, rarch_path_config,
12889             sizeof(config_dir));
12890 
12891    if (string_is_empty(config_dir))
12892    {
12893       runloop_msg_queue_push(msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
12894       RARCH_ERR("[Config]: %s\n", msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET));
12895       return false;
12896    }
12897 
12898    core_path                       = path_get(RARCH_PATH_CORE);
12899    config_name[0]                  = '\0';
12900    config_path[0]                  = '\0';
12901 
12902    /* Infer file name based on libretro core. */
12903    if (path_is_valid(core_path))
12904    {
12905       unsigned i;
12906       RARCH_LOG("%s\n", msg_hash_to_str(MSG_USING_CORE_NAME_FOR_NEW_CONFIG));
12907 
12908       /* In case of collision, find an alternative name. */
12909       for (i = 0; i < 16; i++)
12910       {
12911          char tmp[64];
12912 
12913          fill_pathname_base_noext(
12914                config_name,
12915                core_path,
12916                sizeof(config_name));
12917 
12918          fill_pathname_join(config_path, config_dir, config_name,
12919                sizeof(config_path));
12920 
12921          if (i)
12922             snprintf(tmp, sizeof(tmp), "-%u.cfg", i);
12923          else
12924          {
12925             tmp[0] = '\0';
12926             strlcpy(tmp, ".cfg", sizeof(tmp));
12927          }
12928 
12929          strlcat(config_path, tmp, sizeof(config_path));
12930 
12931          if (!path_is_valid(config_path))
12932          {
12933             found_path = true;
12934             break;
12935          }
12936       }
12937    }
12938 
12939    if (!found_path)
12940    {
12941       /* Fallback to system time... */
12942       RARCH_WARN("[Config]: %s\n",
12943             msg_hash_to_str(MSG_CANNOT_INFER_NEW_CONFIG_PATH));
12944       fill_dated_filename(config_name, ".cfg", sizeof(config_name));
12945       fill_pathname_join(config_path, config_dir, config_name,
12946             sizeof(config_path));
12947    }
12948 
12949    if (runloop_state.overrides_active)
12950    {
12951       /* Overrides block config file saving,
12952        * make it appear as overrides weren't enabled
12953        * for a manual save. */
12954       runloop_state.overrides_active = false;
12955       overrides_active                  = true;
12956    }
12957 
12958 #ifdef HAVE_CONFIGFILE
12959    command_event_save_config(config_path, msg, sizeof(msg));
12960 #endif
12961 
12962    if (!string_is_empty(msg))
12963       runloop_msg_queue_push(msg, 1, 180, true, NULL,
12964             MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
12965 
12966    runloop_state.overrides_active = overrides_active;
12967 
12968    return true;
12969 }
12970 
12971 /**
12972  * event_save_current_config:
12973  *
12974  * Saves current configuration file to disk, and (optionally)
12975  * autosave state.
12976  **/
command_event_save_current_config(struct rarch_state * p_rarch,enum override_type type)12977 static void command_event_save_current_config(
12978       struct rarch_state *p_rarch,
12979       enum override_type type)
12980 {
12981    char msg[128];
12982 
12983    msg[0] = '\0';
12984 
12985    switch (type)
12986    {
12987       case OVERRIDE_NONE:
12988          if (path_is_empty(RARCH_PATH_CONFIG))
12989             strcpy_literal(msg, "[Config]: Config directory not set, cannot save configuration.");
12990          else
12991             command_event_save_config(path_get(RARCH_PATH_CONFIG), msg, sizeof(msg));
12992          break;
12993       case OVERRIDE_GAME:
12994       case OVERRIDE_CORE:
12995       case OVERRIDE_CONTENT_DIR:
12996          if (config_save_overrides(type, &runloop_state.system))
12997          {
12998             strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_SAVED_SUCCESSFULLY), sizeof(msg));
12999             RARCH_LOG("[Config - Overrides]: %s\n", msg);
13000 
13001             /* set overrides to active so the original config can be
13002                restored after closing content */
13003             runloop_state.overrides_active = true;
13004          }
13005          else
13006          {
13007             strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_ERROR_SAVING), sizeof(msg));
13008             RARCH_ERR("[Config - Overrides]: %s\n", msg);
13009          }
13010          break;
13011    }
13012 
13013    if (!string_is_empty(msg))
13014       runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13015 }
13016 #endif
13017 
command_event_undo_save_state(char * s,size_t len)13018 static void command_event_undo_save_state(char *s, size_t len)
13019 {
13020    if (content_undo_save_buf_is_empty())
13021    {
13022       strlcpy(s,
13023          msg_hash_to_str(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET), len);
13024       return;
13025    }
13026 
13027    if (!content_undo_save_state())
13028    {
13029       strlcpy(s,
13030          msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE), len);
13031       return;
13032    }
13033 
13034    strlcpy(s,
13035          msg_hash_to_str(MSG_UNDOING_SAVE_STATE), len);
13036 }
13037 
command_event_undo_load_state(char * s,size_t len)13038 static void command_event_undo_load_state(char *s, size_t len)
13039 {
13040 
13041    if (content_undo_load_buf_is_empty())
13042    {
13043       strlcpy(s,
13044          msg_hash_to_str(MSG_NO_STATE_HAS_BEEN_LOADED_YET),
13045          len);
13046       return;
13047    }
13048 
13049    if (!content_undo_load_state())
13050    {
13051       snprintf(s, len, "%s \"%s\".",
13052             msg_hash_to_str(MSG_FAILED_TO_UNDO_LOAD_STATE),
13053             "RAM");
13054       return;
13055    }
13056 
13057 #ifdef HAVE_NETWORKING
13058    netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
13059 #endif
13060 
13061    strlcpy(s,
13062          msg_hash_to_str(MSG_UNDID_LOAD_STATE), len);
13063 }
13064 
command_event_main_state(struct rarch_state * p_rarch,unsigned cmd)13065 static bool command_event_main_state(
13066       struct rarch_state *p_rarch,
13067       unsigned cmd)
13068 {
13069    retro_ctx_size_info_t info;
13070    char msg[128];
13071    char state_path[16384];
13072    const global_t *global      = &p_rarch->g_extern;
13073    settings_t *settings        = p_rarch->configuration_settings;
13074    bool ret                    = false;
13075    bool push_msg               = true;
13076 
13077    state_path[0] = msg[0]      = '\0';
13078 
13079    if (global)
13080    {
13081       int state_slot             = settings->ints.state_slot;
13082       const char *name_savestate = global->name.savestate;
13083 
13084       if (state_slot > 0)
13085          snprintf(state_path, sizeof(state_path), "%s%d",
13086                name_savestate, state_slot);
13087       else if (state_slot < 0)
13088          fill_pathname_join_delim(state_path,
13089                name_savestate, "auto", '.', sizeof(state_path));
13090       else
13091          strlcpy(state_path, name_savestate, sizeof(state_path));
13092    }
13093 
13094    core_serialize_size(&info);
13095 
13096    if (info.size)
13097    {
13098       switch (cmd)
13099       {
13100          case CMD_EVENT_SAVE_STATE:
13101             {
13102                bool savestate_auto_index                      =
13103                      settings->bools.savestate_auto_index;
13104                unsigned savestate_max_keep                    =
13105                      settings->uints.savestate_max_keep;
13106                bool frame_time_counter_reset_after_save_state =
13107                      settings->bools.frame_time_counter_reset_after_save_state;
13108 
13109                content_save_state(state_path, true, false);
13110 
13111                /* Clean up excess savestates if necessary */
13112                if (savestate_auto_index && (savestate_max_keep > 0))
13113                   command_event_set_savestate_garbage_collect(global,
13114                         p_rarch,
13115                         settings->uints.savestate_max_keep,
13116                         settings->bools.show_hidden_files
13117                         );
13118 
13119                if (frame_time_counter_reset_after_save_state)
13120                   p_rarch->video_driver_frame_time_count = 0;
13121 
13122                ret      = true;
13123                push_msg = false;
13124             }
13125             break;
13126          case CMD_EVENT_LOAD_STATE:
13127             if (content_load_state(state_path, false, false))
13128             {
13129 #ifdef HAVE_CHEEVOS
13130                if (rcheevos_hardcore_active())
13131                {
13132                   rcheevos_pause_hardcore();
13133                   runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED), 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13134                }
13135 #endif
13136                ret = true;
13137 #ifdef HAVE_NETWORKING
13138                netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
13139 #endif
13140                {
13141                   bool frame_time_counter_reset_after_load_state =
13142                      settings->bools.frame_time_counter_reset_after_load_state;
13143                   if (frame_time_counter_reset_after_load_state)
13144                      p_rarch->video_driver_frame_time_count = 0;
13145                }
13146             }
13147             push_msg = false;
13148             break;
13149          case CMD_EVENT_UNDO_LOAD_STATE:
13150             command_event_undo_load_state(msg, sizeof(msg));
13151             ret = true;
13152             break;
13153          case CMD_EVENT_UNDO_SAVE_STATE:
13154             command_event_undo_save_state(msg, sizeof(msg));
13155             ret = true;
13156             break;
13157       }
13158    }
13159    else
13160       strlcpy(msg, msg_hash_to_str(
13161                MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES), sizeof(msg));
13162 
13163    if (push_msg)
13164       runloop_msg_queue_push(msg, 2, 180, true, NULL,
13165             MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13166 
13167    if (!string_is_empty(msg))
13168       RARCH_LOG("%s\n", msg);
13169 
13170    return ret;
13171 }
13172 
command_event_resize_windowed_scale(struct rarch_state * p_rarch)13173 static bool command_event_resize_windowed_scale(struct rarch_state *p_rarch)
13174 {
13175    unsigned                idx = 0;
13176    settings_t      *settings   = p_rarch->configuration_settings;
13177    unsigned      window_scale  = runloop_state.pending_windowed_scale;
13178    bool      video_fullscreen  = settings->bools.video_fullscreen;
13179 
13180    if (window_scale == 0)
13181       return false;
13182 
13183    configuration_set_float(settings, settings->floats.video_scale, (float)window_scale);
13184 
13185    if (!video_fullscreen)
13186       command_event(CMD_EVENT_REINIT, NULL);
13187 
13188    rarch_ctl(RARCH_CTL_SET_WINDOWED_SCALE, &idx);
13189 
13190    return true;
13191 }
13192 
input_remapping_cache_global_config(void)13193 void input_remapping_cache_global_config(void)
13194 {
13195    struct rarch_state *p_rarch = &rarch_st;
13196    settings_t *settings        = p_rarch->configuration_settings;
13197    global_t *global            = &p_rarch->g_extern;
13198    unsigned i;
13199 
13200    for (i = 0; i < MAX_USERS; i++)
13201    {
13202       global->old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i];
13203       global->old_libretro_device[i]  = settings->uints.input_libretro_device[i];
13204    }
13205 
13206    global->old_analog_dpad_mode_set = true;
13207    global->old_libretro_device_set  = true;
13208 }
13209 
input_remapping_enable_global_config_restore(void)13210 void input_remapping_enable_global_config_restore(void)
13211 {
13212    struct rarch_state *p_rarch    = &rarch_st;
13213    global_t *global               = &p_rarch->g_extern;
13214    global->remapping_cache_active = true;
13215 }
13216 
input_remapping_restore_global_config(bool clear_cache)13217 void input_remapping_restore_global_config(bool clear_cache)
13218 {
13219    struct rarch_state *p_rarch = &rarch_st;
13220    settings_t *settings        = p_rarch->configuration_settings;
13221    global_t *global            = &p_rarch->g_extern;
13222    unsigned i;
13223 
13224    if (!global->remapping_cache_active)
13225       goto end;
13226 
13227    for (i = 0; i < MAX_USERS; i++)
13228    {
13229       if (global->old_analog_dpad_mode_set &&
13230           (settings->uints.input_analog_dpad_mode[i] !=
13231                global->old_analog_dpad_mode[i]))
13232          configuration_set_uint(settings,
13233                settings->uints.input_analog_dpad_mode[i],
13234                global->old_analog_dpad_mode[i]);
13235 
13236       if (global->old_libretro_device_set &&
13237           (settings->uints.input_libretro_device[i] !=
13238                global->old_libretro_device[i]))
13239          configuration_set_uint(settings,
13240                settings->uints.input_libretro_device[i],
13241                global->old_libretro_device[i]);
13242    }
13243 
13244 end:
13245    if (clear_cache)
13246    {
13247       global->old_analog_dpad_mode_set = false;
13248       global->old_libretro_device_set  = false;
13249       global->remapping_cache_active   = false;
13250    }
13251 }
13252 
input_remapping_update_port_map(void)13253 void input_remapping_update_port_map(void)
13254 {
13255    unsigned i, j;
13256    struct rarch_state *p_rarch        = &rarch_st;
13257    settings_t *settings               = p_rarch->configuration_settings;
13258    unsigned port_map_index[MAX_USERS] = {0};
13259 
13260    /* First pass: 'reset' port map */
13261    for (i = 0; i < MAX_USERS; i++)
13262       for (j = 0; j < (MAX_USERS + 1); j++)
13263          settings->uints.input_remap_port_map[i][j] = MAX_USERS;
13264 
13265    /* Second pass: assign port indices from
13266     * 'input_remap_ports' */
13267    for (i = 0; i < MAX_USERS; i++)
13268    {
13269       unsigned remap_port = settings->uints.input_remap_ports[i];
13270 
13271       if (remap_port < MAX_USERS)
13272       {
13273          /* 'input_remap_port_map' provides a list of
13274           * 'physical' ports for each 'virtual' port
13275           * sampled in input_state().
13276           * (Note: in the following explanation, port
13277           * index starts from 0, rather than the frontend
13278           * display convention of 1)
13279           * For example - the following remap configuration
13280           * will map input devices 0+1 to port 0, and input
13281           * device 2 to port 1
13282           * > input_remap_ports[0] = 0;
13283           *   input_remap_ports[1] = 0;
13284           *   input_remap_ports[2] = 1;
13285           * This gives a port map of:
13286           * > input_remap_port_map[0] = { 0, 1, MAX_USERS, ... };
13287           *   input_remap_port_map[1] = { 2, MAX_USERS, ... }
13288           *   input_remap_port_map[2] = { MAX_USERS, ... }
13289           *   ...
13290           * A port map value of MAX_USERS indicates the end
13291           * of the 'physical' port list */
13292          settings->uints.input_remap_port_map[remap_port]
13293                [port_map_index[remap_port]] = i;
13294          port_map_index[remap_port]++;
13295       }
13296    }
13297 }
13298 
input_remapping_deinit(void)13299 void input_remapping_deinit(void)
13300 {
13301    struct rarch_state *p_rarch = &rarch_st;
13302    global_t *global            = &p_rarch->g_extern;
13303    if (global->name.remapfile)
13304       free(global->name.remapfile);
13305    global->name.remapfile                  = NULL;
13306    runloop_state.remaps_core_active        = false;
13307    runloop_state.remaps_content_dir_active = false;
13308    runloop_state.remaps_game_active        = false;
13309 }
13310 
input_remapping_set_defaults(bool clear_cache)13311 void input_remapping_set_defaults(bool clear_cache)
13312 {
13313    unsigned i, j;
13314    struct rarch_state *p_rarch = &rarch_st;
13315    settings_t *settings        = p_rarch->configuration_settings;
13316 
13317    for (i = 0; i < MAX_USERS; i++)
13318    {
13319       /* Button/keyboard remaps */
13320       for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++)
13321       {
13322          const struct retro_keybind *keybind = &input_config_binds[i][j];
13323 
13324          configuration_set_uint(settings,
13325                settings->uints.input_remap_ids[i][j],
13326                      keybind ? keybind->id : RARCH_UNMAPPED);
13327 
13328          configuration_set_uint(settings,
13329                settings->uints.input_keymapper_ids[i][j], RETROK_UNKNOWN);
13330       }
13331 
13332       /* Analog stick remaps */
13333       for (j = RARCH_FIRST_CUSTOM_BIND; j < (RARCH_FIRST_CUSTOM_BIND + 8); j++)
13334          configuration_set_uint(settings,
13335                settings->uints.input_remap_ids[i][j], j);
13336 
13337       /* Controller port remaps */
13338       configuration_set_uint(settings,
13339             settings->uints.input_remap_ports[i], i);
13340    }
13341 
13342    /* Need to call 'input_remapping_update_port_map()'
13343     * whenever 'settings->uints.input_remap_ports'
13344     * is modified */
13345    input_remapping_update_port_map();
13346 
13347    /* Restore 'global' settings that were cached on
13348     * the last core init
13349     * > Prevents remap changes from 'bleeding through'
13350     *   into the main config file */
13351    input_remapping_restore_global_config(clear_cache);
13352 }
13353 
input_driver_grab_mouse(struct rarch_state * p_rarch)13354 static bool input_driver_grab_mouse(struct rarch_state *p_rarch)
13355 {
13356    if (!p_rarch->current_input || !p_rarch->current_input->grab_mouse)
13357       return false;
13358 
13359    p_rarch->current_input->grab_mouse(p_rarch->current_input_data, true);
13360    p_rarch->input_driver_grab_mouse_state = true;
13361    return true;
13362 }
13363 
input_driver_ungrab_mouse(struct rarch_state * p_rarch)13364 static bool input_driver_ungrab_mouse(struct rarch_state *p_rarch)
13365 {
13366    if (!p_rarch->current_input || !p_rarch->current_input->grab_mouse)
13367       return false;
13368 
13369    p_rarch->current_input->grab_mouse(p_rarch->current_input_data, false);
13370    p_rarch->input_driver_grab_mouse_state = false;
13371    return true;
13372 }
13373 
command_event_reinit(struct rarch_state * p_rarch,const int flags)13374 static void command_event_reinit(struct rarch_state *p_rarch,
13375       const int flags)
13376 {
13377    settings_t *settings        = p_rarch->configuration_settings;
13378 #ifdef HAVE_MENU
13379    bool video_fullscreen       = settings->bools.video_fullscreen;
13380    bool adaptive_vsync         = settings->bools.video_adaptive_vsync;
13381    unsigned swap_interval      = settings->uints.video_swap_interval;
13382 #endif
13383    enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_REAPPLY;
13384 
13385    video_driver_reinit(flags);
13386    /* Poll input to avoid possibly stale data to corrupt things. */
13387    if (  p_rarch->joypad &&
13388          p_rarch->joypad->poll)
13389       p_rarch->joypad->poll();
13390 #ifdef HAVE_MFI
13391    if (  p_rarch->sec_joypad &&
13392          p_rarch->sec_joypad->poll)
13393       p_rarch->sec_joypad->poll();
13394 #endif
13395    if (  p_rarch->current_input &&
13396          p_rarch->current_input->poll)
13397       p_rarch->current_input->poll(p_rarch->current_input_data);
13398    command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
13399 
13400 #ifdef HAVE_MENU
13401    p_rarch->dispgfx.framebuf_dirty = true;
13402    if (video_fullscreen)
13403       video_driver_hide_mouse();
13404    if (p_rarch->menu_driver_alive && p_rarch->current_video->set_nonblock_state)
13405       p_rarch->current_video->set_nonblock_state(
13406             p_rarch->video_driver_data, false,
13407             video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
13408             adaptive_vsync,
13409             swap_interval);
13410 #endif
13411 }
13412 
retroarch_pause_checks(struct rarch_state * p_rarch)13413 static void retroarch_pause_checks(struct rarch_state *p_rarch)
13414 {
13415 #ifdef HAVE_DISCORD
13416    discord_userdata_t userdata;
13417 #endif
13418    bool is_paused                 = runloop_state.paused;
13419    bool is_idle                   = runloop_state.idle;
13420 #if defined(HAVE_GFX_WIDGETS)
13421    bool widgets_active            = p_rarch->widgets_active;
13422 
13423    if (widgets_active)
13424       p_rarch->gfx_widgets_paused = is_paused;
13425 #endif
13426 
13427    if (is_paused)
13428    {
13429       RARCH_LOG("[Core]: %s\n", msg_hash_to_str(MSG_PAUSED));
13430 
13431 #if defined(HAVE_GFX_WIDGETS)
13432       if (!widgets_active)
13433 #endif
13434          runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1,
13435                1, true,
13436                NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13437 
13438 
13439       if (!is_idle)
13440          video_driver_cached_frame();
13441 
13442 #ifdef HAVE_DISCORD
13443       userdata.status = DISCORD_PRESENCE_GAME_PAUSED;
13444       command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
13445 #endif
13446 
13447 #ifdef HAVE_LAKKA
13448       set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_MENU);
13449 #endif
13450    }
13451    else
13452    {
13453       RARCH_LOG("[Core]: %s\n", msg_hash_to_str(MSG_UNPAUSED));
13454 
13455 #ifdef HAVE_LAKKA
13456       set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_CORE);
13457 #endif
13458    }
13459 
13460 #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
13461    if (p_rarch->dispwidget_st.ai_service_overlay_state == 1)
13462       gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
13463 #endif
13464 }
13465 
retroarch_frame_time_free(struct rarch_state * p_rarch)13466 static void retroarch_frame_time_free(struct rarch_state *p_rarch)
13467 {
13468    memset(&runloop_state.frame_time, 0,
13469          sizeof(struct retro_frame_time_callback));
13470    runloop_state.frame_time_last  = 0;
13471    runloop_state.max_frames       = 0;
13472 }
13473 
retroarch_audio_buffer_status_free(struct rarch_state * p_rarch)13474 static void retroarch_audio_buffer_status_free(struct rarch_state *p_rarch)
13475 {
13476    memset(&runloop_state.audio_buffer_status, 0,
13477          sizeof(struct retro_audio_buffer_status_callback));
13478    runloop_state.audio_latency = 0;
13479 }
13480 
retroarch_game_focus_free(struct rarch_state * p_rarch)13481 static void retroarch_game_focus_free(struct rarch_state *p_rarch)
13482 {
13483    /* Ensure that game focus mode is disabled */
13484    if (p_rarch->game_focus_state.enabled)
13485    {
13486       enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_OFF;
13487       command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
13488    }
13489 
13490    p_rarch->game_focus_state.enabled        = false;
13491    p_rarch->game_focus_state.core_requested = false;
13492 }
13493 
retroarch_fastmotion_override_free(struct rarch_state * p_rarch,runloop_state_t * p_runloop)13494 static void retroarch_fastmotion_override_free(struct rarch_state *p_rarch,
13495       runloop_state_t *p_runloop)
13496 {
13497    settings_t *settings    = p_rarch->configuration_settings;
13498    float fastforward_ratio = settings->floats.fastforward_ratio;
13499    bool reset_frame_limit  = p_runloop->fastmotion_override.fastforward &&
13500          (p_runloop->fastmotion_override.ratio >= 0.0f) &&
13501          (p_runloop->fastmotion_override.ratio != fastforward_ratio);
13502 
13503    p_runloop->fastmotion_override.ratio          = 0.0f;
13504    p_runloop->fastmotion_override.fastforward    = false;
13505    p_runloop->fastmotion_override.notification   = false;
13506    p_runloop->fastmotion_override.inhibit_toggle = false;
13507 
13508    if (reset_frame_limit)
13509       retroarch_set_frame_limit(p_rarch, fastforward_ratio);
13510 }
13511 
retroarch_system_info_free(struct rarch_state * p_rarch)13512 static void retroarch_system_info_free(struct rarch_state *p_rarch)
13513 {
13514    rarch_system_info_t        *sys_info   = &runloop_state.system;
13515 
13516    if (sys_info->subsystem.data)
13517       free(sys_info->subsystem.data);
13518    sys_info->subsystem.data                           = NULL;
13519    sys_info->subsystem.size                           = 0;
13520 
13521    if (sys_info->ports.data)
13522       free(sys_info->ports.data);
13523    sys_info->ports.data                               = NULL;
13524    sys_info->ports.size                               = 0;
13525 
13526    if (sys_info->mmaps.descriptors)
13527       free((void *)sys_info->mmaps.descriptors);
13528    sys_info->mmaps.descriptors                        = NULL;
13529    sys_info->mmaps.num_descriptors                    = 0;
13530 
13531    runloop_state.key_event                         = NULL;
13532    runloop_state.frontend_key_event                = NULL;
13533 
13534    p_rarch->audio_callback.callback                   = NULL;
13535    p_rarch->audio_callback.set_state                  = NULL;
13536 
13537    sys_info->info.library_name                        = NULL;
13538    sys_info->info.library_version                     = NULL;
13539    sys_info->info.valid_extensions                    = NULL;
13540    sys_info->info.need_fullpath                       = false;
13541    sys_info->info.block_extract                       = false;
13542 
13543    memset(&runloop_state.system, 0, sizeof(rarch_system_info_t));
13544 }
13545 
13546 static bool libretro_get_system_info(
13547       struct rarch_state *p_rarch,
13548       const char *path,
13549       struct retro_system_info *info,
13550       bool *load_no_content);
13551 
13552 #ifdef HAVE_RUNAHEAD
runahead_clear_variables(struct rarch_state * p_rarch)13553 static void runahead_clear_variables(struct rarch_state *p_rarch)
13554 {
13555    p_rarch->runahead_save_state_size          = 0;
13556    p_rarch->runahead_save_state_size_known    = false;
13557    p_rarch->runahead_video_driver_is_active   = true;
13558    p_rarch->runahead_available                = true;
13559    p_rarch->runahead_secondary_core_available = true;
13560    p_rarch->runahead_force_input_dirty        = true;
13561    p_rarch->runahead_last_frame_count         = 0;
13562 }
13563 #endif
13564 
13565 /**
13566  * command_event:
13567  * @cmd                  : Event command index.
13568  *
13569  * Performs program event command with index @cmd.
13570  *
13571  * Returns: true (1) on success, otherwise false (0).
13572  **/
command_event(enum event_command cmd,void * data)13573 bool command_event(enum event_command cmd, void *data)
13574 {
13575    bool boolean                = false;
13576    struct rarch_state *p_rarch = &rarch_st;
13577    settings_t *settings        = p_rarch->configuration_settings;
13578 
13579    switch (cmd)
13580    {
13581       case CMD_EVENT_SAVE_FILES:
13582          event_save_files(p_rarch->rarch_use_sram);
13583          break;
13584       case CMD_EVENT_OVERLAY_DEINIT:
13585 #ifdef HAVE_OVERLAY
13586          retroarch_overlay_deinit(p_rarch);
13587 #endif
13588 #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
13589          /* Because the overlay is a display widget,
13590           * it's going to be written
13591           * over the menu, so we unset it here. */
13592          if (p_rarch->dispwidget_st.ai_service_overlay_state != 0)
13593             gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
13594 #endif
13595          break;
13596       case CMD_EVENT_OVERLAY_INIT:
13597 #ifdef HAVE_OVERLAY
13598          retroarch_overlay_init(p_rarch);
13599 #endif
13600          break;
13601       case CMD_EVENT_CHEAT_INDEX_PLUS:
13602 #ifdef HAVE_CHEATS
13603          cheat_manager_index_next();
13604 #endif
13605          break;
13606       case CMD_EVENT_CHEAT_INDEX_MINUS:
13607 #ifdef HAVE_CHEATS
13608          cheat_manager_index_prev();
13609 #endif
13610          break;
13611       case CMD_EVENT_CHEAT_TOGGLE:
13612 #ifdef HAVE_CHEATS
13613          cheat_manager_toggle();
13614 #endif
13615          break;
13616       case CMD_EVENT_SHADER_NEXT:
13617 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
13618          dir_check_shader(p_rarch, settings, &p_rarch->dir_shader_list, true, false);
13619 #endif
13620          break;
13621       case CMD_EVENT_SHADER_PREV:
13622 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
13623          dir_check_shader(p_rarch, settings, &p_rarch->dir_shader_list, false, true);
13624 #endif
13625          break;
13626       case CMD_EVENT_BSV_RECORDING_TOGGLE:
13627 #ifdef HAVE_BSV_MOVIE
13628          if (!recording_is_enabled())
13629             command_event(CMD_EVENT_RECORD_INIT, NULL);
13630          else
13631             command_event(CMD_EVENT_RECORD_DEINIT, NULL);
13632          bsv_movie_check(p_rarch, settings);
13633 #endif
13634          break;
13635       case CMD_EVENT_AI_SERVICE_TOGGLE:
13636          {
13637 #ifdef HAVE_TRANSLATE
13638             bool ai_service_pause     = settings->bools.ai_service_pause;
13639 
13640             if (!settings->bools.ai_service_enable)
13641                break;
13642 
13643             if (ai_service_pause)
13644             {
13645                /* pause on call, unpause on second press. */
13646                if (!runloop_state.paused)
13647                {
13648                   command_event(CMD_EVENT_PAUSE, NULL);
13649                   command_event(CMD_EVENT_AI_SERVICE_CALL, NULL);
13650                }
13651                else
13652                {
13653 #ifdef HAVE_ACCESSIBILITY
13654                   bool accessibility_enable = settings->bools.accessibility_enable;
13655                   unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
13656                   if (is_accessibility_enabled(
13657                            accessibility_enable,
13658                            p_rarch->accessibility_enabled))
13659                      accessibility_speak_priority(p_rarch,
13660                            accessibility_enable,
13661                            accessibility_narrator_speech_speed,
13662                            (char*)msg_hash_to_str(MSG_UNPAUSED), 10);
13663 #endif
13664                   command_event(CMD_EVENT_UNPAUSE, NULL);
13665                }
13666             }
13667             else
13668             {
13669                /* Don't pause - useful for Text-To-Speech since
13670                 * the audio can't currently play while paused.
13671                 * Also useful for cases when users don't want the
13672                 * core's sound to stop while translating.
13673                 *
13674                 * Also, this mode is required for "auto" translation
13675                 * packages, since you don't want to pause for that.
13676                 */
13677                if (p_rarch->ai_service_auto == 2)
13678                {
13679                   /* Auto mode was turned on, but we pressed the
13680                    * toggle button, so turn it off now. */
13681                   p_rarch->ai_service_auto = 0;
13682 #ifdef HAVE_MENU_WIDGETS
13683                   gfx_widgets_ai_service_overlay_unload(&p_rarch->dispwidget_st);
13684 #endif
13685                }
13686                else
13687                   command_event(CMD_EVENT_AI_SERVICE_CALL, NULL);
13688             }
13689 #endif
13690             break;
13691          }
13692       case CMD_EVENT_STREAMING_TOGGLE:
13693          if (streaming_is_enabled())
13694             command_event(CMD_EVENT_RECORD_DEINIT, NULL);
13695          else
13696          {
13697             streaming_set_state(true);
13698             command_event(CMD_EVENT_RECORD_INIT, NULL);
13699          }
13700          break;
13701       case CMD_EVENT_RUNAHEAD_TOGGLE:
13702          {
13703             char msg[256];
13704             msg[0] = '\0';
13705 
13706             settings->bools.run_ahead_enabled =
13707                !(settings->bools.run_ahead_enabled);
13708 
13709             if (!settings->bools.run_ahead_enabled)
13710             {
13711                runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_DISABLED),
13712                      1, 100, false,
13713                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13714             }
13715             else if (!settings->bools.run_ahead_secondary_instance)
13716             {
13717                snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED),
13718                      settings->uints.run_ahead_frames);
13719 
13720                runloop_msg_queue_push(
13721                      msg, 1, 100, false,
13722                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13723             }
13724             else
13725             {
13726                snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE),
13727                      settings->uints.run_ahead_frames);
13728 
13729                runloop_msg_queue_push(
13730                      msg, 1, 100, false,
13731                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13732             }
13733          }
13734          break;
13735       case CMD_EVENT_RECORDING_TOGGLE:
13736          if (recording_is_enabled())
13737             command_event(CMD_EVENT_RECORD_DEINIT, NULL);
13738          else
13739             command_event(CMD_EVENT_RECORD_INIT, NULL);
13740          break;
13741       case CMD_EVENT_OSK_TOGGLE:
13742          if (p_rarch->input_driver_keyboard_linefeed_enable)
13743             p_rarch->input_driver_keyboard_linefeed_enable = false;
13744          else
13745             p_rarch->input_driver_keyboard_linefeed_enable = true;
13746          break;
13747       case CMD_EVENT_SET_PER_GAME_RESOLUTION:
13748 #if defined(GEKKO)
13749          {
13750             unsigned width = 0, height = 0;
13751 
13752             command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
13753 
13754             if (video_driver_get_video_output_size(&width, &height))
13755             {
13756                char msg[128] = {0};
13757 
13758                video_driver_set_video_mode(width, height, true);
13759 
13760                if (width == 0 || height == 0)
13761                   snprintf(msg, sizeof(msg), "%s: DEFAULT",
13762                         msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION));
13763                else
13764                   snprintf(msg, sizeof(msg),"%s: %dx%d",
13765                         msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION),
13766                         width, height);
13767                runloop_msg_queue_push(msg, 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13768             }
13769          }
13770 #endif
13771          break;
13772       case CMD_EVENT_LOAD_CORE_PERSIST:
13773          {
13774             rarch_system_info_t *system_info = &runloop_state.system;
13775             struct retro_system_info *system = &system_info->info;
13776             const char *core_path            = path_get(RARCH_PATH_CORE);
13777 
13778 #if defined(HAVE_DYNAMIC)
13779             if (string_is_empty(core_path))
13780                return false;
13781 #endif
13782 
13783             if (!libretro_get_system_info(
13784                      p_rarch,
13785                      core_path,
13786                      system,
13787                      &system_info->load_no_content))
13788                return false;
13789 
13790             if (!core_info_load(core_path, &p_rarch->core_info_st))
13791             {
13792 #ifdef HAVE_DYNAMIC
13793                return false;
13794 #endif
13795             }
13796          }
13797          break;
13798       case CMD_EVENT_LOAD_CORE:
13799          {
13800             bool success            = false;
13801             subsystem_current_count = 0;
13802             content_clear_subsystem();
13803             success = command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
13804             (void)success;
13805 
13806 #ifndef HAVE_DYNAMIC
13807             command_event(CMD_EVENT_QUIT, NULL);
13808 #else
13809             if (!success)
13810                return false;
13811 #endif
13812             break;
13813          }
13814       case CMD_EVENT_LOAD_STATE:
13815 #ifdef HAVE_BSV_MOVIE
13816          /* Immutable - disallow savestate load when
13817           * we absolutely cannot change game state. */
13818          if (p_rarch->bsv_movie_state_handle)
13819             return false;
13820 #endif
13821 
13822 #ifdef HAVE_CHEEVOS
13823          if (rcheevos_hardcore_active())
13824             return false;
13825 #endif
13826          if (!command_event_main_state(p_rarch, cmd))
13827             return false;
13828          break;
13829       case CMD_EVENT_UNDO_LOAD_STATE:
13830          if (!command_event_main_state(p_rarch, cmd))
13831             return false;
13832          break;
13833       case CMD_EVENT_UNDO_SAVE_STATE:
13834          if (!command_event_main_state(p_rarch, cmd))
13835             return false;
13836          break;
13837       case CMD_EVENT_RESIZE_WINDOWED_SCALE:
13838          if (!command_event_resize_windowed_scale(p_rarch))
13839             return false;
13840          break;
13841       case CMD_EVENT_MENU_TOGGLE:
13842 #ifdef HAVE_MENU
13843          if (p_rarch->menu_driver_alive)
13844             retroarch_menu_running_finished(false);
13845          else
13846             retroarch_menu_running();
13847 #endif
13848          break;
13849       case CMD_EVENT_RESET:
13850          RARCH_LOG("[Core]: %s.\n", msg_hash_to_str(MSG_RESET));
13851          runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
13852 
13853          core_reset();
13854 #ifdef HAVE_CHEEVOS
13855 #ifdef HAVE_GFX_WIDGETS
13856          rcheevos_reset_game(p_rarch->widgets_active);
13857 #else
13858          rcheevos_reset_game(false);
13859 #endif
13860 #endif
13861 #if HAVE_NETWORKING
13862          netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL);
13863 #endif
13864          return false;
13865       case CMD_EVENT_SAVE_STATE:
13866          {
13867             bool savestate_auto_index = settings->bools.savestate_auto_index;
13868             int state_slot            = settings->ints.state_slot;
13869 
13870             if (savestate_auto_index)
13871             {
13872                int new_state_slot = state_slot + 1;
13873                configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
13874             }
13875          }
13876          if (!command_event_main_state(p_rarch, cmd))
13877             return false;
13878          break;
13879       case CMD_EVENT_SAVE_STATE_DECREMENT:
13880          {
13881             int state_slot            = settings->ints.state_slot;
13882 
13883             /* Slot -1 is (auto) slot. */
13884             if (state_slot >= 0)
13885             {
13886                int new_state_slot = state_slot - 1;
13887                configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
13888             }
13889          }
13890          break;
13891       case CMD_EVENT_SAVE_STATE_INCREMENT:
13892          {
13893             int new_state_slot        = settings->ints.state_slot + 1;
13894             configuration_set_int(settings, settings->ints.state_slot, new_state_slot);
13895          }
13896          break;
13897       case CMD_EVENT_TAKE_SCREENSHOT:
13898 #ifdef HAVE_SCREENSHOTS
13899          {
13900             const char *dir_screenshot = settings->paths.directory_screenshot;
13901             if (!take_screenshot(dir_screenshot,
13902                      path_get(RARCH_PATH_BASENAME), false,
13903                      video_driver_cached_frame_has_valid_framebuffer(), false, true))
13904                return false;
13905          }
13906 #endif
13907          break;
13908       case CMD_EVENT_UNLOAD_CORE:
13909          {
13910             bool contentless                = false;
13911             bool is_inited                  = false;
13912             content_ctx_info_t content_info = {0};
13913             global_t   *global              = &p_rarch->g_extern;
13914             rarch_system_info_t *sys_info   = &runloop_state.system;
13915 
13916             content_get_status(&contentless, &is_inited);
13917 
13918             runloop_state.core_running   = false;
13919 
13920             /* Save last selected disk index, if required */
13921             if (sys_info)
13922                disk_control_save_image_index(&sys_info->disk_control);
13923 
13924             command_event_runtime_log_deinit(p_rarch,
13925                   settings->bools.content_runtime_log,
13926                   settings->bools.content_runtime_log_aggregate,
13927                   settings->paths.directory_runtime_log,
13928                   settings->paths.directory_playlist);
13929             command_event_save_auto_state(settings->bools.savestate_auto_save,
13930                   global, p_rarch->current_core_type);
13931 
13932 #ifdef HAVE_CONFIGFILE
13933             if (runloop_state.overrides_active)
13934             {
13935                command_event_disable_overrides(p_rarch);
13936 
13937                if (!settings->bools.video_fullscreen)
13938                {
13939                   video_driver_show_mouse();
13940                   input_driver_ungrab_mouse(p_rarch);
13941                }
13942             }
13943 #endif
13944 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
13945             p_rarch->runtime_shader_preset[0] = '\0';
13946 #endif
13947 
13948             video_driver_restore_cached(p_rarch, settings);
13949 
13950             if (     runloop_state.remaps_core_active
13951                   || runloop_state.remaps_content_dir_active
13952                   || runloop_state.remaps_game_active
13953                )
13954             {
13955                input_remapping_deinit();
13956                input_remapping_set_defaults(true);
13957             }
13958             else
13959                input_remapping_restore_global_config(true);
13960 
13961             if (is_inited)
13962             {
13963 #ifdef HAVE_MENU
13964                if (  (settings->uints.quit_on_close_content == QUIT_ON_CLOSE_CONTENT_CLI && global->launched_from_cli)
13965                      || settings->uints.quit_on_close_content == QUIT_ON_CLOSE_CONTENT_ENABLED
13966                   )
13967                   command_event(CMD_EVENT_QUIT, NULL);
13968 #endif
13969                if (!task_push_start_dummy_core(&content_info))
13970                   return false;
13971             }
13972 #ifdef HAVE_DISCORD
13973             if (discord_is_inited)
13974             {
13975                discord_userdata_t userdata;
13976                userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
13977                command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
13978                userdata.status = DISCORD_PRESENCE_MENU;
13979                command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
13980             }
13981 #endif
13982 #ifdef HAVE_DYNAMIC
13983             path_clear(RARCH_PATH_CORE);
13984             retroarch_system_info_free(p_rarch);
13985 #endif
13986             if (is_inited)
13987             {
13988                subsystem_current_count = 0;
13989                content_clear_subsystem();
13990             }
13991          }
13992          break;
13993       case CMD_EVENT_CLOSE_CONTENT:
13994 #ifdef HAVE_MENU
13995          /* Closing content via hotkey requires toggling menu
13996           * and resetting the position later on to prevent
13997           * going to empty Quick Menu */
13998          if (!p_rarch->menu_driver_alive)
13999          {
14000             p_rarch->menu_driver_state.pending_close_content = true;
14001             command_event(CMD_EVENT_MENU_TOGGLE, NULL);
14002          }
14003 #else
14004          command_event(CMD_EVENT_QUIT, NULL);
14005 #endif
14006          break;
14007       case CMD_EVENT_QUIT:
14008          if (!retroarch_main_quit())
14009             return false;
14010          break;
14011       case CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE:
14012 #ifdef HAVE_CHEEVOS
14013          rcheevos_toggle_hardcore_paused();
14014 #endif
14015          break;
14016       case CMD_EVENT_REINIT_FROM_TOGGLE:
14017          p_rarch->rarch_force_fullscreen = false;
14018          /* this fallthrough is on purpose, it should do
14019             a CMD_EVENT_REINIT too */
14020       case CMD_EVENT_REINIT:
14021          command_event_reinit(p_rarch,
14022                data ? *(const int*)data : DRIVERS_CMD_ALL);
14023          break;
14024       case CMD_EVENT_CHEATS_APPLY:
14025 #ifdef HAVE_CHEATS
14026          cheat_manager_apply_cheats();
14027 #endif
14028          break;
14029       case CMD_EVENT_REWIND_DEINIT:
14030 #ifdef HAVE_REWIND
14031          state_manager_event_deinit(&p_rarch->rewind_st);
14032 #endif
14033          break;
14034       case CMD_EVENT_REWIND_INIT:
14035 #ifdef HAVE_REWIND
14036          {
14037             bool rewind_enable        = settings->bools.rewind_enable;
14038             size_t rewind_buf_size    = settings->sizes.rewind_buffer_size;
14039 #ifdef HAVE_CHEEVOS
14040             if (rcheevos_hardcore_active())
14041                return false;
14042 #endif
14043             if (rewind_enable)
14044             {
14045 #ifdef HAVE_NETWORKING
14046                /* Only enable state manager if netplay is not underway
14047                   TODO/FIXME: Add a setting for these tweaks */
14048                if (!netplay_driver_ctl(
14049                         RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
14050 #endif
14051                {
14052                   state_manager_event_init(&p_rarch->rewind_st,
14053                         (unsigned)rewind_buf_size);
14054                }
14055             }
14056          }
14057 #endif
14058          break;
14059       case CMD_EVENT_REWIND_TOGGLE:
14060 #ifdef HAVE_REWIND
14061          {
14062             bool rewind_enable        = settings->bools.rewind_enable;
14063             if (rewind_enable)
14064                command_event(CMD_EVENT_REWIND_INIT, NULL);
14065             else
14066                command_event(CMD_EVENT_REWIND_DEINIT, NULL);
14067          }
14068 #endif
14069          break;
14070       case CMD_EVENT_AUTOSAVE_INIT:
14071 #ifdef HAVE_THREADS
14072          retroarch_autosave_deinit(p_rarch);
14073          {
14074 #ifdef HAVE_NETWORKING
14075             unsigned autosave_interval =
14076                settings->uints.autosave_interval;
14077             /* Only enable state manager if netplay is not underway
14078                TODO/FIXME: Add a setting for these tweaks */
14079             if (      (autosave_interval != 0)
14080                   && !netplay_driver_ctl(
14081                      RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
14082 #endif
14083                runloop_state.autosave = autosave_init();
14084          }
14085 #endif
14086          break;
14087       case CMD_EVENT_AUDIO_STOP:
14088          midi_driver_set_all_sounds_off(p_rarch);
14089          if (!audio_driver_stop(p_rarch))
14090             return false;
14091          break;
14092       case CMD_EVENT_AUDIO_START:
14093          if (!audio_driver_start(p_rarch,
14094                   runloop_state.shutdown_initiated))
14095             return false;
14096          break;
14097       case CMD_EVENT_AUDIO_MUTE_TOGGLE:
14098          {
14099             bool audio_mute_enable             =
14100                *(audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE));
14101             const char *msg                    = !audio_mute_enable ?
14102                msg_hash_to_str(MSG_AUDIO_MUTED):
14103                msg_hash_to_str(MSG_AUDIO_UNMUTED);
14104 
14105             p_rarch->audio_driver_mute_enable  =
14106                !p_rarch->audio_driver_mute_enable;
14107 
14108 #if defined(HAVE_GFX_WIDGETS)
14109             if (p_rarch->widgets_active)
14110                gfx_widget_volume_update_and_show(
14111                      settings->floats.audio_volume,
14112                      p_rarch->audio_driver_mute_enable);
14113             else
14114 #endif
14115                runloop_msg_queue_push(msg, 1, 180, true, NULL,
14116                      MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14117          }
14118          break;
14119       case CMD_EVENT_SEND_DEBUG_INFO:
14120          break;
14121       case CMD_EVENT_FPS_TOGGLE:
14122          settings->bools.video_fps_show = !(settings->bools.video_fps_show);
14123          break;
14124       case CMD_EVENT_OVERLAY_NEXT:
14125          /* Switch to the next available overlay screen. */
14126 #ifdef HAVE_OVERLAY
14127          {
14128             bool *check_rotation           = (bool*)data;
14129             bool inp_overlay_auto_rotate   = settings->bools.input_overlay_auto_rotate;
14130             float input_overlay_opacity    = settings->floats.input_overlay_opacity;
14131             if (!p_rarch->overlay_ptr)
14132                return false;
14133 
14134             p_rarch->overlay_ptr->index    = p_rarch->overlay_ptr->next_index;
14135             p_rarch->overlay_ptr->active   = &p_rarch->overlay_ptr->overlays[
14136                p_rarch->overlay_ptr->index];
14137 
14138             input_overlay_load_active(p_rarch,
14139                   p_rarch->overlay_ptr, input_overlay_opacity);
14140 
14141             p_rarch->overlay_ptr->blocked    = true;
14142             p_rarch->overlay_ptr->next_index = (unsigned)((p_rarch->overlay_ptr->index + 1) % p_rarch->overlay_ptr->size);
14143 
14144             /* Check orientation, if required */
14145             if (inp_overlay_auto_rotate)
14146                if (check_rotation)
14147                   if (*check_rotation)
14148                      input_overlay_auto_rotate_(p_rarch,
14149                            settings->bools.input_overlay_enable,
14150                            p_rarch->overlay_ptr);
14151          }
14152 #endif
14153          break;
14154       case CMD_EVENT_DSP_FILTER_INIT:
14155 #ifdef HAVE_DSP_FILTER
14156          {
14157             const char *path_audio_dsp_plugin = settings->paths.path_audio_dsp_plugin;
14158             audio_driver_dsp_filter_free();
14159             if (string_is_empty(path_audio_dsp_plugin))
14160                break;
14161             if (!audio_driver_dsp_filter_init(path_audio_dsp_plugin))
14162             {
14163                RARCH_ERR("[DSP]: Failed to initialize DSP filter \"%s\".\n",
14164                      path_audio_dsp_plugin);
14165             }
14166          }
14167 #endif
14168          break;
14169       case CMD_EVENT_RECORD_DEINIT:
14170          p_rarch->recording_enable = false;
14171          streaming_set_state(false);
14172          if (!recording_deinit(p_rarch))
14173             return false;
14174          break;
14175       case CMD_EVENT_RECORD_INIT:
14176          p_rarch->recording_enable = true;
14177          if (!recording_init(settings, p_rarch))
14178          {
14179             command_event(CMD_EVENT_RECORD_DEINIT, NULL);
14180             return false;
14181          }
14182          break;
14183       case CMD_EVENT_HISTORY_DEINIT:
14184          if (g_defaults.content_history)
14185          {
14186             playlist_write_file(g_defaults.content_history);
14187             playlist_free(g_defaults.content_history);
14188          }
14189          g_defaults.content_history = NULL;
14190 
14191          if (g_defaults.music_history)
14192          {
14193             playlist_write_file(g_defaults.music_history);
14194             playlist_free(g_defaults.music_history);
14195          }
14196          g_defaults.music_history = NULL;
14197 
14198 #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
14199          if (g_defaults.video_history)
14200          {
14201             playlist_write_file(g_defaults.video_history);
14202             playlist_free(g_defaults.video_history);
14203          }
14204          g_defaults.video_history = NULL;
14205 #endif
14206 
14207 #ifdef HAVE_IMAGEVIEWER
14208          if (g_defaults.image_history)
14209          {
14210             playlist_write_file(g_defaults.image_history);
14211             playlist_free(g_defaults.image_history);
14212          }
14213          g_defaults.image_history = NULL;
14214 #endif
14215          break;
14216       case CMD_EVENT_HISTORY_INIT:
14217          {
14218             playlist_config_t playlist_config;
14219             bool history_list_enable               = settings->bools.history_list_enable;
14220             const char *path_content_history       = settings->paths.path_content_history;
14221             const char *path_content_music_history = settings->paths.path_content_music_history;
14222 #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
14223             const char *path_content_video_history = settings->paths.path_content_video_history;
14224 #endif
14225 #ifdef HAVE_IMAGEVIEWER
14226             const char *path_content_image_history = settings->paths.path_content_image_history;
14227 #endif
14228             playlist_config.capacity               = settings->uints.content_history_size;
14229             playlist_config.old_format             = settings->bools.playlist_use_old_format;
14230             playlist_config.compress               = settings->bools.playlist_compression;
14231             playlist_config.fuzzy_archive_match    = settings->bools.playlist_fuzzy_archive_match;
14232             /* don't use relative paths for content, music, video, and image histories */
14233             playlist_config_set_base_content_directory(&playlist_config, NULL);
14234 
14235             command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
14236 
14237             if (!history_list_enable)
14238                return false;
14239 
14240             /* Note: Sorting is disabled by default for
14241              * all content history playlists */
14242             RARCH_LOG("[Playlist]: %s: [%s].\n",
14243                   msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
14244                   path_content_history);
14245             playlist_config_set_path(&playlist_config, path_content_history);
14246             g_defaults.content_history = playlist_init(&playlist_config);
14247             playlist_set_sort_mode(
14248                   g_defaults.content_history, PLAYLIST_SORT_MODE_OFF);
14249 
14250             RARCH_LOG("[Playlist]: %s: [%s].\n",
14251                   msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
14252                   path_content_music_history);
14253             playlist_config_set_path(&playlist_config, path_content_music_history);
14254             g_defaults.music_history = playlist_init(&playlist_config);
14255             playlist_set_sort_mode(
14256                   g_defaults.music_history, PLAYLIST_SORT_MODE_OFF);
14257 
14258 #if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
14259             RARCH_LOG("[Playlist]: %s: [%s].\n",
14260                   msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
14261                   path_content_video_history);
14262             playlist_config_set_path(&playlist_config, path_content_video_history);
14263             g_defaults.video_history = playlist_init(&playlist_config);
14264             playlist_set_sort_mode(
14265                   g_defaults.video_history, PLAYLIST_SORT_MODE_OFF);
14266 #endif
14267 
14268 #ifdef HAVE_IMAGEVIEWER
14269             RARCH_LOG("[Playlist]: %s: [%s].\n",
14270                   msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
14271                   path_content_image_history);
14272             playlist_config_set_path(&playlist_config, path_content_image_history);
14273             g_defaults.image_history = playlist_init(&playlist_config);
14274             playlist_set_sort_mode(
14275                   g_defaults.image_history, PLAYLIST_SORT_MODE_OFF);
14276 #endif
14277          }
14278          break;
14279       case CMD_EVENT_CORE_INFO_DEINIT:
14280          core_info_deinit_list();
14281          core_info_free_current_core(&p_rarch->core_info_st);
14282          break;
14283       case CMD_EVENT_CORE_INFO_INIT:
14284          {
14285             char ext_name[255];
14286             const char *dir_libretro       = settings->paths.directory_libretro;
14287             const char *path_libretro_info = settings->paths.path_libretro_info;
14288             bool show_hidden_files         = settings->bools.show_hidden_files;
14289             bool core_info_cache_enable    = settings->bools.core_info_cache_enable;
14290 
14291             ext_name[0]                    = '\0';
14292 
14293             command_event(CMD_EVENT_CORE_INFO_DEINIT, NULL);
14294 
14295             if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
14296                return false;
14297 
14298             if (!string_is_empty(dir_libretro))
14299             {
14300                bool cache_supported = false;
14301 
14302                core_info_init_list(path_libretro_info,
14303                      dir_libretro,
14304                      ext_name,
14305                      show_hidden_files,
14306                      core_info_cache_enable,
14307                      &cache_supported);
14308 
14309                /* If core info cache is enabled but cache
14310                 * functionality is unsupported (i.e. because
14311                 * the core info directory is on read-only
14312                 * storage), force-disable the setting to
14313                 * avoid repeated failures */
14314                if (core_info_cache_enable && !cache_supported)
14315                   configuration_set_bool(settings,
14316                         settings->bools.core_info_cache_enable, false);
14317             }
14318          }
14319          break;
14320       case CMD_EVENT_CORE_DEINIT:
14321          {
14322             struct retro_hw_render_callback *hwr = NULL;
14323             rarch_system_info_t *sys_info        = &runloop_state.system;
14324 
14325             /* Save last selected disk index, if required */
14326             if (sys_info)
14327                disk_control_save_image_index(&sys_info->disk_control);
14328 
14329             command_event_runtime_log_deinit(p_rarch,
14330                   settings->bools.content_runtime_log,
14331                   settings->bools.content_runtime_log_aggregate,
14332                   settings->paths.directory_runtime_log,
14333                   settings->paths.directory_playlist);
14334             content_reset_savestate_backups();
14335             hwr = VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
14336 #ifdef HAVE_CHEEVOS
14337             rcheevos_unload();
14338 #endif
14339             command_event_deinit_core(p_rarch, true);
14340 
14341 #ifdef HAVE_RUNAHEAD
14342             /* If 'runahead_available' is false, then
14343              * runahead is enabled by the user but an
14344              * error occurred while the core was running
14345              * (typically a save state issue). In this
14346              * case we have to 'manually' reset the runahead
14347              * runtime variables, otherwise runahead will
14348              * remain disabled until the user restarts
14349              * RetroArch */
14350             if (!p_rarch->runahead_available)
14351                runahead_clear_variables(p_rarch);
14352 #endif
14353 
14354             if (hwr)
14355                memset(hwr, 0, sizeof(*hwr));
14356 
14357             break;
14358          }
14359       case CMD_EVENT_CORE_INIT:
14360          {
14361             enum rarch_core_type *type    = (enum rarch_core_type*)data;
14362             rarch_system_info_t *sys_info = &runloop_state.system;
14363 
14364             content_reset_savestate_backups();
14365 
14366             /* Ensure that disk control interface is reset */
14367             if (sys_info)
14368                disk_control_set_ext_callback(&sys_info->disk_control, NULL);
14369 
14370             if (!type || !command_event_init_core(settings, p_rarch, *type))
14371                return false;
14372          }
14373          break;
14374       case CMD_EVENT_VIDEO_APPLY_STATE_CHANGES:
14375          video_driver_apply_state_changes();
14376          break;
14377       case CMD_EVENT_VIDEO_SET_BLOCKING_STATE:
14378          {
14379             bool adaptive_vsync       = settings->bools.video_adaptive_vsync;
14380             unsigned swap_interval    = settings->uints.video_swap_interval;
14381 
14382             if (p_rarch->current_video->set_nonblock_state)
14383                p_rarch->current_video->set_nonblock_state(
14384                      p_rarch->video_driver_data, false,
14385                      video_driver_test_all_flags(
14386                         GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
14387                      adaptive_vsync, swap_interval);
14388          }
14389          break;
14390       case CMD_EVENT_VIDEO_SET_ASPECT_RATIO:
14391          video_driver_set_aspect_ratio();
14392          break;
14393       case CMD_EVENT_OVERLAY_SET_SCALE_FACTOR:
14394 #ifdef HAVE_OVERLAY
14395          {
14396             overlay_layout_desc_t layout_desc;
14397 
14398             layout_desc.scale_landscape         = settings->floats.input_overlay_scale_landscape;
14399             layout_desc.aspect_adjust_landscape = settings->floats.input_overlay_aspect_adjust_landscape;
14400             layout_desc.x_separation_landscape  = settings->floats.input_overlay_x_separation_landscape;
14401             layout_desc.y_separation_landscape  = settings->floats.input_overlay_y_separation_landscape;
14402             layout_desc.x_offset_landscape      = settings->floats.input_overlay_x_offset_landscape;
14403             layout_desc.y_offset_landscape      = settings->floats.input_overlay_y_offset_landscape;
14404             layout_desc.scale_portrait          = settings->floats.input_overlay_scale_portrait;
14405             layout_desc.aspect_adjust_portrait  = settings->floats.input_overlay_aspect_adjust_portrait;
14406             layout_desc.x_separation_portrait   = settings->floats.input_overlay_x_separation_portrait;
14407             layout_desc.y_separation_portrait   = settings->floats.input_overlay_y_separation_portrait;
14408             layout_desc.x_offset_portrait       = settings->floats.input_overlay_x_offset_portrait;
14409             layout_desc.y_offset_portrait       = settings->floats.input_overlay_y_offset_portrait;
14410             layout_desc.touch_scale             = (float)settings->uints.input_touch_scale;
14411             layout_desc.auto_scale              = settings->bools.input_overlay_auto_scale;
14412 
14413             input_overlay_set_scale_factor(p_rarch, p_rarch->overlay_ptr, &layout_desc);
14414          }
14415 #endif
14416          break;
14417       case CMD_EVENT_OVERLAY_SET_ALPHA_MOD:
14418          /* Sets a modulating factor for alpha channel. Default is 1.0.
14419           * The alpha factor is applied for all overlays. */
14420 #ifdef HAVE_OVERLAY
14421          {
14422             float input_overlay_opacity = settings->floats.input_overlay_opacity;
14423             input_overlay_set_alpha_mod(p_rarch,
14424                   p_rarch->overlay_ptr, input_overlay_opacity);
14425          }
14426 #endif
14427          break;
14428       case CMD_EVENT_AUDIO_REINIT:
14429          driver_uninit(p_rarch, DRIVER_AUDIO_MASK);
14430          drivers_init(p_rarch, settings, DRIVER_AUDIO_MASK, verbosity_is_enabled());
14431          break;
14432       case CMD_EVENT_SHUTDOWN:
14433 #if defined(__linux__) && !defined(ANDROID)
14434          runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_SHUTTING_DOWN), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14435          command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
14436          command_event(CMD_EVENT_QUIT, NULL);
14437          system("shutdown -P now");
14438 #endif
14439          break;
14440       case CMD_EVENT_REBOOT:
14441 #if defined(__linux__) && !defined(ANDROID)
14442          runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_REBOOTING), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14443          command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
14444          command_event(CMD_EVENT_QUIT, NULL);
14445          system("shutdown -r now");
14446 #endif
14447          break;
14448       case CMD_EVENT_RESUME:
14449          retroarch_menu_running_finished(false);
14450          if (p_rarch->main_ui_companion_is_on_foreground)
14451          {
14452 #ifdef HAVE_QT
14453             bool desktop_menu_enable = settings->bools.desktop_menu_enable;
14454             bool ui_companion_toggle = settings->bools.ui_companion_toggle;
14455 #else
14456             bool desktop_menu_enable = false;
14457             bool ui_companion_toggle = false;
14458 #endif
14459             ui_companion_driver_toggle(p_rarch, desktop_menu_enable, ui_companion_toggle, false);
14460          }
14461          break;
14462       case CMD_EVENT_ADD_TO_FAVORITES:
14463          {
14464             struct string_list *str_list = (struct string_list*)data;
14465 
14466             /* Check whether favourties playlist is at capacity */
14467             if (playlist_size(g_defaults.content_favorites) >=
14468                   playlist_capacity(g_defaults.content_favorites))
14469             {
14470                runloop_msg_queue_push(
14471                      msg_hash_to_str(MSG_ADD_TO_FAVORITES_FAILED), 1, 180, true, NULL,
14472                      MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
14473                return false;
14474             }
14475 
14476             if (str_list)
14477             {
14478                if (str_list->size >= 6)
14479                {
14480                   struct playlist_entry entry     = {0};
14481                   bool playlist_sort_alphabetical = settings->bools.playlist_sort_alphabetical;
14482 
14483                   entry.path      = str_list->elems[0].data; /* content_path */
14484                   entry.label     = str_list->elems[1].data; /* content_label */
14485                   entry.core_path = str_list->elems[2].data; /* core_path */
14486                   entry.core_name = str_list->elems[3].data; /* core_name */
14487                   entry.crc32     = str_list->elems[4].data; /* crc32 */
14488                   entry.db_name   = str_list->elems[5].data; /* db_name */
14489 
14490                   /* Write playlist entry */
14491                   if (playlist_push(g_defaults.content_favorites, &entry))
14492                   {
14493                      enum playlist_sort_mode current_sort_mode =
14494                         playlist_get_sort_mode(g_defaults.content_favorites);
14495 
14496                      /* New addition - need to resort if option is enabled */
14497                      if ((playlist_sort_alphabetical && (current_sort_mode == PLAYLIST_SORT_MODE_DEFAULT)) ||
14498                            (current_sort_mode == PLAYLIST_SORT_MODE_ALPHABETICAL))
14499                         playlist_qsort(g_defaults.content_favorites);
14500 
14501                      playlist_write_file(g_defaults.content_favorites);
14502                      runloop_msg_queue_push(msg_hash_to_str(MSG_ADDED_TO_FAVORITES), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14503                   }
14504                }
14505             }
14506 
14507             break;
14508          }
14509       case CMD_EVENT_RESET_CORE_ASSOCIATION:
14510          {
14511             const char *core_name          = "DETECT";
14512             const char *core_path          = "DETECT";
14513             size_t *playlist_index         = (size_t*)data;
14514             struct playlist_entry entry    = {0};
14515 
14516             /* the update function reads our entry as const,
14517              * so these casts are safe */
14518             entry.core_path                = (char*)core_path;
14519             entry.core_name                = (char*)core_name;
14520 
14521             command_playlist_update_write(
14522                   NULL, *playlist_index, &entry);
14523 
14524             runloop_msg_queue_push(msg_hash_to_str(MSG_RESET_CORE_ASSOCIATION), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14525             break;
14526 
14527          }
14528       case CMD_EVENT_RESTART_RETROARCH:
14529          if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART))
14530             return false;
14531 #ifndef HAVE_DYNAMIC
14532          command_event(CMD_EVENT_QUIT, NULL);
14533 #endif
14534          break;
14535       case CMD_EVENT_MENU_RESET_TO_DEFAULT_CONFIG:
14536          config_set_defaults(&p_rarch->g_extern);
14537          break;
14538       case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG:
14539 #if !defined(HAVE_DYNAMIC)
14540          config_save_file_salamander();
14541 #endif
14542 #ifdef HAVE_CONFIGFILE
14543          command_event_save_current_config(p_rarch, OVERRIDE_NONE);
14544 #endif
14545          break;
14546       case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_CORE:
14547 #ifdef HAVE_CONFIGFILE
14548          command_event_save_current_config(p_rarch, OVERRIDE_CORE);
14549 #endif
14550          break;
14551       case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR:
14552 #ifdef HAVE_CONFIGFILE
14553          command_event_save_current_config(p_rarch, OVERRIDE_CONTENT_DIR);
14554 #endif
14555          break;
14556       case CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_GAME:
14557 #ifdef HAVE_CONFIGFILE
14558          command_event_save_current_config(p_rarch, OVERRIDE_GAME);
14559 #endif
14560          break;
14561       case CMD_EVENT_MENU_SAVE_CONFIG:
14562 #ifdef HAVE_CONFIGFILE
14563          if (!command_event_save_core_config(p_rarch,
14564                   settings->paths.directory_menu_config,
14565                   path_get(RARCH_PATH_CONFIG)))
14566             return false;
14567 #endif
14568          break;
14569       case CMD_EVENT_SHADER_PRESET_LOADED:
14570          ui_companion_event_command(cmd);
14571          break;
14572       case CMD_EVENT_SHADERS_APPLY_CHANGES:
14573 #ifdef HAVE_MENU
14574 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
14575          menu_shader_manager_apply_changes(menu_shader_get(),
14576                settings->paths.directory_video_shader,
14577                settings->paths.directory_menu_config
14578                );
14579 #endif
14580 #endif
14581          ui_companion_event_command(cmd);
14582          break;
14583       case CMD_EVENT_PAUSE_TOGGLE:
14584          {
14585 #ifdef HAVE_ACCESSIBILITY
14586             bool accessibility_enable                    = settings->bools.accessibility_enable;
14587             unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
14588 #endif
14589             boolean                                      = runloop_state.paused;
14590             boolean                                      = !boolean;
14591 
14592 #ifdef HAVE_ACCESSIBILITY
14593             if (is_accessibility_enabled(
14594                   accessibility_enable,
14595                   p_rarch->accessibility_enabled))
14596             {
14597                if (boolean)
14598                   accessibility_speak_priority(p_rarch,
14599                      accessibility_enable,
14600                      accessibility_narrator_speech_speed,
14601                      (char*)msg_hash_to_str(MSG_PAUSED), 10);
14602                else
14603                   accessibility_speak_priority(p_rarch,
14604                      accessibility_enable,
14605                      accessibility_narrator_speech_speed,
14606                      (char*)msg_hash_to_str(MSG_UNPAUSED), 10);
14607             }
14608 #endif
14609 
14610             runloop_state.paused = boolean;
14611             retroarch_pause_checks(p_rarch);
14612          }
14613          break;
14614       case CMD_EVENT_UNPAUSE:
14615          boolean                 = false;
14616          runloop_state.paused = boolean;
14617          retroarch_pause_checks(p_rarch);
14618          break;
14619       case CMD_EVENT_PAUSE:
14620          boolean                 = true;
14621          runloop_state.paused = boolean;
14622          retroarch_pause_checks(p_rarch);
14623          break;
14624       case CMD_EVENT_MENU_PAUSE_LIBRETRO:
14625 #ifdef HAVE_MENU
14626          if (p_rarch->menu_driver_alive)
14627          {
14628             bool menu_pause_libretro  = settings->bools.menu_pause_libretro;
14629             if (menu_pause_libretro)
14630                command_event(CMD_EVENT_AUDIO_STOP, NULL);
14631             else
14632                command_event(CMD_EVENT_AUDIO_START, NULL);
14633          }
14634          else
14635          {
14636             bool menu_pause_libretro  = settings->bools.menu_pause_libretro;
14637             if (menu_pause_libretro)
14638                command_event(CMD_EVENT_AUDIO_START, NULL);
14639          }
14640 #endif
14641          break;
14642 #ifdef HAVE_NETWORKING
14643       case CMD_EVENT_NETPLAY_GAME_WATCH:
14644          netplay_driver_ctl(RARCH_NETPLAY_CTL_GAME_WATCH, NULL);
14645          break;
14646       case CMD_EVENT_NETPLAY_DEINIT:
14647          deinit_netplay(p_rarch);
14648          break;
14649       case CMD_EVENT_NETWORK_INIT:
14650          network_init();
14651          break;
14652          /* init netplay manually */
14653       case CMD_EVENT_NETPLAY_INIT:
14654          {
14655             char       *hostname       = (char*)data;
14656             const char *netplay_server = settings->paths.netplay_server;
14657             unsigned netplay_port      = settings->uints.netplay_port;
14658 
14659             command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14660 
14661             if (!init_netplay(p_rarch,
14662                      p_rarch->configuration_settings,
14663                      NULL,
14664                      hostname
14665                      ? hostname
14666                      : netplay_server, netplay_port))
14667             {
14668                command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14669                return false;
14670             }
14671 
14672             /* Disable rewind & SRAM autosave if it was enabled
14673              * TODO/FIXME: Add a setting for these tweaks */
14674 #ifdef HAVE_REWIND
14675             state_manager_event_deinit(&p_rarch->rewind_st);
14676 #endif
14677 #ifdef HAVE_THREADS
14678             autosave_deinit();
14679 #endif
14680          }
14681          break;
14682          /* Initialize netplay via lobby when content is loaded */
14683       case CMD_EVENT_NETPLAY_INIT_DIRECT:
14684          {
14685             /* buf is expected to be address|port */
14686             static struct string_list *hostname = NULL;
14687             char *buf                           = (char *)data;
14688             unsigned netplay_port               = settings->uints.netplay_port;
14689 
14690             hostname                            = string_split(buf, "|");
14691 
14692             command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14693 
14694             RARCH_LOG("[Netplay]: Connecting to %s:%d (direct)\n",
14695                   hostname->elems[0].data, !string_is_empty(hostname->elems[1].data)
14696                   ? atoi(hostname->elems[1].data)
14697                   : netplay_port);
14698 
14699             if (!init_netplay(
14700                      p_rarch,
14701                      p_rarch->configuration_settings,
14702                      NULL,
14703                      hostname->elems[0].data,
14704                      !string_is_empty(hostname->elems[1].data)
14705                      ? atoi(hostname->elems[1].data)
14706                      : netplay_port))
14707             {
14708                command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14709                string_list_free(hostname);
14710                return false;
14711             }
14712 
14713             string_list_free(hostname);
14714 
14715             /* Disable rewind if it was enabled
14716                TODO/FIXME: Add a setting for these tweaks */
14717 #ifdef HAVE_REWIND
14718             state_manager_event_deinit(&p_rarch->rewind_st);
14719 #endif
14720 #ifdef HAVE_THREADS
14721             autosave_deinit();
14722 #endif
14723          }
14724          break;
14725          /* init netplay via lobby when content is not loaded */
14726       case CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED:
14727          {
14728             static struct string_list *hostname = NULL;
14729             /* buf is expected to be address|port */
14730             char *buf                           = (char *)data;
14731             unsigned netplay_port               = settings->uints.netplay_port;
14732 
14733             hostname = string_split(buf, "|");
14734 
14735             command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14736 
14737             RARCH_LOG("[Netplay]: Connecting to %s:%d (deferred)\n",
14738                   hostname->elems[0].data, !string_is_empty(hostname->elems[1].data)
14739                   ? atoi(hostname->elems[1].data)
14740                   : netplay_port);
14741 
14742             if (!init_netplay_deferred(p_rarch,
14743                      hostname->elems[0].data,
14744                      !string_is_empty(hostname->elems[1].data)
14745                      ? atoi(hostname->elems[1].data)
14746                      : netplay_port))
14747             {
14748                command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14749                string_list_free(hostname);
14750                return false;
14751             }
14752 
14753             string_list_free(hostname);
14754 
14755             /* Disable rewind if it was enabled
14756              * TODO/FIXME: Add a setting for these tweaks */
14757 #ifdef HAVE_REWIND
14758             state_manager_event_deinit(&p_rarch->rewind_st);
14759 #endif
14760 #ifdef HAVE_THREADS
14761             autosave_deinit();
14762 #endif
14763          }
14764          break;
14765       case CMD_EVENT_NETPLAY_ENABLE_HOST:
14766          {
14767 #ifdef HAVE_MENU
14768             bool contentless  = false;
14769             bool is_inited    = false;
14770 
14771             content_get_status(&contentless, &is_inited);
14772 
14773             if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
14774                command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
14775             netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_SERVER, NULL);
14776 
14777             /* If we haven't yet started, this will load on its own */
14778             if (!is_inited)
14779             {
14780                runloop_msg_queue_push(
14781                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED),
14782                      1, 480, true,
14783                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14784                return false;
14785             }
14786 
14787             /* Enable Netplay itself */
14788             if (!command_event(CMD_EVENT_NETPLAY_INIT, NULL))
14789                return false;
14790 #endif
14791             break;
14792          }
14793       case CMD_EVENT_NETPLAY_DISCONNECT:
14794          {
14795             netplay_driver_ctl(RARCH_NETPLAY_CTL_DISCONNECT, NULL);
14796             netplay_driver_ctl(RARCH_NETPLAY_CTL_DISABLE, NULL);
14797 
14798             {
14799                bool rewind_enable                  = settings->bools.rewind_enable;
14800                unsigned autosave_interval          = settings->uints.autosave_interval;
14801 
14802 #ifdef HAVE_REWIND
14803                /* Re-enable rewind if it was enabled
14804                 * TODO/FIXME: Add a setting for these tweaks */
14805                if (rewind_enable)
14806                   command_event(CMD_EVENT_REWIND_INIT, NULL);
14807 #endif
14808                if (autosave_interval != 0)
14809                   command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
14810             }
14811 
14812             break;
14813          }
14814       case CMD_EVENT_NETPLAY_HOST_TOGGLE:
14815          if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
14816                netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL))
14817             command_event(CMD_EVENT_NETPLAY_DISCONNECT, NULL);
14818          else if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
14819                !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL) &&
14820                netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
14821             command_event(CMD_EVENT_NETPLAY_DISCONNECT, NULL);
14822          else
14823             command_event(CMD_EVENT_NETPLAY_ENABLE_HOST, NULL);
14824 
14825          break;
14826 #else
14827       case CMD_EVENT_NETPLAY_DEINIT:
14828       case CMD_EVENT_NETWORK_INIT:
14829       case CMD_EVENT_NETPLAY_INIT:
14830       case CMD_EVENT_NETPLAY_INIT_DIRECT:
14831       case CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED:
14832       case CMD_EVENT_NETPLAY_HOST_TOGGLE:
14833       case CMD_EVENT_NETPLAY_DISCONNECT:
14834       case CMD_EVENT_NETPLAY_ENABLE_HOST:
14835       case CMD_EVENT_NETPLAY_GAME_WATCH:
14836          return false;
14837 #endif
14838       case CMD_EVENT_FULLSCREEN_TOGGLE:
14839          {
14840             bool *userdata            = (bool*)data;
14841             bool video_fullscreen     = settings->bools.video_fullscreen;
14842             bool ra_is_forced_fs      = p_rarch->rarch_force_fullscreen;
14843             bool new_fullscreen_state = !video_fullscreen && !ra_is_forced_fs;
14844 
14845             if (!video_driver_has_windowed())
14846                return false;
14847 
14848             p_rarch->rarch_is_switching_display_mode = true;
14849 
14850             /* we toggled manually, write the new value to settings */
14851             configuration_set_bool(settings, settings->bools.video_fullscreen,
14852                   new_fullscreen_state);
14853             /* Need to grab this setting's value again */
14854             video_fullscreen = new_fullscreen_state;
14855 
14856             /* we toggled manually, the CLI arg is irrelevant now */
14857             if (ra_is_forced_fs)
14858                p_rarch->rarch_force_fullscreen = false;
14859 
14860             /* If we go fullscreen we drop all drivers and
14861              * reinitialize to be safe. */
14862             command_event(CMD_EVENT_REINIT, NULL);
14863             if (video_fullscreen)
14864             {
14865                video_driver_hide_mouse();
14866                if (!settings->bools.video_windowed_fullscreen)
14867                   input_driver_grab_mouse(p_rarch);
14868             }
14869             else
14870             {
14871                video_driver_show_mouse();
14872                if (!settings->bools.video_windowed_fullscreen)
14873                   input_driver_ungrab_mouse(p_rarch);
14874             }
14875 
14876             p_rarch->rarch_is_switching_display_mode = false;
14877 
14878             if (userdata && *userdata == true)
14879                video_driver_cached_frame();
14880          }
14881          break;
14882       case CMD_EVENT_DISK_APPEND_IMAGE:
14883          {
14884             const char *path              = (const char*)data;
14885             rarch_system_info_t *sys_info = &runloop_state.system;
14886 
14887             if (string_is_empty(path) || !sys_info)
14888                return false;
14889 
14890             if (disk_control_enabled(&sys_info->disk_control))
14891             {
14892 #if defined(HAVE_MENU)
14893                bool refresh               = false;
14894                /* Get initial disk eject state */
14895                bool initial_disk_ejected  = disk_control_get_eject_state(&sys_info->disk_control);
14896 #endif
14897                rarch_system_info_t *
14898                   sys_info                = &runloop_state.system;
14899                /* Append disk image */
14900                bool success               = command_event_disk_control_append_image(p_rarch, sys_info, path);
14901 
14902 #if defined(HAVE_MENU)
14903                /* Appending a disk image may or may not affect
14904                 * the disk tray eject status. If status has changed,
14905                 * must refresh the disk options menu */
14906                if (initial_disk_ejected != disk_control_get_eject_state(&sys_info->disk_control))
14907                {
14908                   menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
14909                   menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
14910                }
14911 #endif
14912                return success;
14913             }
14914             else
14915                runloop_msg_queue_push(
14916                      msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
14917                      1, 120, true,
14918                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14919          }
14920          break;
14921       case CMD_EVENT_DISK_EJECT_TOGGLE:
14922          {
14923             rarch_system_info_t *sys_info = &runloop_state.system;
14924 
14925             if (!sys_info)
14926                return false;
14927 
14928             if (disk_control_enabled(&sys_info->disk_control))
14929             {
14930                bool *show_msg = (bool*)data;
14931                bool eject     = !disk_control_get_eject_state(&sys_info->disk_control);
14932                bool verbose   = true;
14933                bool refresh   = false;
14934 
14935                if (show_msg)
14936                   verbose     = *show_msg;
14937 
14938                disk_control_set_eject_state(
14939                      &sys_info->disk_control, eject, verbose);
14940 
14941 #if defined(HAVE_MENU)
14942                /* It is necessary to refresh the disk options
14943                 * menu when toggling the tray state */
14944                menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
14945                menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
14946 #endif
14947             }
14948             else
14949                runloop_msg_queue_push(
14950                      msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
14951                      1, 120, true,
14952                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14953          }
14954          break;
14955       case CMD_EVENT_DISK_NEXT:
14956          {
14957             rarch_system_info_t *sys_info = &runloop_state.system;
14958 
14959             if (!sys_info)
14960                return false;
14961 
14962             if (disk_control_enabled(&sys_info->disk_control))
14963             {
14964                bool *show_msg = (bool*)data;
14965                bool verbose   = true;
14966 
14967                if (show_msg)
14968                   verbose     = *show_msg;
14969 
14970                disk_control_set_index_next(&sys_info->disk_control, verbose);
14971             }
14972             else
14973                runloop_msg_queue_push(
14974                      msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
14975                      1, 120, true,
14976                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
14977          }
14978          break;
14979       case CMD_EVENT_DISK_PREV:
14980          {
14981             rarch_system_info_t *sys_info = &runloop_state.system;
14982 
14983             if (!sys_info)
14984                return false;
14985 
14986             if (disk_control_enabled(&sys_info->disk_control))
14987             {
14988                bool *show_msg = (bool*)data;
14989                bool verbose   = true;
14990 
14991                if (show_msg)
14992                   verbose     = *show_msg;
14993 
14994                disk_control_set_index_prev(&sys_info->disk_control, verbose);
14995             }
14996             else
14997                runloop_msg_queue_push(
14998                      msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
14999                      1, 120, true,
15000                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
15001          }
15002          break;
15003       case CMD_EVENT_DISK_INDEX:
15004          {
15005             rarch_system_info_t *sys_info = &runloop_state.system;
15006             unsigned *index               = (unsigned*)data;
15007 
15008             if (!sys_info || !index)
15009                return false;
15010 
15011             /* Note: Menu itself provides visual feedback - no
15012              * need to print info message to screen */
15013             if (disk_control_enabled(&sys_info->disk_control))
15014                disk_control_set_index(&sys_info->disk_control, *index, false);
15015             else
15016                runloop_msg_queue_push(
15017                      msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
15018                      1, 120, true,
15019                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
15020          }
15021          break;
15022       case CMD_EVENT_RUMBLE_STOP:
15023          {
15024             unsigned i;
15025             for (i = 0; i < MAX_USERS; i++)
15026             {
15027                input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0);
15028                input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0);
15029             }
15030          }
15031          break;
15032       case CMD_EVENT_GRAB_MOUSE_TOGGLE:
15033          {
15034             bool ret              = false;
15035             bool grab_mouse_state = !p_rarch->input_driver_grab_mouse_state;
15036 
15037             if (grab_mouse_state)
15038                ret = input_driver_grab_mouse(p_rarch);
15039             else
15040                ret = input_driver_ungrab_mouse(p_rarch);
15041 
15042             if (!ret)
15043                return false;
15044 
15045             RARCH_LOG("[Input]: %s => %s\n",
15046                   msg_hash_to_str(MSG_GRAB_MOUSE_STATE),
15047                   grab_mouse_state ? "ON" : "OFF");
15048 
15049             if (grab_mouse_state)
15050                video_driver_hide_mouse();
15051             else
15052                video_driver_show_mouse();
15053          }
15054          break;
15055       case CMD_EVENT_UI_COMPANION_TOGGLE:
15056          {
15057 #ifdef HAVE_QT
15058             bool desktop_menu_enable = settings->bools.desktop_menu_enable;
15059             bool ui_companion_toggle = settings->bools.ui_companion_toggle;
15060 #else
15061             bool desktop_menu_enable = false;
15062             bool ui_companion_toggle = false;
15063 #endif
15064             ui_companion_driver_toggle(p_rarch, desktop_menu_enable, ui_companion_toggle, true);
15065          }
15066          break;
15067       case CMD_EVENT_GAME_FOCUS_TOGGLE:
15068          {
15069             bool video_fullscreen                         =
15070                settings->bools.video_fullscreen || p_rarch->rarch_force_fullscreen;
15071             enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_TOGGLE;
15072             bool current_enable_state                     = p_rarch->game_focus_state.enabled;
15073             bool apply_update                             = false;
15074             bool show_message                             = false;
15075 
15076             if (data)
15077                game_focus_cmd = *((enum input_game_focus_cmd_type*)data);
15078 
15079             switch (game_focus_cmd)
15080             {
15081                case GAME_FOCUS_CMD_OFF:
15082                   /* Force game focus off */
15083                   p_rarch->game_focus_state.enabled = false;
15084                   if (p_rarch->game_focus_state.enabled != current_enable_state)
15085                   {
15086                      apply_update = true;
15087                      show_message = true;
15088                   }
15089                   break;
15090                case GAME_FOCUS_CMD_ON:
15091                   /* Force game focus on */
15092                   p_rarch->game_focus_state.enabled = true;
15093                   if (p_rarch->game_focus_state.enabled != current_enable_state)
15094                   {
15095                      apply_update = true;
15096                      show_message = true;
15097                   }
15098                   break;
15099                case GAME_FOCUS_CMD_TOGGLE:
15100                   /* Invert current game focus state */
15101                   p_rarch->game_focus_state.enabled = !p_rarch->game_focus_state.enabled;
15102 #ifdef HAVE_MENU
15103                   /* If menu is currently active, disable
15104                    * 'toggle on' functionality */
15105                   if (p_rarch->menu_driver_alive)
15106                      p_rarch->game_focus_state.enabled = false;
15107 #endif
15108                   if (p_rarch->game_focus_state.enabled != current_enable_state)
15109                   {
15110                      apply_update = true;
15111                      show_message = true;
15112                   }
15113                   break;
15114                case GAME_FOCUS_CMD_REAPPLY:
15115                   /* Reapply current game focus state */
15116                   apply_update = true;
15117                   show_message = false;
15118                   break;
15119                default:
15120                   break;
15121             }
15122 
15123             if (apply_update)
15124             {
15125                if (p_rarch->game_focus_state.enabled)
15126                {
15127                   input_driver_grab_mouse(p_rarch);
15128                   video_driver_hide_mouse();
15129                }
15130                else if (!video_fullscreen)
15131                {
15132                   input_driver_ungrab_mouse(p_rarch);
15133                   video_driver_show_mouse();
15134                }
15135 
15136                p_rarch->input_driver_block_hotkey =
15137                   p_rarch->game_focus_state.enabled;
15138                p_rarch->keyboard_mapping_blocked  =
15139                   p_rarch->game_focus_state.enabled;
15140 
15141                if (show_message)
15142                   runloop_msg_queue_push(
15143                         p_rarch->game_focus_state.enabled ?
15144                         msg_hash_to_str(MSG_GAME_FOCUS_ON) :
15145                         msg_hash_to_str(MSG_GAME_FOCUS_OFF),
15146                         1, 60, true,
15147                         NULL, MESSAGE_QUEUE_ICON_DEFAULT,
15148                         MESSAGE_QUEUE_CATEGORY_INFO);
15149 
15150                RARCH_LOG("[Input]: %s => %s\n",
15151                      "Game Focus",
15152                      p_rarch->game_focus_state.enabled ? "ON" : "OFF");
15153             }
15154          }
15155          break;
15156       case CMD_EVENT_VOLUME_UP:
15157          command_event_set_volume(settings, 0.5f,
15158 #if defined(HAVE_GFX_WIDGETS)
15159                p_rarch->widgets_active,
15160 #else
15161                false,
15162 #endif
15163                p_rarch->audio_driver_mute_enable);
15164          break;
15165       case CMD_EVENT_VOLUME_DOWN:
15166          command_event_set_volume(settings, -0.5f,
15167 #if defined(HAVE_GFX_WIDGETS)
15168                p_rarch->widgets_active,
15169 #else
15170                false,
15171 #endif
15172                p_rarch->audio_driver_mute_enable
15173                );
15174          break;
15175       case CMD_EVENT_MIXER_VOLUME_UP:
15176          command_event_set_mixer_volume(settings, 0.5f);
15177          break;
15178       case CMD_EVENT_MIXER_VOLUME_DOWN:
15179          command_event_set_mixer_volume(settings, -0.5f);
15180          break;
15181       case CMD_EVENT_SET_FRAME_LIMIT:
15182          retroarch_set_frame_limit(p_rarch,
15183                retroarch_get_runloop_fastforward_ratio(
15184                      settings, &runloop_state));
15185          break;
15186       case CMD_EVENT_DISCORD_INIT:
15187 #ifdef HAVE_DISCORD
15188          {
15189             bool discord_enable        = settings ? settings->bools.discord_enable : false;
15190             const char *discord_app_id = settings ? settings->arrays.discord_app_id : NULL;
15191             discord_state_t *discord_st = &p_rarch->discord_st;
15192 
15193             if (!settings)
15194                return false;
15195             if (!discord_enable)
15196                return false;
15197             if (discord_st->ready)
15198                return true;
15199             discord_init(discord_st,
15200                   discord_app_id,
15201                   p_rarch->launch_arguments);
15202          }
15203 #endif
15204          break;
15205       case CMD_EVENT_DISCORD_UPDATE:
15206          {
15207 #ifdef HAVE_DISCORD
15208             discord_state_t *discord_st  = &p_rarch->discord_st;
15209             if (!data || !discord_st->ready)
15210                return false;
15211 
15212             discord_userdata_t *userdata = (discord_userdata_t*)data;
15213 
15214             if (discord_st->ready)
15215                discord_update(userdata->status);
15216 #endif
15217          }
15218          break;
15219 
15220       case CMD_EVENT_AI_SERVICE_CALL:
15221          {
15222 #ifdef HAVE_TRANSLATE
15223             bool accessibility_enable = settings->bools.accessibility_enable;
15224             unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
15225             unsigned ai_service_mode  = settings->uints.ai_service_mode;
15226             if (ai_service_mode == 1 && is_ai_service_speech_running())
15227             {
15228 #ifdef HAVE_AUDIOMIXER
15229                audio_driver_mixer_stop_stream(10);
15230                audio_driver_mixer_remove_stream(10);
15231 #endif
15232 #ifdef HAVE_ACCESSIBILITY
15233                if (is_accessibility_enabled(
15234                         accessibility_enable,
15235                         p_rarch->accessibility_enabled))
15236                   accessibility_speak_priority(p_rarch,
15237                         accessibility_enable,
15238                         accessibility_narrator_speech_speed,
15239                         "stopped.", 10);
15240 #endif
15241             }
15242 #ifdef HAVE_ACCESSIBILITY
15243             else if (is_accessibility_enabled(
15244                      accessibility_enable,
15245                      p_rarch->accessibility_enabled) &&
15246                   ai_service_mode == 2 &&
15247                   is_narrator_running(p_rarch, accessibility_enable))
15248                accessibility_speak_priority(p_rarch,
15249                      accessibility_enable,
15250                      accessibility_narrator_speech_speed,
15251                      "stopped.", 10);
15252 #endif
15253             else
15254             {
15255                bool paused = runloop_state.paused;
15256                if (data)
15257                   paused = *((bool*)data);
15258 
15259                if (      p_rarch->ai_service_auto == 0
15260                      && !settings->bools.ai_service_pause)
15261                   p_rarch->ai_service_auto = 1;
15262 
15263                run_translation_service(p_rarch->configuration_settings,
15264                      p_rarch, paused);
15265             }
15266 #endif
15267             break;
15268          }
15269       case CMD_EVENT_CONTROLLER_INIT:
15270          {
15271             rarch_system_info_t *info = &runloop_state.system;
15272             if (info)
15273                command_event_init_controllers(info, settings,
15274                      p_rarch->input_driver_max_users);
15275          }
15276          break;
15277       case CMD_EVENT_NONE:
15278          return false;
15279    }
15280 
15281    return true;
15282 }
15283 
15284 /* FRONTEND */
15285 
retroarch_override_setting_set(enum rarch_override_setting enum_idx,void * data)15286 void retroarch_override_setting_set(
15287       enum rarch_override_setting enum_idx, void *data)
15288 {
15289    struct rarch_state            *p_rarch = &rarch_st;
15290 
15291    switch (enum_idx)
15292    {
15293       case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE:
15294          {
15295             unsigned *val = (unsigned*)data;
15296             if (val)
15297             {
15298                unsigned bit = *val;
15299                BIT256_SET(p_rarch->has_set_libretro_device, bit);
15300             }
15301          }
15302          break;
15303       case RARCH_OVERRIDE_SETTING_VERBOSITY:
15304          p_rarch->has_set_verbosity = true;
15305          break;
15306       case RARCH_OVERRIDE_SETTING_LIBRETRO:
15307          p_rarch->has_set_libretro = true;
15308          break;
15309       case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY:
15310          p_rarch->has_set_libretro_directory = true;
15311          break;
15312       case RARCH_OVERRIDE_SETTING_SAVE_PATH:
15313          p_rarch->has_set_save_path = true;
15314          break;
15315       case RARCH_OVERRIDE_SETTING_STATE_PATH:
15316          p_rarch->has_set_state_path = true;
15317          break;
15318 #ifdef HAVE_NETWORKING
15319       case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
15320          p_rarch->has_set_netplay_mode = true;
15321          break;
15322       case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
15323          p_rarch->has_set_netplay_ip_address = true;
15324          break;
15325       case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
15326          p_rarch->has_set_netplay_ip_port = true;
15327          break;
15328       case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
15329          p_rarch->has_set_netplay_stateless_mode = true;
15330          break;
15331       case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
15332          p_rarch->has_set_netplay_check_frames = true;
15333          break;
15334 #endif
15335       case RARCH_OVERRIDE_SETTING_UPS_PREF:
15336 #ifdef HAVE_PATCH
15337          p_rarch->has_set_ups_pref = true;
15338 #endif
15339          break;
15340       case RARCH_OVERRIDE_SETTING_BPS_PREF:
15341 #ifdef HAVE_PATCH
15342          p_rarch->has_set_bps_pref = true;
15343 #endif
15344          break;
15345       case RARCH_OVERRIDE_SETTING_IPS_PREF:
15346 #ifdef HAVE_PATCH
15347          p_rarch->has_set_ips_pref = true;
15348 #endif
15349          break;
15350       case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
15351          p_rarch->has_set_log_to_file = true;
15352          break;
15353       case RARCH_OVERRIDE_SETTING_NONE:
15354       default:
15355          break;
15356    }
15357 }
15358 
retroarch_override_setting_unset(enum rarch_override_setting enum_idx,void * data)15359 void retroarch_override_setting_unset(
15360       enum rarch_override_setting enum_idx, void *data)
15361 {
15362    struct rarch_state            *p_rarch = &rarch_st;
15363 
15364    switch (enum_idx)
15365    {
15366       case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE:
15367          {
15368             unsigned *val = (unsigned*)data;
15369             if (val)
15370             {
15371                unsigned bit = *val;
15372                BIT256_CLEAR(p_rarch->has_set_libretro_device, bit);
15373             }
15374          }
15375          break;
15376       case RARCH_OVERRIDE_SETTING_VERBOSITY:
15377          p_rarch->has_set_verbosity = false;
15378          break;
15379       case RARCH_OVERRIDE_SETTING_LIBRETRO:
15380          p_rarch->has_set_libretro = false;
15381          break;
15382       case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY:
15383          p_rarch->has_set_libretro_directory = false;
15384          break;
15385       case RARCH_OVERRIDE_SETTING_SAVE_PATH:
15386          p_rarch->has_set_save_path = false;
15387          break;
15388       case RARCH_OVERRIDE_SETTING_STATE_PATH:
15389          p_rarch->has_set_state_path = false;
15390          break;
15391 #ifdef HAVE_NETWORKING
15392       case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
15393          p_rarch->has_set_netplay_mode = false;
15394          break;
15395       case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
15396          p_rarch->has_set_netplay_ip_address = false;
15397          break;
15398       case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
15399          p_rarch->has_set_netplay_ip_port = false;
15400          break;
15401       case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
15402          p_rarch->has_set_netplay_stateless_mode = false;
15403          break;
15404       case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
15405          p_rarch->has_set_netplay_check_frames = false;
15406          break;
15407 #endif
15408       case RARCH_OVERRIDE_SETTING_UPS_PREF:
15409 #ifdef HAVE_PATCH
15410          p_rarch->has_set_ups_pref = false;
15411 #endif
15412          break;
15413       case RARCH_OVERRIDE_SETTING_BPS_PREF:
15414 #ifdef HAVE_PATCH
15415          p_rarch->has_set_bps_pref = false;
15416 #endif
15417          break;
15418       case RARCH_OVERRIDE_SETTING_IPS_PREF:
15419 #ifdef HAVE_PATCH
15420          p_rarch->has_set_ips_pref = false;
15421 #endif
15422          break;
15423       case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
15424          p_rarch->has_set_log_to_file = false;
15425          break;
15426       case RARCH_OVERRIDE_SETTING_NONE:
15427       default:
15428          break;
15429    }
15430 }
15431 
retroarch_override_setting_free_state(void)15432 static void retroarch_override_setting_free_state(void)
15433 {
15434    unsigned i;
15435    for (i = 0; i < RARCH_OVERRIDE_SETTING_LAST; i++)
15436    {
15437       if (i == RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE)
15438       {
15439          unsigned j;
15440          for (j = 0; j < MAX_USERS; j++)
15441             retroarch_override_setting_unset(
15442                   (enum rarch_override_setting)(i), &j);
15443       }
15444       else
15445          retroarch_override_setting_unset(
15446                (enum rarch_override_setting)(i), NULL);
15447    }
15448 }
15449 
global_free(struct rarch_state * p_rarch)15450 static void global_free(struct rarch_state *p_rarch)
15451 {
15452    global_t            *global                     = NULL;
15453 
15454    content_deinit();
15455 
15456    path_deinit_subsystem(p_rarch);
15457    command_event(CMD_EVENT_RECORD_DEINIT, NULL);
15458 
15459    retro_main_log_file_deinit();
15460 
15461    p_rarch->rarch_is_sram_load_disabled            = false;
15462    p_rarch->rarch_is_sram_save_disabled            = false;
15463    p_rarch->rarch_use_sram                         = false;
15464 #ifdef HAVE_PATCH
15465    p_rarch->rarch_bps_pref                         = false;
15466    p_rarch->rarch_ips_pref                         = false;
15467    p_rarch->rarch_ups_pref                         = false;
15468    p_rarch->rarch_patch_blocked                    = false;
15469 #endif
15470 #ifdef HAVE_CONFIGFILE
15471    p_rarch->rarch_block_config_read                = false;
15472    runloop_state.overrides_active               = false;
15473    runloop_state.remaps_core_active             = false;
15474    runloop_state.remaps_game_active             = false;
15475    runloop_state.remaps_content_dir_active      = false;
15476 #endif
15477 
15478    p_rarch->current_core.has_set_input_descriptors = false;
15479    p_rarch->current_core.has_set_subsystems        = false;
15480 
15481    global                                          = &p_rarch->g_extern;
15482    path_clear_all();
15483    dir_clear_all();
15484 
15485    if (global)
15486    {
15487       if (!string_is_empty(global->name.remapfile))
15488          free(global->name.remapfile);
15489       memset(global, 0, sizeof(struct global));
15490    }
15491    retroarch_override_setting_free_state();
15492 }
15493 
15494 #if defined(HAVE_SDL) || defined(HAVE_SDL2) || defined(HAVE_SDL_DINGUX)
sdl_exit(void)15495 static void sdl_exit(void)
15496 {
15497    /* Quit any SDL subsystems, then quit
15498     * SDL itself */
15499    uint32_t sdl_subsystem_flags = SDL_WasInit(0);
15500 
15501    if (sdl_subsystem_flags != 0)
15502    {
15503       SDL_QuitSubSystem(sdl_subsystem_flags);
15504       SDL_Quit();
15505    }
15506 }
15507 #endif
15508 
15509 /**
15510  * main_exit:
15511  *
15512  * Cleanly exit RetroArch.
15513  *
15514  * Also saves configuration files to disk,
15515  * and (optionally) autosave state.
15516  **/
main_exit(void * args)15517 void main_exit(void *args)
15518 {
15519    struct rarch_state *p_rarch  = &rarch_st;
15520 #ifdef HAVE_MENU
15521    struct menu_state  *menu_st  = &p_rarch->menu_driver_state;
15522 #endif
15523    settings_t     *settings     = p_rarch->configuration_settings;
15524    bool     config_save_on_exit = settings->bools.config_save_on_exit;
15525 
15526    video_driver_restore_cached(p_rarch, settings);
15527 
15528    if (config_save_on_exit)
15529       command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
15530 
15531 #if defined(HAVE_GFX_WIDGETS)
15532    /* Do not want display widgets to live any more. */
15533    p_rarch->widgets_persisting = false;
15534 #endif
15535 #ifdef HAVE_MENU
15536    /* Do not want menu context to live any more. */
15537    if (menu_st)
15538       menu_st->data_own = false;
15539 #endif
15540    rarch_ctl(RARCH_CTL_MAIN_DEINIT, NULL);
15541 
15542    if (runloop_state.perfcnt_enable)
15543    {
15544       RARCH_LOG("[PERF]: Performance counters (RetroArch):\n");
15545       log_counters(p_rarch->perf_counters_rarch, p_rarch->perf_ptr_rarch);
15546    }
15547 
15548 #if defined(HAVE_LOGGER) && !defined(ANDROID)
15549    logger_shutdown();
15550 #endif
15551 
15552    frontend_driver_deinit(args);
15553    frontend_driver_exitspawn(
15554          path_get_ptr(RARCH_PATH_CORE),
15555          path_get_realsize(RARCH_PATH_CORE),
15556          p_rarch->launch_arguments);
15557 
15558    p_rarch->has_set_username        = false;
15559    p_rarch->rarch_is_inited         = false;
15560    p_rarch->rarch_error_on_init     = false;
15561 #ifdef HAVE_CONFIGFILE
15562    p_rarch->rarch_block_config_read = false;
15563 #endif
15564 
15565    retroarch_msg_queue_deinit();
15566    driver_uninit(p_rarch, DRIVERS_CMD_ALL);
15567 
15568    retro_main_log_file_deinit();
15569 
15570    rarch_ctl(RARCH_CTL_STATE_FREE,  NULL);
15571    global_free(p_rarch);
15572    task_queue_deinit();
15573 
15574    if (p_rarch->configuration_settings)
15575       free(p_rarch->configuration_settings);
15576    p_rarch->configuration_settings = NULL;
15577 
15578    ui_companion_driver_deinit(p_rarch);
15579 
15580    frontend_driver_shutdown(false);
15581 
15582    retroarch_deinit_drivers(p_rarch, &p_rarch->retro_ctx);
15583    ui_companion_driver_free();
15584    frontend_driver_free();
15585 
15586    rtime_deinit();
15587 
15588 #if defined(ANDROID)
15589    play_feature_delivery_deinit();
15590 #endif
15591 
15592 #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
15593    CoUninitialize();
15594 #endif
15595 
15596 #if defined(HAVE_SDL) || defined(HAVE_SDL2) || defined(HAVE_SDL_DINGUX)
15597    sdl_exit();
15598 #endif
15599 }
15600 
15601 /**
15602  * main_entry:
15603  *
15604  * Main function of RetroArch.
15605  *
15606  * If HAVE_MAIN is not defined, will contain main loop and will not
15607  * be exited from until we exit the program. Otherwise, will
15608  * just do initialization.
15609  *
15610  * Returns: varies per platform.
15611  **/
rarch_main(int argc,char * argv[],void * data)15612 int rarch_main(int argc, char *argv[], void *data)
15613 {
15614    struct rarch_state *p_rarch                                   = &rarch_st;
15615 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
15616    p_rarch->shader_presets_need_reload                           = true;
15617 #endif
15618 #ifdef HAVE_RUNAHEAD
15619    p_rarch->runahead_video_driver_is_active                      = true;
15620    p_rarch->runahead_available                                   = true;
15621    p_rarch->runahead_secondary_core_available                    = true;
15622    p_rarch->runahead_force_input_dirty                           = true;
15623 #endif
15624 #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
15625    if (FAILED(CoInitialize(NULL)))
15626    {
15627       RARCH_ERR("FATAL: Failed to initialize the COM interface\n");
15628       return 1;
15629    }
15630 #endif
15631 
15632    rtime_init();
15633 
15634 #if defined(ANDROID)
15635    play_feature_delivery_init();
15636 #endif
15637 
15638    libretro_free_system_info(&runloop_state.system.info);
15639    command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
15640    rarch_favorites_deinit();
15641 
15642    p_rarch->configuration_settings = (settings_t*)calloc(1, sizeof(settings_t));
15643 
15644    retroarch_deinit_drivers(p_rarch, &p_rarch->retro_ctx);
15645    rarch_ctl(RARCH_CTL_STATE_FREE,  NULL);
15646    global_free(p_rarch);
15647 
15648    frontend_driver_init_first(data);
15649 
15650    if (p_rarch->rarch_is_inited)
15651       driver_uninit(p_rarch, DRIVERS_CMD_ALL);
15652 
15653 #ifdef HAVE_THREAD_STORAGE
15654    sthread_tls_create(&p_rarch->rarch_tls);
15655    sthread_tls_set(&p_rarch->rarch_tls, MAGIC_POINTER);
15656 #endif
15657    p_rarch->video_driver_active = true;
15658    p_rarch->audio_driver_active = true;
15659 
15660    {
15661       uint8_t i;
15662       for (i = 0; i < MAX_USERS; i++)
15663          input_config_set_device(i, RETRO_DEVICE_JOYPAD);
15664    }
15665 
15666    retroarch_msg_queue_init();
15667 
15668    if (p_rarch->current_frontend_ctx)
15669    {
15670       content_ctx_info_t info;
15671 
15672       info.argc            = argc;
15673       info.argv            = argv;
15674       info.args            = data;
15675       info.environ_get     = p_rarch->current_frontend_ctx->environment_get;
15676 
15677       if (!task_push_load_content_from_cli(
15678                NULL,
15679                NULL,
15680                &info,
15681                CORE_TYPE_PLAIN,
15682                NULL,
15683                NULL))
15684          return 1;
15685    }
15686 
15687    ui_companion_driver_init_first(p_rarch->configuration_settings,
15688          p_rarch);
15689 
15690 #if !defined(HAVE_MAIN) || defined(HAVE_QT)
15691    for (;;)
15692    {
15693       int ret;
15694       bool app_exit     = false;
15695 #ifdef HAVE_QT
15696       ui_companion_qt.application->process_events();
15697 #endif
15698       ret = runloop_iterate();
15699 
15700       task_queue_check();
15701 
15702 #ifdef HAVE_QT
15703       app_exit = ui_companion_qt.application->exiting;
15704 #endif
15705 
15706       if (ret == -1 || app_exit)
15707       {
15708 #ifdef HAVE_QT
15709          ui_companion_qt.application->quit();
15710 #endif
15711          break;
15712       }
15713    }
15714 
15715    main_exit(data);
15716 #endif
15717 
15718    return 0;
15719 }
15720 
15721 #if defined(EMSCRIPTEN)
15722 void RWebAudioRecalibrateTime(void);
15723 
emscripten_mainloop(void)15724 void emscripten_mainloop(void)
15725 {
15726    int ret;
15727    static unsigned emscripten_frame_count = 0;
15728    struct rarch_state *p_rarch            = &rarch_st;
15729    settings_t        *settings            = p_rarch->configuration_settings;
15730    bool black_frame_insertion             = settings->uints.video_black_frame_insertion;
15731    bool input_driver_nonblock_state       = p_rarch->input_driver_nonblock_state;
15732    bool runloop_is_slowmotion             = runloop_state.slowmotion;
15733    bool runloop_is_paused                 = runloop_state.paused;
15734 
15735    RWebAudioRecalibrateTime();
15736 
15737    emscripten_frame_count++;
15738 
15739    /* Disable BFI during fast forward, slow-motion,
15740     * and pause to prevent flicker. */
15741    if (
15742              black_frame_insertion
15743          && !input_driver_nonblock_state
15744          && !runloop_is_slowmotion
15745          && !runloop_is_paused)
15746    {
15747       if ((emscripten_frame_count % (black_frame_insertion+1)) != 0)
15748       {
15749          glClear(GL_COLOR_BUFFER_BIT);
15750          if (p_rarch->current_video_context.swap_buffers)
15751             p_rarch->current_video_context.swap_buffers(
15752                   p_rarch->video_context_data);
15753          return;
15754       }
15755    }
15756 
15757    ret = runloop_iterate();
15758 
15759    task_queue_check();
15760 
15761    if (ret != -1)
15762       return;
15763 
15764    main_exit(NULL);
15765    emscripten_force_exit(0);
15766 }
15767 #endif
15768 
15769 #ifndef HAVE_MAIN
15770 #ifdef __cplusplus
15771 extern "C"
15772 #endif
main(int argc,char * argv[])15773 int main(int argc, char *argv[])
15774 {
15775    return rarch_main(argc, argv, NULL);
15776 }
15777 #endif
15778 
15779 /* CORE OPTIONS */
core_option_manager_parse_value_label(const char * value,const char * value_label)15780 static const char *core_option_manager_parse_value_label(
15781       const char *value, const char *value_label)
15782 {
15783    /* 'value_label' may be NULL */
15784    const char *label = string_is_empty(value_label) ?
15785          value : value_label;
15786 
15787    if (string_is_empty(label))
15788       return NULL;
15789 
15790    /* Any label starting with a digit (or +/-)
15791     * cannot be a boolean string, and requires
15792     * no further processing */
15793    if (ISDIGIT((unsigned char)*label) ||
15794        (*label == '+') ||
15795        (*label == '-'))
15796       return label;
15797 
15798    /* Core devs have a habit of using arbitrary
15799     * strings to label boolean values (i.e. enabled,
15800     * Enabled, on, On, ON, true, True, TRUE, disabled,
15801     * Disabled, off, Off, OFF, false, False, FALSE).
15802     * These should all be converted to standard ON/OFF
15803     * strings
15804     * > Note: We require some duplication here
15805     *   (e.g. MENU_ENUM_LABEL_ENABLED *and*
15806     *    MENU_ENUM_LABEL_VALUE_ENABLED) in order
15807     *   to match both localised and non-localised
15808     *   strings. This function is not performance
15809     *   critical, so these extra comparisons do
15810     *   no harm */
15811    if (string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) ||
15812        string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ENABLED)) ||
15813        string_is_equal_noncase(label, "enable") ||
15814        string_is_equal_noncase(label, "on") ||
15815        string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)) ||
15816        string_is_equal_noncase(label, "true") ||
15817        string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TRUE)))
15818       label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON);
15819    else if (string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) ||
15820             string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISABLED)) ||
15821             string_is_equal_noncase(label, "disable") ||
15822             string_is_equal_noncase(label, "off") ||
15823             string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)) ||
15824             string_is_equal_noncase(label, "false") ||
15825             string_is_equal_noncase(label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FALSE)))
15826       label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
15827 
15828    return label;
15829 }
15830 
core_option_manager_parse_variable(core_option_manager_t * opt,size_t idx,const struct retro_variable * var,config_file_t * config_src)15831 static bool core_option_manager_parse_variable(
15832       core_option_manager_t *opt, size_t idx,
15833       const struct retro_variable *var,
15834       config_file_t *config_src)
15835 {
15836    size_t i;
15837    union string_list_elem_attr attr;
15838    const char *val_start      = NULL;
15839    char *value                = NULL;
15840    char *desc_end             = NULL;
15841    struct core_option *option = (struct core_option*)&opt->opts[idx];
15842    struct config_entry_list
15843       *entry                  = NULL;
15844 
15845    /* All options are visible by default */
15846    option->visible            = true;
15847 
15848    if (!string_is_empty(var->key))
15849       option->key             = strdup(var->key);
15850    if (!string_is_empty(var->value))
15851       value                   = strdup(var->value);
15852 
15853    if (!string_is_empty(value))
15854       desc_end                = strstr(value, "; ");
15855 
15856    if (!desc_end)
15857       goto error;
15858 
15859    *desc_end    = '\0';
15860 
15861    if (!string_is_empty(value))
15862       option->desc    = strdup(value);
15863 
15864    val_start          = desc_end + 2;
15865    option->vals       = string_split(val_start, "|");
15866 
15867    if (!option->vals)
15868       goto error;
15869 
15870    /* Legacy core option interface has no concept
15871     * of value labels
15872     * > Use actual values for display purposes */
15873    attr.i             = 0;
15874    option->val_labels = string_list_new();
15875 
15876    if (!option->val_labels)
15877       goto error;
15878 
15879    /* > Loop over values and 'extract' labels */
15880    for (i = 0; i < option->vals->size; i++)
15881    {
15882       const char *value       = option->vals->elems[i].data;
15883       const char *value_label = core_option_manager_parse_value_label(
15884             value, NULL);
15885 
15886       /* Redundant safely check... */
15887       value_label = string_is_empty(value_label) ?
15888             value : value_label;
15889 
15890       /* Append value label string */
15891       string_list_append(option->val_labels, value_label, attr);
15892    }
15893 
15894    /* Legacy core option interface always uses first
15895     * defined value as the default */
15896    option->default_index = 0;
15897    option->index         = 0;
15898 
15899    if (config_src)
15900       entry              = config_get_entry(config_src, option->key);
15901    else
15902       entry              = config_get_entry(opt->conf,  option->key);
15903 
15904    /* Set current config value */
15905    if (entry && !string_is_empty(entry->value))
15906    {
15907       for (i = 0; i < option->vals->size; i++)
15908       {
15909          if (string_is_equal(option->vals->elems[i].data, entry->value))
15910          {
15911             option->index = i;
15912             break;
15913          }
15914       }
15915    }
15916 
15917    free(value);
15918 
15919    return true;
15920 
15921 error:
15922    free(value);
15923    return false;
15924 }
15925 
core_option_manager_parse_option(core_option_manager_t * opt,size_t idx,const struct retro_core_option_definition * option_def,config_file_t * config_src)15926 static bool core_option_manager_parse_option(
15927       core_option_manager_t *opt, size_t idx,
15928       const struct retro_core_option_definition *option_def,
15929       config_file_t *config_src)
15930 {
15931    size_t i;
15932    union string_list_elem_attr attr;
15933    struct config_entry_list
15934       *entry                  = NULL;
15935    size_t num_vals            = 0;
15936    struct core_option *option = (struct core_option*)&opt->opts[idx];
15937    const struct retro_core_option_value
15938       *values                 = option_def->values;
15939 
15940    /* All options are visible by default */
15941    option->visible            = true;
15942 
15943    if (!string_is_empty(option_def->key))
15944       option->key             = strdup(option_def->key);
15945 
15946    if (!string_is_empty(option_def->desc))
15947       option->desc            = strdup(option_def->desc);
15948 
15949    if (!string_is_empty(option_def->info))
15950       option->info            = strdup(option_def->info);
15951 
15952    /* Get number of values */
15953    for (;;)
15954    {
15955       if (string_is_empty(values[num_vals].value))
15956          break;
15957       num_vals++;
15958    }
15959 
15960    if (num_vals < 1)
15961       return false;
15962 
15963    /* Initialise string lists */
15964    attr.i             = 0;
15965    option->vals       = string_list_new();
15966    option->val_labels = string_list_new();
15967 
15968    if (!option->vals || !option->val_labels)
15969       return false;
15970 
15971    /* Initialise default value */
15972    option->default_index = 0;
15973    option->index         = 0;
15974 
15975    /* Extract value/label pairs */
15976    for (i = 0; i < num_vals; i++)
15977    {
15978       const char *value       = values[i].value;
15979       const char *value_label = values[i].label;
15980 
15981       /* Append value string
15982        * > We know that 'value' is always valid */
15983       string_list_append(option->vals, value, attr);
15984 
15985       /* Value label requires additional processing */
15986       value_label = core_option_manager_parse_value_label(
15987             value, value_label);
15988 
15989       /* > Redundant safely check... */
15990       value_label = string_is_empty(value_label) ?
15991             value : value_label;
15992 
15993       /* Append value label string */
15994       string_list_append(option->val_labels, value_label, attr);
15995 
15996       /* Check whether this value is the default setting */
15997       if (!string_is_empty(option_def->default_value))
15998       {
15999          if (string_is_equal(option_def->default_value, value))
16000          {
16001             option->default_index = i;
16002             option->index         = i;
16003          }
16004       }
16005    }
16006 
16007    if (config_src)
16008       entry              = config_get_entry(config_src, option->key);
16009    else
16010       entry              = config_get_entry(opt->conf,  option->key);
16011 
16012    /* Set current config value */
16013    if (entry && !string_is_empty(entry->value))
16014    {
16015       for (i = 0; i < option->vals->size; i++)
16016       {
16017          if (string_is_equal(option->vals->elems[i].data, entry->value))
16018          {
16019             option->index = i;
16020             break;
16021          }
16022       }
16023    }
16024 
16025    return true;
16026 }
16027 
16028 /**
16029  * core_option_manager_free:
16030  * @opt              : options manager handle
16031  *
16032  * Frees core option manager handle.
16033  **/
core_option_manager_free(core_option_manager_t * opt)16034 static void core_option_manager_free(core_option_manager_t *opt)
16035 {
16036    size_t i;
16037 
16038    if (!opt)
16039       return;
16040 
16041    for (i = 0; i < opt->size; i++)
16042    {
16043       if (opt->opts[i].desc)
16044          free(opt->opts[i].desc);
16045       if (opt->opts[i].info)
16046          free(opt->opts[i].info);
16047       if (opt->opts[i].key)
16048          free(opt->opts[i].key);
16049 
16050       if (opt->opts[i].vals)
16051          string_list_free(opt->opts[i].vals);
16052       if (opt->opts[i].val_labels)
16053          string_list_free(opt->opts[i].val_labels);
16054 
16055       opt->opts[i].desc = NULL;
16056       opt->opts[i].info = NULL;
16057       opt->opts[i].key  = NULL;
16058       opt->opts[i].vals = NULL;
16059    }
16060 
16061    if (opt->conf)
16062       config_file_free(opt->conf);
16063    free(opt->opts);
16064    free(opt);
16065 }
16066 
16067 /**
16068  * core_option_manager_new_vars:
16069  * @conf_path        : Filesystem path to write core option config file to.
16070  * @src_conf_path    : Filesystem path from which to load initial config settings.
16071  * @vars             : Pointer to variable array handle.
16072  *
16073  * Legacy version of core_option_manager_new().
16074  * Creates and initializes a core manager handle.
16075  *
16076  * Returns: handle to new core manager handle, otherwise NULL.
16077  **/
core_option_manager_new_vars(const char * conf_path,const char * src_conf_path,const struct retro_variable * vars)16078 static core_option_manager_t *core_option_manager_new_vars(
16079       const char *conf_path, const char *src_conf_path,
16080       const struct retro_variable *vars)
16081 {
16082    const struct retro_variable *var;
16083    size_t size                       = 0;
16084    config_file_t *config_src         = NULL;
16085    core_option_manager_t *opt        = (core_option_manager_t*)
16086       malloc(sizeof(*opt));
16087 
16088    if (!opt)
16089       return NULL;
16090 
16091    opt->conf                         = NULL;
16092    opt->conf_path[0]                 = '\0';
16093    opt->opts                         = NULL;
16094    opt->size                         = 0;
16095    opt->updated                      = false;
16096 
16097    if (!string_is_empty(conf_path))
16098       if (!(opt->conf = config_file_new_from_path_to_string(conf_path)))
16099          if (!(opt->conf = config_file_new_alloc()))
16100             goto error;
16101 
16102    strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path));
16103 
16104    /* Load source config file, if required */
16105    if (!string_is_empty(src_conf_path))
16106       config_src = config_file_new_from_path_to_string(src_conf_path);
16107 
16108    for (var = vars; var->key && var->value; var++)
16109       size++;
16110 
16111    if (size == 0)
16112       goto error;
16113 
16114    opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts));
16115    if (!opt->opts)
16116       goto error;
16117 
16118    opt->size = size;
16119    size      = 0;
16120 
16121    for (var = vars; var->key && var->value; size++, var++)
16122    {
16123       if (!core_option_manager_parse_variable(opt, size, var, config_src))
16124          goto error;
16125    }
16126 
16127    if (config_src)
16128       config_file_free(config_src);
16129 
16130    return opt;
16131 
16132 error:
16133    if (config_src)
16134       config_file_free(config_src);
16135    core_option_manager_free(opt);
16136    return NULL;
16137 }
16138 
16139 /**
16140  * core_option_manager_new:
16141  * @conf_path        : Filesystem path to write core option config file to.
16142  * @src_conf_path    : Filesystem path from which to load initial config settings.
16143  * @option_defs      : Pointer to variable array handle.
16144  *
16145  * Creates and initializes a core manager handle.
16146  *
16147  * Returns: handle to new core manager handle, otherwise NULL.
16148  **/
core_option_manager_new(const char * conf_path,const char * src_conf_path,const struct retro_core_option_definition * option_defs)16149 static core_option_manager_t *core_option_manager_new(
16150       const char *conf_path, const char *src_conf_path,
16151       const struct retro_core_option_definition *option_defs)
16152 {
16153    const struct retro_core_option_definition *option_def;
16154    size_t size                       = 0;
16155    config_file_t *config_src         = NULL;
16156    core_option_manager_t *opt        = (core_option_manager_t*)
16157       malloc(sizeof(*opt));
16158 
16159    if (!opt)
16160       return NULL;
16161 
16162    opt->conf                         = NULL;
16163    opt->conf_path[0]                 = '\0';
16164    opt->opts                         = NULL;
16165    opt->size                         = 0;
16166    opt->updated                      = false;
16167 
16168    if (!string_is_empty(conf_path))
16169       if (!(opt->conf = config_file_new_from_path_to_string(conf_path)))
16170          if (!(opt->conf = config_file_new_alloc()))
16171             goto error;
16172 
16173    strlcpy(opt->conf_path, conf_path, sizeof(opt->conf_path));
16174 
16175    /* Load source config file, if required */
16176    if (!string_is_empty(src_conf_path))
16177       config_src = config_file_new_from_path_to_string(src_conf_path);
16178 
16179    /* Note: 'option_def->info == NULL' is valid */
16180    for (option_def = option_defs;
16181         option_def->key && option_def->desc && option_def->values[0].value;
16182         option_def++)
16183       size++;
16184 
16185    if (size == 0)
16186       goto error;
16187 
16188    opt->opts = (struct core_option*)calloc(size, sizeof(*opt->opts));
16189    if (!opt->opts)
16190       goto error;
16191 
16192    opt->size = size;
16193    size      = 0;
16194 
16195    /* Note: 'option_def->info == NULL' is valid */
16196    for (option_def = option_defs;
16197         option_def->key && option_def->desc && option_def->values[0].value;
16198         size++, option_def++)
16199       if (!core_option_manager_parse_option(opt, size, option_def, config_src))
16200          goto error;
16201 
16202    if (config_src)
16203       config_file_free(config_src);
16204 
16205    return opt;
16206 
16207 error:
16208    if (config_src)
16209       config_file_free(config_src);
16210    core_option_manager_free(opt);
16211    return NULL;
16212 }
16213 
16214 /**
16215  * core_option_manager_flush:
16216  * @opt              : options manager handle
16217  *
16218  * Writes core option key-pair values to file.
16219  **/
core_option_manager_flush(config_file_t * conf,core_option_manager_t * opt)16220 static void core_option_manager_flush(
16221       config_file_t *conf,
16222       core_option_manager_t *opt)
16223 {
16224    size_t i;
16225 
16226    for (i = 0; i < opt->size; i++)
16227    {
16228       struct core_option *option = (struct core_option*)&opt->opts[i];
16229 
16230       if (option)
16231          config_set_string(conf, option->key,
16232                opt->opts[i].vals->elems[opt->opts[i].index].data);
16233    }
16234 }
16235 
16236 /**
16237  * core_option_manager_get_desc:
16238  * @opt              : options manager handle
16239  * @index            : index identifier of the option
16240  *
16241  * Gets description for an option.
16242  *
16243  * Returns: Description for an option.
16244  **/
core_option_manager_get_desc(core_option_manager_t * opt,size_t idx)16245 const char *core_option_manager_get_desc(
16246       core_option_manager_t *opt, size_t idx)
16247 {
16248    if (!opt)
16249       return NULL;
16250    if (idx >= opt->size)
16251       return NULL;
16252    return opt->opts[idx].desc;
16253 }
16254 
16255 /**
16256  * core_option_manager_get_info:
16257  * @opt              : options manager handle
16258  * @idx              : idx identifier of the option
16259  *
16260  * Gets information text for an option.
16261  *
16262  * Returns: Information text for an option.
16263  **/
core_option_manager_get_info(core_option_manager_t * opt,size_t idx)16264 const char *core_option_manager_get_info(
16265       core_option_manager_t *opt, size_t idx)
16266 {
16267    if (!opt)
16268       return NULL;
16269    if (idx >= opt->size)
16270       return NULL;
16271    return opt->opts[idx].info;
16272 }
16273 
16274 /**
16275  * core_option_manager_get_val:
16276  * @opt              : options manager handle
16277  * @index            : index identifier of the option
16278  *
16279  * Gets value for an option.
16280  *
16281  * Returns: Value for an option.
16282  **/
core_option_manager_get_val(core_option_manager_t * opt,size_t idx)16283 const char *core_option_manager_get_val(core_option_manager_t *opt, size_t idx)
16284 {
16285    struct core_option *option = NULL;
16286    if (!opt)
16287       return NULL;
16288    if (idx >= opt->size)
16289       return NULL;
16290    option = (struct core_option*)&opt->opts[idx];
16291    return option->vals->elems[option->index].data;
16292 }
16293 
16294 /**
16295  * core_option_manager_get_val_label:
16296  * @opt              : options manager handle
16297  * @idx              : idx identifier of the option
16298  *
16299  * Gets value label for an option.
16300  *
16301  * Returns: Value label for an option.
16302  **/
core_option_manager_get_val_label(core_option_manager_t * opt,size_t idx)16303 const char *core_option_manager_get_val_label(core_option_manager_t *opt, size_t idx)
16304 {
16305    struct core_option *option = NULL;
16306    if (!opt)
16307       return NULL;
16308    if (idx >= opt->size)
16309       return NULL;
16310    option = (struct core_option*)&opt->opts[idx];
16311    return option->val_labels->elems[option->index].data;
16312 }
16313 
16314 /**
16315  * core_option_manager_get_visible:
16316  * @opt              : options manager handle
16317  * @idx              : idx identifier of the option
16318  *
16319  * Gets whether option should be visible when displaying
16320  * core options in the frontend
16321  *
16322  * Returns: 'true' if option should be displayed by the frontend.
16323  **/
core_option_manager_get_visible(core_option_manager_t * opt,size_t idx)16324 bool core_option_manager_get_visible(core_option_manager_t *opt,
16325       size_t idx)
16326 {
16327    if (!opt)
16328       return false;
16329    if (idx >= opt->size)
16330       return false;
16331    return opt->opts[idx].visible;
16332 }
16333 
core_option_manager_set_val(core_option_manager_t * opt,size_t idx,size_t val_idx)16334 void core_option_manager_set_val(core_option_manager_t *opt,
16335       size_t idx, size_t val_idx)
16336 {
16337    struct core_option *option = NULL;
16338 
16339    if (!opt)
16340       return;
16341    if (idx >= opt->size)
16342       return;
16343 
16344    option        = (struct core_option*)&opt->opts[idx];
16345    option->index = val_idx % option->vals->size;
16346 
16347    opt->updated  = true;
16348 
16349 #ifdef HAVE_CHEEVOS
16350    rcheevos_validate_config_settings();
16351 #endif
16352 }
16353 
core_option_manager_adjust_val(core_option_manager_t * opt,size_t idx,int adjustment)16354 static void core_option_manager_adjust_val(core_option_manager_t* opt,
16355    size_t idx, int adjustment)
16356 {
16357    struct core_option* option = NULL;
16358 
16359    if (!opt)
16360       return;
16361    if (idx >= opt->size)
16362       return;
16363 
16364    option = (struct core_option*)&opt->opts[idx];
16365    option->index = (option->index + option->vals->size + adjustment) % option->vals->size;
16366 
16367    opt->updated = true;
16368 
16369 #ifdef HAVE_CHEEVOS
16370    rcheevos_validate_config_settings();
16371 #endif
16372 }
16373 
16374 /**
16375  * core_option_manager_set_default:
16376  * @opt                   : pointer to core option manager object.
16377  * @idx                   : index of core option to be reset to defaults.
16378  *
16379  * Reset core option specified by @idx and sets default value for option.
16380  **/
core_option_manager_set_default(core_option_manager_t * opt,size_t idx)16381 void core_option_manager_set_default(core_option_manager_t *opt, size_t idx)
16382 {
16383    if (!opt)
16384       return;
16385    if (idx >= opt->size)
16386       return;
16387 
16388    opt->opts[idx].index = opt->opts[idx].default_index;
16389    opt->updated         = true;
16390 
16391 #ifdef HAVE_CHEEVOS
16392    rcheevos_validate_config_settings();
16393 #endif
16394 }
16395 
core_option_manager_get_definitions(const struct retro_core_options_intl * core_options_intl)16396 static struct retro_core_option_definition *core_option_manager_get_definitions(
16397       const struct retro_core_options_intl *core_options_intl)
16398 {
16399    size_t i;
16400    size_t num_options                                     = 0;
16401    struct retro_core_option_definition *option_defs_us    = NULL;
16402    struct retro_core_option_definition *option_defs_local = NULL;
16403    struct retro_core_option_definition *option_defs       = NULL;
16404 
16405    if (!core_options_intl)
16406       return NULL;
16407 
16408    option_defs_us    = core_options_intl->us;
16409    option_defs_local = core_options_intl->local;
16410 
16411    if (!option_defs_us)
16412       return NULL;
16413 
16414    /* Determine number of options */
16415    for (;;)
16416    {
16417       if (string_is_empty(option_defs_us[num_options].key))
16418          break;
16419       num_options++;
16420    }
16421 
16422    if (num_options < 1)
16423       return NULL;
16424 
16425    /* Allocate output option_defs array
16426     * > One extra entry required for terminating NULL entry
16427     * > Note that calloc() sets terminating NULL entry and
16428     *   correctly 'nullifies' each values array */
16429    option_defs = (struct retro_core_option_definition *)calloc(
16430          num_options + 1, sizeof(struct retro_core_option_definition));
16431 
16432    if (!option_defs)
16433       return NULL;
16434 
16435    /* Loop through options... */
16436    for (i = 0; i < num_options; i++)
16437    {
16438       size_t j;
16439       size_t num_values                            = 0;
16440       const char *key                              = option_defs_us[i].key;
16441       const char *local_desc                       = NULL;
16442       const char *local_info                       = NULL;
16443       struct retro_core_option_value *local_values = NULL;
16444 
16445       /* Key is always taken from us english defs */
16446       option_defs[i].key = key;
16447 
16448       /* Default value is always taken from us english defs */
16449       option_defs[i].default_value = option_defs_us[i].default_value;
16450 
16451       /* Try to find corresponding entry in local defs array */
16452       if (option_defs_local)
16453       {
16454          size_t index = 0;
16455 
16456          for (;;)
16457          {
16458             const char *local_key = option_defs_local[index].key;
16459 
16460             if (string_is_empty(local_key))
16461                break;
16462 
16463             if (string_is_equal(key, local_key))
16464             {
16465                local_desc   = option_defs_local[index].desc;
16466                local_info   = option_defs_local[index].info;
16467                local_values = option_defs_local[index].values;
16468                break;
16469             }
16470 
16471             index++;
16472          }
16473       }
16474 
16475       /* Set desc and info strings */
16476       option_defs[i].desc = string_is_empty(local_desc) ? option_defs_us[i].desc : local_desc;
16477       option_defs[i].info = string_is_empty(local_info) ? option_defs_us[i].info : local_info;
16478 
16479       /* Determine number of values
16480        * (always taken from us english defs) */
16481       for (;;)
16482       {
16483          if (string_is_empty(option_defs_us[i].values[num_values].value))
16484             break;
16485          num_values++;
16486       }
16487 
16488       /* Copy values */
16489       for (j = 0; j < num_values; j++)
16490       {
16491          const char *value       = option_defs_us[i].values[j].value;
16492          const char *local_label = NULL;
16493 
16494          /* Value string is always taken from us english defs */
16495          option_defs[i].values[j].value = value;
16496 
16497          /* Try to find corresponding entry in local defs values array */
16498          if (local_values)
16499          {
16500             size_t value_index = 0;
16501 
16502             for (;;)
16503             {
16504                const char *local_value = local_values[value_index].value;
16505 
16506                if (string_is_empty(local_value))
16507                   break;
16508 
16509                if (string_is_equal(value, local_value))
16510                {
16511                   local_label = local_values[value_index].label;
16512                   break;
16513                }
16514 
16515                value_index++;
16516             }
16517          }
16518 
16519          /* Set value label string */
16520          option_defs[i].values[j].label = string_is_empty(local_label) ?
16521                option_defs_us[i].values[j].label : local_label;
16522       }
16523    }
16524 
16525    return option_defs;
16526 }
16527 
core_option_manager_set_display(core_option_manager_t * opt,const char * key,bool visible)16528 static void core_option_manager_set_display(core_option_manager_t *opt,
16529       const char *key, bool visible)
16530 {
16531    size_t i;
16532 
16533    if (!opt || string_is_empty(key))
16534       return;
16535 
16536    for (i = 0; i < opt->size; i++)
16537    {
16538       if (string_is_empty(opt->opts[i].key))
16539          continue;
16540 
16541       if (string_is_equal(opt->opts[i].key, key))
16542       {
16543          opt->opts[i].visible = visible;
16544          return;
16545       }
16546    }
16547 }
16548 
16549 /* DYNAMIC LIBRETRO CORE  */
16550 
libretro_find_subsystem_info(const struct retro_subsystem_info * info,unsigned num_info,const char * ident)16551 const struct retro_subsystem_info *libretro_find_subsystem_info(
16552       const struct retro_subsystem_info *info, unsigned num_info,
16553       const char *ident)
16554 {
16555    unsigned i;
16556    for (i = 0; i < num_info; i++)
16557    {
16558       if (string_is_equal(info[i].ident, ident))
16559          return &info[i];
16560       else if (string_is_equal(info[i].desc, ident))
16561          return &info[i];
16562    }
16563 
16564    return NULL;
16565 }
16566 
16567 /**
16568  * libretro_find_controller_description:
16569  * @info                         : Pointer to controller info handle.
16570  * @id                           : Identifier of controller to search
16571  *                                 for.
16572  *
16573  * Search for a controller of type @id in @info.
16574  *
16575  * Returns: controller description of found controller on success,
16576  * otherwise NULL.
16577  **/
16578 const struct retro_controller_description *
libretro_find_controller_description(const struct retro_controller_info * info,unsigned id)16579 libretro_find_controller_description(
16580       const struct retro_controller_info *info, unsigned id)
16581 {
16582    unsigned i;
16583 
16584    for (i = 0; i < info->num_types; i++)
16585    {
16586       if (info->types[i].id != id)
16587          continue;
16588 
16589       return &info->types[i];
16590    }
16591 
16592    return NULL;
16593 }
16594 
16595 /**
16596  * libretro_free_system_info:
16597  * @info                         : Pointer to system info information.
16598  *
16599  * Frees system information.
16600  **/
libretro_free_system_info(struct retro_system_info * info)16601 void libretro_free_system_info(struct retro_system_info *info)
16602 {
16603    if (!info)
16604       return;
16605 
16606    free((void*)info->library_name);
16607    free((void*)info->library_version);
16608    free((void*)info->valid_extensions);
16609    memset(info, 0, sizeof(*info));
16610 }
16611 
environ_cb_get_system_info(unsigned cmd,void * data)16612 static bool environ_cb_get_system_info(unsigned cmd, void *data)
16613 {
16614    struct rarch_state *p_rarch  = &rarch_st;
16615    rarch_system_info_t *system  = &runloop_state.system;
16616 
16617    switch (cmd)
16618    {
16619       case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
16620          *p_rarch->load_no_content_hook = *(const bool*)data;
16621          break;
16622       case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
16623       {
16624          unsigned i, j, size;
16625          const struct retro_subsystem_info *info =
16626             (const struct retro_subsystem_info*)data;
16627          settings_t *settings    = p_rarch->configuration_settings;
16628          unsigned log_level      = settings->uints.libretro_log_level;
16629 
16630          subsystem_current_count = 0;
16631 
16632          RARCH_LOG("[Environ]: SET_SUBSYSTEM_INFO.\n");
16633 
16634          for (i = 0; info[i].ident; i++)
16635          {
16636             if (log_level != RETRO_LOG_DEBUG)
16637                continue;
16638 
16639             RARCH_LOG("Subsystem ID: %d\nSpecial game type: %s\n  Ident: %s\n  ID: %u\n  Content:\n",
16640                   i,
16641                   info[i].desc,
16642                   info[i].ident,
16643                   info[i].id
16644                   );
16645             for (j = 0; j < info[i].num_roms; j++)
16646             {
16647                RARCH_LOG("    %s (%s)\n",
16648                      info[i].roms[j].desc, info[i].roms[j].required ?
16649                      "required" : "optional");
16650             }
16651          }
16652 
16653          size = i;
16654 
16655          if (log_level == RETRO_LOG_DEBUG)
16656          {
16657             RARCH_LOG("Subsystems: %d\n", i);
16658             if (size > SUBSYSTEM_MAX_SUBSYSTEMS)
16659                RARCH_WARN("Subsystems exceed subsystem max, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEMS);
16660          }
16661 
16662          if (system)
16663          {
16664             for (i = 0; i < size && i < SUBSYSTEM_MAX_SUBSYSTEMS; i++)
16665             {
16666                /* Nasty, but have to do it like this since
16667                 * the pointers are const char *
16668                 * (if we don't free them, we get a memory leak) */
16669                if (!string_is_empty(subsystem_data[i].desc))
16670                   free((char *)subsystem_data[i].desc);
16671                if (!string_is_empty(subsystem_data[i].ident))
16672                   free((char *)subsystem_data[i].ident);
16673                subsystem_data[i].desc     = strdup(info[i].desc);
16674                subsystem_data[i].ident    = strdup(info[i].ident);
16675                subsystem_data[i].id       = info[i].id;
16676                subsystem_data[i].num_roms = info[i].num_roms;
16677 
16678                if (log_level == RETRO_LOG_DEBUG)
16679                   if (subsystem_data[i].num_roms > SUBSYSTEM_MAX_SUBSYSTEM_ROMS)
16680                      RARCH_WARN("Subsystems exceed subsystem max roms, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEM_ROMS);
16681 
16682                for (j = 0; j < subsystem_data[i].num_roms && j < SUBSYSTEM_MAX_SUBSYSTEM_ROMS; j++)
16683                {
16684                   /* Nasty, but have to do it like this since
16685                    * the pointers are const char *
16686                    * (if we don't free them, we get a memory leak) */
16687                   if (!string_is_empty(p_rarch->subsystem_data_roms[i][j].desc))
16688                      free((char *)p_rarch->subsystem_data_roms[i][j].desc);
16689                   if (!string_is_empty(p_rarch->subsystem_data_roms[i][j].valid_extensions))
16690                      free((char *)p_rarch->subsystem_data_roms[i][j].valid_extensions);
16691                   p_rarch->subsystem_data_roms[i][j].desc             = strdup(info[i].roms[j].desc);
16692                   p_rarch->subsystem_data_roms[i][j].valid_extensions = strdup(info[i].roms[j].valid_extensions);
16693                   p_rarch->subsystem_data_roms[i][j].required         = info[i].roms[j].required;
16694                   p_rarch->subsystem_data_roms[i][j].block_extract    = info[i].roms[j].block_extract;
16695                   p_rarch->subsystem_data_roms[i][j].need_fullpath    = info[i].roms[j].need_fullpath;
16696                }
16697 
16698                subsystem_data[i].roms               = p_rarch->subsystem_data_roms[i];
16699             }
16700 
16701             subsystem_current_count =
16702                size <= SUBSYSTEM_MAX_SUBSYSTEMS
16703                ? size
16704                : SUBSYSTEM_MAX_SUBSYSTEMS;
16705          }
16706          break;
16707       }
16708       default:
16709          return false;
16710    }
16711 
16712    return true;
16713 }
16714 
dynamic_request_hw_context(enum retro_hw_context_type type,unsigned minor,unsigned major)16715 static bool dynamic_request_hw_context(enum retro_hw_context_type type,
16716       unsigned minor, unsigned major)
16717 {
16718    switch (type)
16719    {
16720       case RETRO_HW_CONTEXT_NONE:
16721          RARCH_LOG("Requesting no HW context.\n");
16722          break;
16723 
16724       case RETRO_HW_CONTEXT_VULKAN:
16725 #ifdef HAVE_VULKAN
16726          RARCH_LOG("Requesting Vulkan context.\n");
16727          break;
16728 #else
16729          RARCH_ERR("Requesting Vulkan context, but RetroArch is not compiled against Vulkan. Cannot use HW context.\n");
16730          return false;
16731 #endif
16732 
16733 #if defined(HAVE_OPENGLES)
16734 
16735 #if (defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3))
16736       case RETRO_HW_CONTEXT_OPENGLES2:
16737       case RETRO_HW_CONTEXT_OPENGLES3:
16738          RARCH_LOG("Requesting OpenGLES%u context.\n",
16739                type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3);
16740          break;
16741 
16742 #if defined(HAVE_OPENGLES3)
16743       case RETRO_HW_CONTEXT_OPENGLES_VERSION:
16744 #ifndef HAVE_OPENGLES3_2
16745          if (major == 3 && minor == 2)
16746          {
16747             RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
16748                   major, minor);
16749             return false;
16750          }
16751 #endif
16752 #if !defined(HAVE_OPENGLES3_2) && !defined(HAVE_OPENGLES3_1)
16753          if (major == 3 && minor == 1)
16754          {
16755             RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
16756                   major, minor);
16757             return false;
16758          }
16759 #endif
16760          RARCH_LOG("Requesting OpenGLES%u.%u context.\n",
16761                major, minor);
16762          break;
16763 #endif
16764 
16765 #endif
16766       case RETRO_HW_CONTEXT_OPENGL:
16767       case RETRO_HW_CONTEXT_OPENGL_CORE:
16768          RARCH_ERR("Requesting OpenGL context, but RetroArch "
16769                "is compiled against OpenGLES. Cannot use HW context.\n");
16770          return false;
16771 
16772 #elif defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
16773       case RETRO_HW_CONTEXT_OPENGLES2:
16774       case RETRO_HW_CONTEXT_OPENGLES3:
16775          RARCH_ERR("Requesting OpenGLES%u context, but RetroArch "
16776                "is compiled against OpenGL. Cannot use HW context.\n",
16777                type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3);
16778          return false;
16779 
16780       case RETRO_HW_CONTEXT_OPENGLES_VERSION:
16781          RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch "
16782                "is compiled against OpenGL. Cannot use HW context.\n",
16783                major, minor);
16784          return false;
16785 
16786       case RETRO_HW_CONTEXT_OPENGL:
16787          RARCH_LOG("Requesting OpenGL context.\n");
16788          break;
16789 
16790       case RETRO_HW_CONTEXT_OPENGL_CORE:
16791          /* TODO/FIXME - we should do a check here to see if
16792           * the requested core GL version is supported */
16793          RARCH_LOG("Requesting core OpenGL context (%u.%u).\n",
16794                major, minor);
16795          break;
16796 #endif
16797 
16798 #if defined(HAVE_D3D9) || defined(HAVE_D3D11)
16799       case RETRO_HW_CONTEXT_DIRECT3D:
16800          switch (major)
16801          {
16802 #ifdef HAVE_D3D9
16803             case 9:
16804                RARCH_LOG("Requesting D3D9 context.\n");
16805                break;
16806 #endif
16807 #ifdef HAVE_D3D11
16808             case 11:
16809                RARCH_LOG("Requesting D3D11 context.\n");
16810                break;
16811 #endif
16812             default:
16813                RARCH_LOG("Requesting unknown context.\n");
16814                return false;
16815          }
16816          break;
16817 #endif
16818 
16819       default:
16820          RARCH_LOG("Requesting unknown context.\n");
16821          return false;
16822    }
16823 
16824    return true;
16825 }
16826 
dynamic_verify_hw_context(const char * video_ident,bool driver_switch_enable,enum retro_hw_context_type type,unsigned minor,unsigned major)16827 static bool dynamic_verify_hw_context(
16828       const char *video_ident,
16829       bool driver_switch_enable,
16830       enum retro_hw_context_type type,
16831       unsigned minor, unsigned major)
16832 {
16833    if (driver_switch_enable)
16834       return true;
16835 
16836    switch (type)
16837    {
16838       case RETRO_HW_CONTEXT_VULKAN:
16839          if (!string_is_equal(video_ident, "vulkan"))
16840             return false;
16841          break;
16842 #if defined(HAVE_OPENGL_CORE)
16843       case RETRO_HW_CONTEXT_OPENGL_CORE:
16844          if (!string_is_equal(video_ident, "glcore"))
16845             return false;
16846          break;
16847 #else
16848       case RETRO_HW_CONTEXT_OPENGL_CORE:
16849 #endif
16850       case RETRO_HW_CONTEXT_OPENGLES2:
16851       case RETRO_HW_CONTEXT_OPENGLES3:
16852       case RETRO_HW_CONTEXT_OPENGLES_VERSION:
16853       case RETRO_HW_CONTEXT_OPENGL:
16854          if (!string_is_equal(video_ident, "gl") &&
16855              !string_is_equal(video_ident, "glcore"))
16856             return false;
16857          break;
16858       case RETRO_HW_CONTEXT_DIRECT3D:
16859          if (!(string_is_equal(video_ident, "d3d11") && major == 11))
16860             return false;
16861          break;
16862       default:
16863          break;
16864    }
16865 
16866    return true;
16867 }
16868 
rarch_log_libretro(enum retro_log_level level,const char * fmt,...)16869 static void rarch_log_libretro(
16870       enum retro_log_level level,
16871       const char *fmt, ...)
16872 {
16873    va_list vp;
16874    struct rarch_state *p_rarch = &rarch_st;
16875    settings_t        *settings = p_rarch->configuration_settings;
16876    unsigned libretro_log_level = settings->uints.libretro_log_level;
16877 
16878    if ((unsigned)level < libretro_log_level)
16879       return;
16880 
16881    if (!verbosity_is_enabled())
16882       return;
16883 
16884    va_start(vp, fmt);
16885 
16886    switch (level)
16887    {
16888       case RETRO_LOG_DEBUG:
16889          RARCH_LOG_V("[libretro DEBUG]", fmt, vp);
16890          break;
16891 
16892       case RETRO_LOG_INFO:
16893          RARCH_LOG_OUTPUT_V("[libretro INFO]", fmt, vp);
16894          break;
16895 
16896       case RETRO_LOG_WARN:
16897          RARCH_WARN_V("[libretro WARN]", fmt, vp);
16898          break;
16899 
16900       case RETRO_LOG_ERROR:
16901          RARCH_ERR_V("[libretro ERROR]", fmt, vp);
16902          break;
16903 
16904       default:
16905          break;
16906    }
16907 
16908    va_end(vp);
16909 }
16910 
core_performance_counter_start(struct retro_perf_counter * perf)16911 static void core_performance_counter_start(
16912       struct retro_perf_counter *perf)
16913 {
16914    bool runloop_perfcnt_enable = runloop_state.perfcnt_enable;
16915 
16916    if (runloop_perfcnt_enable)
16917    {
16918       perf->call_cnt++;
16919       perf->start      = cpu_features_get_perf_counter();
16920    }
16921 }
16922 
core_performance_counter_stop(struct retro_perf_counter * perf)16923 static void core_performance_counter_stop(struct retro_perf_counter *perf)
16924 {
16925    bool runloop_perfcnt_enable = runloop_state.perfcnt_enable;
16926 
16927    if (runloop_perfcnt_enable)
16928       perf->total += cpu_features_get_perf_counter() - perf->start;
16929 }
16930 
mmap_add_bits_down(size_t n)16931 static size_t mmap_add_bits_down(size_t n)
16932 {
16933    n |= n >>  1;
16934    n |= n >>  2;
16935    n |= n >>  4;
16936    n |= n >>  8;
16937    n |= n >> 16;
16938 
16939    /* double shift to avoid warnings on 32bit (it's dead code,
16940     * but compilers suck) */
16941    if (sizeof(size_t) > 4)
16942       n |= n >> 16 >> 16;
16943 
16944    return n;
16945 }
16946 
mmap_inflate(size_t addr,size_t mask)16947 static size_t mmap_inflate(size_t addr, size_t mask)
16948 {
16949     while (mask)
16950    {
16951       size_t tmp = (mask - 1) & ~mask;
16952 
16953       /* to put in an 1 bit instead, OR in tmp+1 */
16954       addr       = ((addr & ~tmp) << 1) | (addr & tmp);
16955       mask       = mask & (mask - 1);
16956    }
16957 
16958    return addr;
16959 }
16960 
mmap_reduce(size_t addr,size_t mask)16961 static size_t mmap_reduce(size_t addr, size_t mask)
16962 {
16963    while (mask)
16964    {
16965       size_t tmp = (mask - 1) & ~mask;
16966       addr       = (addr & tmp) | ((addr >> 1) & ~tmp);
16967       mask       = (mask & (mask - 1)) >> 1;
16968    }
16969 
16970    return addr;
16971 }
16972 
mmap_highest_bit(size_t n)16973 static size_t mmap_highest_bit(size_t n)
16974 {
16975    n = mmap_add_bits_down(n);
16976    return n ^ (n >> 1);
16977 }
16978 
16979 
mmap_preprocess_descriptors(rarch_memory_descriptor_t * first,unsigned count)16980 static bool mmap_preprocess_descriptors(
16981       rarch_memory_descriptor_t *first, unsigned count)
16982 {
16983    size_t                      top_addr = 1;
16984    rarch_memory_descriptor_t *desc      = NULL;
16985    const rarch_memory_descriptor_t *end = first + count;
16986 
16987    for (desc = first; desc < end; desc++)
16988    {
16989       if (desc->core.select != 0)
16990          top_addr |= desc->core.select;
16991       else
16992          top_addr |= desc->core.start + desc->core.len - 1;
16993    }
16994 
16995    top_addr = mmap_add_bits_down(top_addr);
16996 
16997    for (desc = first; desc < end; desc++)
16998    {
16999       if (desc->core.select == 0)
17000       {
17001          if (desc->core.len == 0)
17002             return false;
17003 
17004          if ((desc->core.len & (desc->core.len - 1)) != 0)
17005             return false;
17006 
17007          desc->core.select = top_addr & ~mmap_inflate(mmap_add_bits_down(desc->core.len - 1),
17008                desc->core.disconnect);
17009       }
17010 
17011       if (desc->core.len == 0)
17012          desc->core.len = mmap_add_bits_down(mmap_reduce(top_addr & ~desc->core.select,
17013                   desc->core.disconnect)) + 1;
17014 
17015       if (desc->core.start & ~desc->core.select)
17016          return false;
17017 
17018       while (mmap_reduce(top_addr & ~desc->core.select, desc->core.disconnect) >> 1 > desc->core.len - 1)
17019          desc->core.disconnect |= mmap_highest_bit(top_addr & ~desc->core.select & ~desc->core.disconnect);
17020 
17021       desc->disconnect_mask = mmap_add_bits_down(desc->core.len - 1);
17022       desc->core.disconnect &= desc->disconnect_mask;
17023 
17024       while ((~desc->disconnect_mask) >> 1 & desc->core.disconnect)
17025       {
17026          desc->disconnect_mask >>= 1;
17027          desc->core.disconnect &= desc->disconnect_mask;
17028       }
17029    }
17030 
17031    return true;
17032 }
17033 
rarch_clear_all_thread_waits(unsigned clear_threads,void * data)17034 static bool rarch_clear_all_thread_waits(
17035       unsigned clear_threads, void *data)
17036 {
17037    struct rarch_state *p_rarch  = &rarch_st;
17038    if ( clear_threads > 0)
17039       audio_driver_start(p_rarch,
17040             false);
17041    else
17042       audio_driver_stop(p_rarch);
17043 
17044    return true;
17045 }
17046 
runloop_core_msg_queue_push(struct retro_system_av_info * av_info,const struct retro_message_ext * msg)17047 static void runloop_core_msg_queue_push(
17048       struct retro_system_av_info *av_info,
17049       const struct retro_message_ext *msg)
17050 {
17051    double fps;
17052    unsigned duration_frames;
17053    enum message_queue_category category;
17054 
17055    /* Assign category */
17056    switch (msg->level)
17057    {
17058       case RETRO_LOG_WARN:
17059          category = MESSAGE_QUEUE_CATEGORY_WARNING;
17060          break;
17061       case RETRO_LOG_ERROR:
17062          category = MESSAGE_QUEUE_CATEGORY_ERROR;
17063          break;
17064       case RETRO_LOG_INFO:
17065       case RETRO_LOG_DEBUG:
17066       default:
17067          category = MESSAGE_QUEUE_CATEGORY_INFO;
17068          break;
17069    }
17070 
17071    /* Get duration in frames */
17072    fps             = (av_info && (av_info->timing.fps > 0)) ? av_info->timing.fps : 60.0;
17073    duration_frames = (unsigned)((fps * (float)msg->duration / 1000.0f) + 0.5f);
17074 
17075    /* Note: Do not flush the message queue here - a core
17076     * may need to send multiple notifications simultaneously */
17077    runloop_msg_queue_push(msg->msg,
17078          msg->priority, duration_frames,
17079          false, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
17080          category);
17081 }
17082 
17083 #if defined(HAVE_VULKAN) || defined(HAVE_D3D11) || defined(HAVE_D3D9) || defined(HAVE_OPENGL_CORE)
hw_render_context_driver(enum retro_hw_context_type type,int major,int minor)17084 static video_driver_t *hw_render_context_driver(enum retro_hw_context_type type, int major, int minor)
17085 {
17086    switch (type)
17087    {
17088       case RETRO_HW_CONTEXT_OPENGL_CORE:
17089 #ifdef HAVE_OPENGL_CORE
17090          return &video_gl_core;
17091 #else
17092          break;
17093 #endif
17094       case RETRO_HW_CONTEXT_OPENGL:
17095 #ifdef HAVE_OPENGL
17096          return &video_gl2;
17097 #else
17098          break;
17099 #endif
17100       case RETRO_HW_CONTEXT_DIRECT3D:
17101 #if defined(HAVE_D3D9)
17102          if (major == 9)
17103             return &video_d3d9;
17104 #endif
17105 #if defined(HAVE_D3D11)
17106          if (major == 11)
17107             return &video_d3d11;
17108 #endif
17109          break;
17110       case RETRO_HW_CONTEXT_VULKAN:
17111 #if defined(HAVE_VULKAN)
17112          return &video_vulkan;
17113 #else
17114          break;
17115 #endif
17116       default:
17117       case RETRO_HW_CONTEXT_NONE:
17118          break;
17119    }
17120 
17121    return NULL;
17122 }
17123 #endif
17124 
hw_render_context_type(const char * s)17125 static enum retro_hw_context_type hw_render_context_type(const char *s)
17126 {
17127 #ifdef HAVE_OPENGL_CORE
17128    if (string_is_equal(s, "glcore"))
17129       return RETRO_HW_CONTEXT_OPENGL_CORE;
17130 #endif
17131 #ifdef HAVE_OPENGL
17132    if (string_is_equal(s, "gl"))
17133       return RETRO_HW_CONTEXT_OPENGL;
17134 #endif
17135 #ifdef HAVE_VULKAN
17136    if (string_is_equal(s, "vulkan"))
17137       return RETRO_HW_CONTEXT_VULKAN;
17138 #endif
17139 #ifdef HAVE_D3D11
17140    if (string_is_equal(s, "d3d11"))
17141       return RETRO_HW_CONTEXT_DIRECT3D;
17142 #endif
17143 #ifdef HAVE_D3D11
17144    if (string_is_equal(s, "d3d9"))
17145       return RETRO_HW_CONTEXT_DIRECT3D;
17146 #endif
17147    return RETRO_HW_CONTEXT_NONE;
17148 }
17149 
hw_render_context_name(enum retro_hw_context_type type,int major,int minor)17150 static const char *hw_render_context_name(enum retro_hw_context_type type, int major, int minor)
17151 {
17152 #ifdef HAVE_OPENGL_CORE
17153    if (type == RETRO_HW_CONTEXT_OPENGL_CORE)
17154       return "glcore";
17155 #endif
17156 #ifdef HAVE_OPENGL
17157    switch (type)
17158    {
17159       case RETRO_HW_CONTEXT_OPENGLES2:
17160       case RETRO_HW_CONTEXT_OPENGLES3:
17161       case RETRO_HW_CONTEXT_OPENGLES_VERSION:
17162       case RETRO_HW_CONTEXT_OPENGL:
17163 #ifndef HAVE_OPENGL_CORE
17164       case RETRO_HW_CONTEXT_OPENGL_CORE:
17165 #endif
17166          return "gl";
17167       default:
17168          break;
17169    }
17170 #endif
17171 #ifdef HAVE_VULKAN
17172    if (type == RETRO_HW_CONTEXT_VULKAN)
17173       return "vulkan";
17174 #endif
17175 #ifdef HAVE_D3D11
17176    if (type == RETRO_HW_CONTEXT_DIRECT3D && major == 11)
17177       return "d3d11";
17178 #endif
17179 #ifdef HAVE_D3D9
17180    if (type == RETRO_HW_CONTEXT_DIRECT3D && major == 9)
17181       return "d3d9";
17182 #endif
17183    return "N/A";
17184 }
17185 
17186 /**
17187  * rarch_environment_cb:
17188  * @cmd                          : Identifier of command.
17189  * @data                         : Pointer to data.
17190  *
17191  * Environment callback function implementation.
17192  *
17193  * Returns: true (1) if environment callback command could
17194  * be performed, otherwise false (0).
17195  **/
rarch_environment_cb(unsigned cmd,void * data)17196 static bool rarch_environment_cb(unsigned cmd, void *data)
17197 {
17198    unsigned p;
17199    struct rarch_state *p_rarch  = &rarch_st;
17200    settings_t         *settings = p_rarch->configuration_settings;
17201    rarch_system_info_t *system  = &runloop_state.system;
17202    bool ignore_environment_cb   = p_rarch->ignore_environment_cb;
17203 
17204    if (ignore_environment_cb)
17205       return false;
17206 
17207    switch (cmd)
17208    {
17209       case RETRO_ENVIRONMENT_GET_OVERSCAN:
17210          {
17211             bool video_crop_overscan = settings->bools.video_crop_overscan;
17212             *(bool*)data = !video_crop_overscan;
17213             RARCH_LOG("[Environ]: GET_OVERSCAN: %u\n",
17214                   (unsigned)!video_crop_overscan);
17215          }
17216          break;
17217 
17218       case RETRO_ENVIRONMENT_GET_CAN_DUPE:
17219          *(bool*)data = true;
17220          RARCH_LOG("[Environ]: GET_CAN_DUPE: true\n");
17221          break;
17222 
17223       case RETRO_ENVIRONMENT_GET_VARIABLE:
17224          {
17225             unsigned log_level         = settings->uints.libretro_log_level;
17226             struct retro_variable *var = (struct retro_variable*)data;
17227 
17228             if (!var)
17229                return true;
17230 
17231             var->value = NULL;
17232 
17233             if (!runloop_state.core_options)
17234             {
17235                RARCH_LOG("[Environ]: GET_VARIABLE %s: not implemented.\n",
17236                      var->key);
17237                return true;
17238             }
17239 
17240             {
17241                size_t i;
17242 
17243 #ifdef HAVE_RUNAHEAD
17244                if (runloop_state.core_options->updated)
17245                   p_rarch->has_variable_update = true;
17246 #endif
17247 
17248                runloop_state.core_options->updated   = false;
17249 
17250                for (i = 0; i < runloop_state.core_options->size; i++)
17251                {
17252                   if (!string_is_empty(runloop_state.core_options->opts[i].key))
17253                      if (string_is_equal(
17254                               runloop_state.core_options->opts[i].key, var->key))
17255                      {
17256                         var->value = runloop_state.core_options->opts[i].vals->elems[
17257                            runloop_state.core_options->opts[i].index].data;
17258                         break;
17259                      }
17260                }
17261             }
17262 
17263             if (log_level == RETRO_LOG_DEBUG)
17264             {
17265                char s[128];
17266                s[0] = '\0';
17267 
17268                snprintf(s, sizeof(s), "[Environ]: GET_VARIABLE %s:\n\t%s\n", var->key, var->value ? var->value :
17269                      msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
17270                RARCH_LOG(s);
17271             }
17272          }
17273 
17274          break;
17275 
17276       case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE:
17277          if (runloop_state.core_options)
17278             *(bool*)data = runloop_state.core_options->updated;
17279          else
17280             *(bool*)data = false;
17281          break;
17282 
17283       /* SET_VARIABLES: Legacy path */
17284       case RETRO_ENVIRONMENT_SET_VARIABLES:
17285          RARCH_LOG("[Environ]: SET_VARIABLES.\n");
17286 
17287          if (runloop_state.core_options)
17288             retroarch_deinit_core_options(p_rarch,
17289                   path_get(RARCH_PATH_CORE_OPTIONS)
17290                   );
17291          retroarch_init_core_variables(
17292                p_rarch,
17293                (const struct retro_variable *)data);
17294          break;
17295 
17296       case RETRO_ENVIRONMENT_SET_CORE_OPTIONS:
17297          RARCH_LOG("[Environ]: SET_CORE_OPTIONS.\n");
17298 
17299          if (runloop_state.core_options)
17300             retroarch_deinit_core_options(p_rarch,
17301                   path_get(RARCH_PATH_CORE_OPTIONS)
17302                   );
17303          rarch_init_core_options(p_rarch,
17304                (const struct retro_core_option_definition*)data);
17305 
17306          break;
17307 
17308       case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL:
17309          RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.\n");
17310 
17311          {
17312             struct retro_core_option_definition *option_defs =
17313                core_option_manager_get_definitions((const struct retro_core_options_intl*)data);
17314 
17315             if (runloop_state.core_options)
17316                retroarch_deinit_core_options(p_rarch,
17317                      path_get(RARCH_PATH_CORE_OPTIONS)
17318                      );
17319 
17320             /* Parse core_options_intl to create option definitions array */
17321             if (option_defs)
17322             {
17323                /* Initialise core options */
17324                rarch_init_core_options(p_rarch, option_defs);
17325 
17326                /* Clean up */
17327                free(option_defs);
17328             }
17329 
17330          }
17331          break;
17332 
17333       case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY:
17334          RARCH_DBG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.\n");
17335 
17336          {
17337             const struct retro_core_option_display *core_options_display = (const struct retro_core_option_display *)data;
17338 
17339             if (runloop_state.core_options && core_options_display)
17340                core_option_manager_set_display(
17341                      runloop_state.core_options,
17342                      core_options_display->key,
17343                      core_options_display->visible);
17344          }
17345          break;
17346 
17347       case RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION:
17348          RARCH_LOG("[Environ]: GET_MESSAGE_INTERFACE_VERSION.\n");
17349          /* Current API version is 1 */
17350          *(unsigned *)data = 1;
17351          break;
17352 
17353       case RETRO_ENVIRONMENT_SET_MESSAGE:
17354       {
17355          const struct retro_message *msg = (const struct retro_message*)data;
17356          RARCH_LOG("[Environ]: SET_MESSAGE: %s\n", msg->msg);
17357 #if defined(HAVE_GFX_WIDGETS)
17358          if (p_rarch->widgets_active)
17359             gfx_widget_set_libretro_message(&p_rarch->dispwidget_st,
17360                   msg->msg,
17361                   roundf((float)msg->frames / 60.0f * 1000.0f));
17362          else
17363 #endif
17364             runloop_msg_queue_push(msg->msg, 3, msg->frames,
17365                   true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
17366                   MESSAGE_QUEUE_CATEGORY_INFO);
17367          break;
17368       }
17369 
17370       case RETRO_ENVIRONMENT_SET_MESSAGE_EXT:
17371       {
17372          const struct retro_message_ext *msg =
17373             (const struct retro_message_ext*)data;
17374 
17375          /* Log message, if required */
17376          if (msg->target != RETRO_MESSAGE_TARGET_OSD)
17377          {
17378             settings_t *settings = p_rarch->configuration_settings;
17379             unsigned log_level   = settings->uints.frontend_log_level;
17380             switch (msg->level)
17381             {
17382                case RETRO_LOG_DEBUG:
17383                   if (log_level == RETRO_LOG_DEBUG)
17384                      RARCH_LOG("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
17385                   break;
17386                case RETRO_LOG_WARN:
17387                   RARCH_WARN("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
17388                   break;
17389                case RETRO_LOG_ERROR:
17390                   RARCH_ERR("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
17391                   break;
17392                case RETRO_LOG_INFO:
17393                default:
17394                   RARCH_LOG("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
17395                   break;
17396             }
17397          }
17398 
17399          /* Display message via OSD, if required */
17400          if (msg->target != RETRO_MESSAGE_TARGET_LOG)
17401          {
17402             switch (msg->type)
17403             {
17404                /* Handle 'status' messages */
17405                case RETRO_MESSAGE_TYPE_STATUS:
17406 
17407                   /* Note: We need to lock a mutex here. Strictly
17408                    * speaking, runloop_core_status_msg is not part
17409                    * of the message queue, but:
17410                    * - It may be implemented as a queue in the future
17411                    * - It seems unnecessary to create a new slock_t
17412                    *   object for this type of message when
17413                    *   _runloop_msg_queue_lock is already available
17414                    * We therefore just call runloop_msg_queue_lock()/
17415                    * runloop_msg_queue_unlock() in this case */
17416                   RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
17417 
17418                   /* If a message is already set, only overwrite
17419                    * it if the new message has the same or higher
17420                    * priority */
17421                   if (!runloop_core_status_msg.set ||
17422                       (runloop_core_status_msg.priority <= msg->priority))
17423                   {
17424                      if (!string_is_empty(msg->msg))
17425                      {
17426                         strlcpy(runloop_core_status_msg.str, msg->msg,
17427                               sizeof(runloop_core_status_msg.str));
17428 
17429                         runloop_core_status_msg.duration = (float)msg->duration;
17430                         runloop_core_status_msg.set      = true;
17431                      }
17432                      else
17433                      {
17434                         /* Ensure sane behaviour if core sends an
17435                          * empty message */
17436                         runloop_core_status_msg.str[0] = '\0';
17437                         runloop_core_status_msg.priority = 0;
17438                         runloop_core_status_msg.duration = 0.0f;
17439                         runloop_core_status_msg.set      = false;
17440                      }
17441                   }
17442 
17443                   RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
17444                   break;
17445 
17446 #if defined(HAVE_GFX_WIDGETS)
17447                /* Handle 'alternate' non-queued notifications */
17448                case RETRO_MESSAGE_TYPE_NOTIFICATION_ALT:
17449                   if (p_rarch->widgets_active)
17450                      gfx_widget_set_libretro_message(&p_rarch->dispwidget_st,
17451                            msg->msg, msg->duration);
17452                   else
17453                      runloop_core_msg_queue_push(
17454                            &p_rarch->video_driver_av_info, msg);
17455 
17456                   break;
17457 
17458                /* Handle 'progress' messages */
17459                case RETRO_MESSAGE_TYPE_PROGRESS:
17460                   if (p_rarch->widgets_active)
17461                      gfx_widget_set_progress_message(&p_rarch->dispwidget_st,
17462                            msg->msg, msg->duration,
17463                            msg->priority, msg->progress);
17464                   else
17465                      runloop_core_msg_queue_push(
17466                            &p_rarch->video_driver_av_info, msg);
17467 
17468                   break;
17469 #endif
17470                /* Handle standard (queued) notifications */
17471                case RETRO_MESSAGE_TYPE_NOTIFICATION:
17472                default:
17473                   runloop_core_msg_queue_push(
17474                         &p_rarch->video_driver_av_info, msg);
17475                   break;
17476             }
17477          }
17478 
17479          break;
17480       }
17481 
17482       case RETRO_ENVIRONMENT_SET_ROTATION:
17483       {
17484          unsigned rotation       = *(const unsigned*)data;
17485          bool video_allow_rotate = settings->bools.video_allow_rotate;
17486 
17487          RARCH_LOG("[Environ]: SET_ROTATION: %u\n", rotation);
17488          if (!video_allow_rotate)
17489             break;
17490 
17491          if (system)
17492             system->rotation = rotation;
17493 
17494          if (!video_driver_set_rotation(rotation))
17495             return false;
17496          break;
17497       }
17498 
17499       case RETRO_ENVIRONMENT_SHUTDOWN:
17500          RARCH_LOG("[Environ]: SHUTDOWN.\n");
17501 
17502          /* This case occurs when a core (internally) requests
17503           * a shutdown event. Must save runtime log file here,
17504           * since normal command.c CMD_EVENT_CORE_DEINIT event
17505           * will not occur until after the current content has
17506           * been cleared (causing log to be skipped) */
17507          command_event_runtime_log_deinit(p_rarch,
17508                settings->bools.content_runtime_log,
17509                settings->bools.content_runtime_log_aggregate,
17510                settings->paths.directory_runtime_log,
17511                settings->paths.directory_playlist);
17512 
17513          runloop_state.shutdown_initiated      = true;
17514          runloop_state.core_shutdown_initiated = true;
17515          break;
17516 
17517       case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL:
17518          if (system)
17519          {
17520             system->performance_level = *(const unsigned*)data;
17521             RARCH_LOG("[Environ]: PERFORMANCE_LEVEL: %u.\n",
17522                   system->performance_level);
17523          }
17524          break;
17525 
17526       case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY:
17527          {
17528             const char *dir_system          = settings->paths.directory_system;
17529             bool systemfiles_in_content_dir = settings->bools.systemfiles_in_content_dir;
17530             if (string_is_empty(dir_system) || systemfiles_in_content_dir)
17531             {
17532                const char *fullpath = path_get(RARCH_PATH_CONTENT);
17533                if (!string_is_empty(fullpath))
17534                {
17535                   char temp_path[PATH_MAX_LENGTH];
17536                   temp_path[0]     = '\0';
17537 
17538                   if (string_is_empty(dir_system))
17539                      RARCH_WARN("[Environ]: SYSTEM DIR is empty, assume CONTENT DIR %s\n",
17540                            fullpath);
17541                   fill_pathname_basedir(temp_path, fullpath, sizeof(temp_path));
17542                   dir_set(RARCH_DIR_SYSTEM, temp_path);
17543                }
17544 
17545                *(const char**)data = dir_get_ptr(RARCH_DIR_SYSTEM);
17546                RARCH_LOG("[Environ]: SYSTEM_DIRECTORY: \"%s\".\n",
17547                      dir_system);
17548             }
17549             else
17550             {
17551                *(const char**)data = dir_system;
17552                RARCH_LOG("[Environ]: SYSTEM_DIRECTORY: \"%s\".\n",
17553                      dir_system);
17554             }
17555          }
17556          break;
17557 
17558       case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY:
17559          RARCH_LOG("[Environ]: GET_SAVE_DIRECTORY.\n");
17560          *(const char**)data = p_rarch->current_savefile_dir;
17561          break;
17562 
17563       case RETRO_ENVIRONMENT_GET_USERNAME:
17564          *(const char**)data = *settings->paths.username ?
17565             settings->paths.username : NULL;
17566          RARCH_LOG("[Environ]: GET_USERNAME: \"%s\".\n",
17567                settings->paths.username);
17568          break;
17569 
17570       case RETRO_ENVIRONMENT_GET_LANGUAGE:
17571 #ifdef HAVE_LANGEXTRA
17572          {
17573             unsigned user_lang = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE);
17574             *(unsigned *)data  = user_lang;
17575             RARCH_LOG("[Environ]: GET_LANGUAGE: \"%u\".\n", user_lang);
17576          }
17577 #endif
17578          break;
17579 
17580       case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT:
17581       {
17582          enum retro_pixel_format pix_fmt =
17583             *(const enum retro_pixel_format*)data;
17584 
17585          switch (pix_fmt)
17586          {
17587             case RETRO_PIXEL_FORMAT_0RGB1555:
17588                RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: 0RGB1555.\n");
17589                break;
17590 
17591             case RETRO_PIXEL_FORMAT_RGB565:
17592                RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: RGB565.\n");
17593                break;
17594             case RETRO_PIXEL_FORMAT_XRGB8888:
17595                RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: XRGB8888.\n");
17596                break;
17597             default:
17598                return false;
17599          }
17600 
17601          p_rarch->video_driver_pix_fmt = pix_fmt;
17602          break;
17603       }
17604 
17605       case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS:
17606       {
17607          static const char *libretro_btn_desc[]    = {
17608             "B (bottom)", "Y (left)", "Select", "Start",
17609             "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right",
17610             "A (right)", "X (up)",
17611             "L", "R", "L2", "R2", "L3", "R3",
17612          };
17613 
17614          if (system)
17615          {
17616             unsigned retro_id;
17617             const struct retro_input_descriptor *desc = NULL;
17618             memset((void*)&system->input_desc_btn, 0,
17619                   sizeof(system->input_desc_btn));
17620 
17621             desc = (const struct retro_input_descriptor*)data;
17622 
17623             for (; desc->description; desc++)
17624             {
17625                unsigned retro_port = desc->port;
17626 
17627                retro_id            = desc->id;
17628 
17629                if (desc->port >= MAX_USERS)
17630                   continue;
17631 
17632                if (desc->id >= RARCH_FIRST_CUSTOM_BIND)
17633                   continue;
17634 
17635                switch (desc->device)
17636                {
17637                   case RETRO_DEVICE_JOYPAD:
17638                      system->input_desc_btn[retro_port]
17639                         [retro_id] = desc->description;
17640                      break;
17641                   case RETRO_DEVICE_ANALOG:
17642                      switch (retro_id)
17643                      {
17644                         case RETRO_DEVICE_ID_ANALOG_X:
17645                            switch (desc->index)
17646                            {
17647                               case RETRO_DEVICE_INDEX_ANALOG_LEFT:
17648                                  system->input_desc_btn[retro_port]
17649                                     [RARCH_ANALOG_LEFT_X_PLUS]  = desc->description;
17650                                  system->input_desc_btn[retro_port]
17651                                     [RARCH_ANALOG_LEFT_X_MINUS] = desc->description;
17652                                  break;
17653                               case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
17654                                  system->input_desc_btn[retro_port]
17655                                     [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description;
17656                                  system->input_desc_btn[retro_port]
17657                                     [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description;
17658                                  break;
17659                            }
17660                            break;
17661                         case RETRO_DEVICE_ID_ANALOG_Y:
17662                            switch (desc->index)
17663                            {
17664                               case RETRO_DEVICE_INDEX_ANALOG_LEFT:
17665                                  system->input_desc_btn[retro_port]
17666                                     [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description;
17667                                  system->input_desc_btn[retro_port]
17668                                     [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description;
17669                                  break;
17670                               case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
17671                                  system->input_desc_btn[retro_port]
17672                                     [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description;
17673                                  system->input_desc_btn[retro_port]
17674                                     [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description;
17675                                  break;
17676                            }
17677                            break;
17678                      }
17679                      break;
17680                }
17681             }
17682 
17683             RARCH_LOG("[Environ]: SET_INPUT_DESCRIPTORS:\n");
17684 
17685             {
17686                unsigned log_level      = settings->uints.libretro_log_level;
17687 
17688                if (log_level == RETRO_LOG_DEBUG)
17689                {
17690                   unsigned input_driver_max_users =
17691                      p_rarch->input_driver_max_users;
17692                   for (p = 0; p < input_driver_max_users; p++)
17693                   {
17694                      unsigned mapped_port = settings->uints.input_remap_ports[p];
17695 
17696                      for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++)
17697                      {
17698                         const char *description = system->input_desc_btn[mapped_port][retro_id];
17699 
17700                         if (!description)
17701                            continue;
17702 
17703                         RARCH_LOG("\tRetroPad, Port %u, Button \"%s\" => \"%s\"\n",
17704                               p + 1, libretro_btn_desc[retro_id], description);
17705                      }
17706                   }
17707                }
17708             }
17709 
17710             p_rarch->current_core.has_set_input_descriptors = true;
17711          }
17712 
17713          break;
17714       }
17715 
17716       case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK:
17717       {
17718          const struct retro_keyboard_callback *info =
17719             (const struct retro_keyboard_callback*)data;
17720          retro_keyboard_event_t *frontend_key_event = &runloop_state.frontend_key_event;
17721          retro_keyboard_event_t *key_event          = &runloop_state.key_event;
17722 
17723          RARCH_LOG("[Environ]: SET_KEYBOARD_CALLBACK.\n");
17724          if (key_event)
17725             *key_event                  = info->callback;
17726 
17727          if (frontend_key_event && key_event)
17728             *frontend_key_event         = *key_event;
17729 
17730          /* If a core calls RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK,
17731           * then it is assumed that game focus mode is desired */
17732          p_rarch->game_focus_state.core_requested = true;
17733 
17734          break;
17735       }
17736 
17737       case RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION:
17738          RARCH_LOG("[Environ]: GET_DISK_CONTROL_INTERFACE_VERSION.\n");
17739          /* Current API version is 1 */
17740          *(unsigned *)data = 1;
17741          break;
17742 
17743       case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE:
17744          {
17745             const struct retro_disk_control_callback *control_cb =
17746                   (const struct retro_disk_control_callback*)data;
17747 
17748             if (system)
17749             {
17750                RARCH_LOG("[Environ]: SET_DISK_CONTROL_INTERFACE.\n");
17751                disk_control_set_callback(&system->disk_control, control_cb);
17752             }
17753          }
17754          break;
17755 
17756       case RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE:
17757          {
17758             const struct retro_disk_control_ext_callback *control_cb =
17759                   (const struct retro_disk_control_ext_callback*)data;
17760 
17761             if (system)
17762             {
17763                RARCH_LOG("[Environ]: SET_DISK_CONTROL_EXT_INTERFACE.\n");
17764                disk_control_set_ext_callback(&system->disk_control, control_cb);
17765             }
17766          }
17767          break;
17768 
17769       case RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER:
17770       {
17771          unsigned *cb = (unsigned*)data;
17772          settings_t *settings          = p_rarch->configuration_settings;
17773          const char *video_driver_name = settings->arrays.video_driver;
17774          bool driver_switch_enable     = settings->bools.driver_switch_enable;
17775 
17776          RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER, video driver name: %s.\n", video_driver_name);
17777 
17778          if (string_is_equal(video_driver_name, "glcore"))
17779          {
17780              *cb = RETRO_HW_CONTEXT_OPENGL_CORE;
17781              RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_OPENGL_CORE.\n");
17782          }
17783          else if (string_is_equal(video_driver_name, "gl"))
17784          {
17785              *cb = RETRO_HW_CONTEXT_OPENGL;
17786              RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_OPENGL.\n");
17787          }
17788          else if (string_is_equal(video_driver_name, "vulkan"))
17789          {
17790              *cb = RETRO_HW_CONTEXT_VULKAN;
17791              RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_VULKAN.\n");
17792          }
17793          else if (!strncmp(video_driver_name, "d3d", 3))
17794          {
17795              *cb = RETRO_HW_CONTEXT_DIRECT3D;
17796              RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_DIRECT3D.\n");
17797          }
17798          else
17799          {
17800              *cb = RETRO_HW_CONTEXT_NONE;
17801              RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_NONE.\n");
17802          }
17803 
17804          if (!driver_switch_enable)
17805          {
17806             RARCH_LOG("[Environ]: Driver switching disabled, GET_PREFERRED_HW_RENDER will be ignored.\n");
17807             return false;
17808          }
17809 
17810          break;
17811       }
17812 
17813       case RETRO_ENVIRONMENT_SET_HW_RENDER:
17814       case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL:
17815       {
17816          struct retro_hw_render_callback *cb =
17817             (struct retro_hw_render_callback*)data;
17818          struct retro_hw_render_callback *hwr =
17819             VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
17820 
17821          if (!cb)
17822          {
17823             RARCH_ERR("[Environ]: SET_HW_RENDER - No valid callback passed, returning...\n");
17824             return false;
17825          }
17826 
17827          RARCH_LOG("[Environ]: SET_HW_RENDER, context type: %s.\n", hw_render_context_name(cb->context_type, cb->version_major, cb->version_minor));
17828 
17829          if (!dynamic_request_hw_context(
17830                   cb->context_type, cb->version_minor, cb->version_major))
17831          {
17832             RARCH_ERR("[Environ]: SET_HW_RENDER - Dynamic request HW context failed.\n");
17833             return false;
17834          }
17835 
17836          if (!dynamic_verify_hw_context(p_rarch->configuration_settings->arrays.video_driver,
17837                                         p_rarch->configuration_settings->bools.driver_switch_enable,
17838                   cb->context_type, cb->version_minor, cb->version_major))
17839          {
17840             RARCH_ERR("[Environ]: SET_HW_RENDER: Dynamic verify HW context failed.\n");
17841             return false;
17842          }
17843 
17844 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
17845          /* TODO/FIXME - should check first if an OpenGL
17846           * driver is running */
17847          if (cb->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
17848          {
17849             /* Ensure that the rest of the frontend knows
17850              * we have a core context */
17851             gfx_ctx_flags_t flags;
17852             flags.flags = 0;
17853             BIT32_SET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
17854 
17855             video_context_driver_set_flags(&flags);
17856          }
17857 #endif
17858 
17859          cb->get_current_framebuffer = video_driver_get_current_framebuffer;
17860          cb->get_proc_address        = video_driver_get_proc_address;
17861 
17862          /* Old ABI. Don't copy garbage. */
17863          if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL)
17864          {
17865             memcpy(hwr,
17866                   cb, offsetof(struct retro_hw_render_callback, stencil));
17867             memset((uint8_t*)hwr + offsetof(struct retro_hw_render_callback, stencil),
17868                0, sizeof(*cb) - offsetof(struct retro_hw_render_callback, stencil));
17869          }
17870          else
17871             memcpy(hwr, cb, sizeof(*cb));
17872          RARCH_LOG("Reached end of SET_HW_RENDER.\n");
17873          break;
17874       }
17875 
17876       case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
17877       {
17878          bool state = *(const bool*)data;
17879          RARCH_LOG("[Environ]: SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no");
17880 
17881          if (state)
17882             content_set_does_not_need_content();
17883          else
17884             content_unset_does_not_need_content();
17885          break;
17886       }
17887 
17888       case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH:
17889       {
17890          const char **path = (const char**)data;
17891          RARCH_LOG("[Environ]: GET_LIBRETRO_PATH.\n");
17892 #ifdef HAVE_DYNAMIC
17893          *path = path_get(RARCH_PATH_CORE);
17894 #else
17895          *path = NULL;
17896 #endif
17897          break;
17898       }
17899 
17900       case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK:
17901 #ifdef HAVE_THREADS
17902       {
17903          const struct retro_audio_callback *cb = (const struct retro_audio_callback*)data;
17904          RARCH_LOG("[Environ]: SET_AUDIO_CALLBACK.\n");
17905 #ifdef HAVE_NETWORKING
17906          if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
17907             return false;
17908 #endif
17909          if (p_rarch->recording_data) /* A/V sync is a must. */
17910             return false;
17911          if (cb)
17912             p_rarch->audio_callback = *cb;
17913       }
17914       break;
17915 #else
17916       return false;
17917 #endif
17918 
17919       case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK:
17920       {
17921          const struct retro_frame_time_callback *info =
17922             (const struct retro_frame_time_callback*)data;
17923 
17924          RARCH_LOG("[Environ]: SET_FRAME_TIME_CALLBACK.\n");
17925 #ifdef HAVE_NETWORKING
17926          /* retro_run() will be called in very strange and
17927           * mysterious ways, have to disable it. */
17928          if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
17929             return false;
17930 #endif
17931          runloop_state.frame_time = *info;
17932          break;
17933       }
17934 
17935       case RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK:
17936       {
17937          const struct retro_audio_buffer_status_callback *info =
17938             (const struct retro_audio_buffer_status_callback*)data;
17939 
17940          RARCH_LOG("[Environ]: SET_AUDIO_BUFFER_STATUS_CALLBACK.\n");
17941 
17942          if (info)
17943             runloop_state.audio_buffer_status.callback = info->callback;
17944          else
17945             runloop_state.audio_buffer_status.callback = NULL;
17946 
17947          break;
17948       }
17949 
17950       case RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY:
17951       {
17952          unsigned audio_latency_default = settings->uints.audio_latency;
17953          unsigned audio_latency_current =
17954                (runloop_state.audio_latency > audio_latency_default) ?
17955                      runloop_state.audio_latency : audio_latency_default;
17956          unsigned audio_latency_new;
17957 
17958          RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY.\n");
17959 
17960          /* Sanitise input latency value */
17961          runloop_state.audio_latency    = 0;
17962          if (data)
17963             runloop_state.audio_latency = *(const unsigned*)data;
17964          if (runloop_state.audio_latency > 512)
17965          {
17966             RARCH_WARN("[Environ]: Requested audio latency of %u ms - limiting to maximum of 512 ms.\n",
17967                   runloop_state.audio_latency);
17968             runloop_state.audio_latency = 512;
17969          }
17970 
17971          /* Determine new set-point latency value */
17972          if (runloop_state.audio_latency >= audio_latency_default)
17973             audio_latency_new = runloop_state.audio_latency;
17974          else
17975          {
17976             if (runloop_state.audio_latency != 0)
17977                RARCH_WARN("[Environ]: Requested audio latency of %u ms is less than frontend default of %u ms."
17978                      " Using frontend default...\n",
17979                      runloop_state.audio_latency, audio_latency_default);
17980 
17981             audio_latency_new = audio_latency_default;
17982          }
17983 
17984          /* Check whether audio driver requires reinitialisation
17985           * (Identical to RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
17986           * without video driver initialisation) */
17987          if (audio_latency_new != audio_latency_current)
17988          {
17989             bool video_fullscreen = settings->bools.video_fullscreen;
17990             int reinit_flags      = DRIVERS_CMD_ALL &
17991                   ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK | DRIVER_MENU_MASK);
17992 
17993             RARCH_LOG("[Environ]: Setting audio latency to %u ms.\n", audio_latency_new);
17994 
17995             command_event(CMD_EVENT_REINIT, &reinit_flags);
17996             video_driver_set_aspect_ratio();
17997 
17998             /* Cannot continue recording with different parameters.
17999              * Take the easiest route out and just restart the recording. */
18000             if (p_rarch->recording_data)
18001             {
18002                runloop_msg_queue_push(
18003                      msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
18004                      2, 180, false,
18005                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
18006                command_event(CMD_EVENT_RECORD_DEINIT, NULL);
18007                command_event(CMD_EVENT_RECORD_INIT, NULL);
18008             }
18009 
18010             /* Hide mouse cursor in fullscreen mode */
18011             if (video_fullscreen)
18012                video_driver_hide_mouse();
18013          }
18014 
18015          break;
18016       }
18017 
18018       case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE:
18019       {
18020          struct retro_rumble_interface *iface =
18021             (struct retro_rumble_interface*)data;
18022 
18023          RARCH_LOG("[Environ]: GET_RUMBLE_INTERFACE.\n");
18024          iface->set_rumble_state = input_driver_set_rumble_state;
18025          break;
18026       }
18027 
18028       case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES:
18029       {
18030          uint64_t *mask = (uint64_t*)data;
18031 
18032          RARCH_LOG("[Environ]: GET_INPUT_DEVICE_CAPABILITIES.\n");
18033          if (!p_rarch->current_input->get_capabilities || !p_rarch->current_input_data)
18034             return false;
18035          *mask = input_driver_get_capabilities();
18036          break;
18037       }
18038 
18039       case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE:
18040       {
18041          settings_t *settings                 = p_rarch->configuration_settings;
18042          bool input_sensors_enable            = settings->bools.input_sensors_enable;
18043          struct retro_sensor_interface *iface = (struct retro_sensor_interface*)data;
18044 
18045          RARCH_LOG("[Environ]: GET_SENSOR_INTERFACE.\n");
18046 
18047          if (!input_sensors_enable)
18048             return false;
18049 
18050          iface->set_sensor_state = input_sensor_set_state;
18051          iface->get_sensor_input = input_sensor_get_input;
18052          break;
18053       }
18054       case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE:
18055       {
18056          struct retro_camera_callback *cb =
18057             (struct retro_camera_callback*)data;
18058 
18059          RARCH_LOG("[Environ]: GET_CAMERA_INTERFACE.\n");
18060          cb->start                        = driver_camera_start;
18061          cb->stop                         = driver_camera_stop;
18062 
18063          p_rarch->camera_cb               = *cb;
18064 
18065          if (cb->caps != 0)
18066             p_rarch->camera_driver_active = true;
18067          else
18068             p_rarch->camera_driver_active = false;
18069          break;
18070       }
18071 
18072       case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE:
18073       {
18074          struct retro_location_callback *cb =
18075             (struct retro_location_callback*)data;
18076 
18077          RARCH_LOG("[Environ]: GET_LOCATION_INTERFACE.\n");
18078          cb->start                       = driver_location_start;
18079          cb->stop                        = driver_location_stop;
18080          cb->get_position                = driver_location_get_position;
18081          cb->set_interval                = driver_location_set_interval;
18082 
18083          if (system)
18084             system->location_cb          = *cb;
18085 
18086          p_rarch->location_driver_active = false;
18087          break;
18088       }
18089 
18090       case RETRO_ENVIRONMENT_GET_LOG_INTERFACE:
18091       {
18092          struct retro_log_callback *cb = (struct retro_log_callback*)data;
18093 
18094          RARCH_LOG("[Environ]: GET_LOG_INTERFACE.\n");
18095          cb->log = rarch_log_libretro;
18096          break;
18097       }
18098 
18099       case RETRO_ENVIRONMENT_GET_PERF_INTERFACE:
18100       {
18101          struct retro_perf_callback *cb = (struct retro_perf_callback*)data;
18102 
18103          RARCH_LOG("[Environ]: GET_PERF_INTERFACE.\n");
18104          cb->get_time_usec    = cpu_features_get_time_usec;
18105          cb->get_cpu_features = cpu_features_get;
18106          cb->get_perf_counter = cpu_features_get_perf_counter;
18107 
18108          cb->perf_register    = performance_counter_register;
18109          cb->perf_start       = core_performance_counter_start;
18110          cb->perf_stop        = core_performance_counter_stop;
18111          cb->perf_log         = retro_perf_log;
18112          break;
18113       }
18114 
18115       case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY:
18116       {
18117          const char **dir            = (const char**)data;
18118          const char *dir_core_assets = settings->paths.directory_core_assets;
18119 
18120          *dir = *dir_core_assets ?
18121             dir_core_assets : NULL;
18122          RARCH_LOG("[Environ]: CORE_ASSETS_DIRECTORY: \"%s\".\n",
18123                dir_core_assets);
18124          break;
18125       }
18126 
18127       case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO:
18128       /**
18129        * Update the system Audio/Video information.
18130        * Will reinitialize audio/video drivers if needed.
18131        * Used by RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO.
18132        **/
18133       {
18134          const struct retro_system_av_info **info = (const struct retro_system_av_info**)&data;
18135          struct retro_system_av_info *av_info     = &p_rarch->video_driver_av_info;
18136          if (data)
18137          {
18138             settings_t *settings                  = p_rarch->configuration_settings;
18139             unsigned crt_switch_resolution        = settings->uints.crt_switch_resolution;
18140             bool video_fullscreen                 = settings->bools.video_fullscreen;
18141             const bool no_video_reinit            = (
18142                      crt_switch_resolution == 0
18143                   && data
18144                   && ((*info)->geometry.max_width  == av_info->geometry.max_width)
18145                   && ((*info)->geometry.max_height == av_info->geometry.max_height));
18146             /* When not doing video reinit, we also must not do input and menu
18147              * reinit, otherwise the input driver crashes and the menu gets
18148              * corrupted. */
18149             int reinit_flags = no_video_reinit ?
18150                     DRIVERS_CMD_ALL & ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK | DRIVER_MENU_MASK)
18151                   : DRIVERS_CMD_ALL;
18152 
18153             RARCH_LOG("[Environ]: SET_SYSTEM_AV_INFO: %ux%u, aspect: %.3f, fps: %.3f, sample rate: %.2f Hz.\n",
18154                   (*info)->geometry.base_width, (*info)->geometry.base_height,
18155                   (*info)->geometry.aspect_ratio,
18156                   (*info)->timing.fps,
18157                   (*info)->timing.sample_rate);
18158 
18159             memcpy(av_info, *info, sizeof(*av_info));
18160             command_event(CMD_EVENT_REINIT, &reinit_flags);
18161             if (no_video_reinit)
18162                video_driver_set_aspect_ratio();
18163 
18164             /* Cannot continue recording with different parameters.
18165              * Take the easiest route out and just restart the recording. */
18166             if (p_rarch->recording_data)
18167             {
18168                runloop_msg_queue_push(
18169                      msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
18170                      2, 180, false,
18171                      NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
18172                command_event(CMD_EVENT_RECORD_DEINIT, NULL);
18173                command_event(CMD_EVENT_RECORD_INIT, NULL);
18174             }
18175 
18176             /* Hide mouse cursor in fullscreen after
18177              * a RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO call. */
18178             if (video_fullscreen)
18179                video_driver_hide_mouse();
18180 
18181             return true;
18182          }
18183          return false;
18184       }
18185 
18186       case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
18187       {
18188          unsigned i;
18189          const struct retro_subsystem_info *info =
18190             (const struct retro_subsystem_info*)data;
18191          unsigned log_level   = settings->uints.libretro_log_level;
18192 
18193          if (log_level == RETRO_LOG_DEBUG)
18194             RARCH_LOG("[Environ]: SET_SUBSYSTEM_INFO.\n");
18195 
18196          for (i = 0; info[i].ident; i++)
18197          {
18198             unsigned j;
18199             if (log_level != RETRO_LOG_DEBUG)
18200                continue;
18201 
18202             RARCH_LOG("Special game type: %s\n  Ident: %s\n  ID: %u\n  Content:\n",
18203                   info[i].desc,
18204                   info[i].ident,
18205                   info[i].id
18206                   );
18207             for (j = 0; j < info[i].num_roms; j++)
18208             {
18209                RARCH_LOG("    %s (%s)\n",
18210                      info[i].roms[j].desc, info[i].roms[j].required ?
18211                      "required" : "optional");
18212             }
18213          }
18214 
18215          if (system)
18216          {
18217             struct retro_subsystem_info *info_ptr = NULL;
18218             free(system->subsystem.data);
18219             system->subsystem.data = NULL;
18220             system->subsystem.size = 0;
18221 
18222             info_ptr = (struct retro_subsystem_info*)
18223                malloc(i * sizeof(*info_ptr));
18224 
18225             if (!info_ptr)
18226                return false;
18227 
18228             system->subsystem.data = info_ptr;
18229 
18230             memcpy(system->subsystem.data, info,
18231                   i * sizeof(*system->subsystem.data));
18232             system->subsystem.size                   = i;
18233             p_rarch->current_core.has_set_subsystems = true;
18234          }
18235          break;
18236       }
18237 
18238       case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO:
18239       {
18240          unsigned i, j;
18241          const struct retro_controller_info *info =
18242             (const struct retro_controller_info*)data;
18243          unsigned log_level      = settings->uints.libretro_log_level;
18244 
18245          RARCH_LOG("[Environ]: SET_CONTROLLER_INFO.\n");
18246 
18247          for (i = 0; info[i].types; i++)
18248          {
18249             if (log_level != RETRO_LOG_DEBUG)
18250                continue;
18251 
18252             RARCH_LOG("Controller port: %u\n", i + 1);
18253             for (j = 0; j < info[i].num_types; j++)
18254                RARCH_LOG("   %s (ID: %u)\n", info[i].types[j].desc,
18255                      info[i].types[j].id);
18256          }
18257 
18258          if (system)
18259          {
18260             struct retro_controller_info *info_ptr = NULL;
18261 
18262             free(system->ports.data);
18263             system->ports.data = NULL;
18264             system->ports.size = 0;
18265 
18266             info_ptr = (struct retro_controller_info*)calloc(i, sizeof(*info_ptr));
18267             if (!info_ptr)
18268                return false;
18269 
18270             system->ports.data = info_ptr;
18271             memcpy(system->ports.data, info,
18272                   i * sizeof(*system->ports.data));
18273             system->ports.size = i;
18274          }
18275          break;
18276       }
18277 
18278       case RETRO_ENVIRONMENT_SET_MEMORY_MAPS:
18279       {
18280          if (system)
18281          {
18282             unsigned i;
18283             const struct retro_memory_map *mmaps        =
18284                (const struct retro_memory_map*)data;
18285             rarch_memory_descriptor_t *descriptors = NULL;
18286 
18287             RARCH_LOG("[Environ]: SET_MEMORY_MAPS.\n");
18288             free((void*)system->mmaps.descriptors);
18289             system->mmaps.descriptors     = 0;
18290             system->mmaps.num_descriptors = 0;
18291             descriptors = (rarch_memory_descriptor_t*)
18292                calloc(mmaps->num_descriptors,
18293                      sizeof(*descriptors));
18294 
18295             if (!descriptors)
18296                return false;
18297 
18298             system->mmaps.descriptors     = descriptors;
18299             system->mmaps.num_descriptors = mmaps->num_descriptors;
18300 
18301             for (i = 0; i < mmaps->num_descriptors; i++)
18302                system->mmaps.descriptors[i].core = mmaps->descriptors[i];
18303 
18304             mmap_preprocess_descriptors(descriptors, mmaps->num_descriptors);
18305 
18306             if (sizeof(void *) == 8)
18307                RARCH_LOG("   ndx flags  ptr              offset   start    select   disconn  len      addrspace\n");
18308             else
18309                RARCH_LOG("   ndx flags  ptr          offset   start    select   disconn  len      addrspace\n");
18310 
18311             for (i = 0; i < system->mmaps.num_descriptors; i++)
18312             {
18313                const rarch_memory_descriptor_t *desc =
18314                   &system->mmaps.descriptors[i];
18315                char flags[7];
18316 
18317                flags[0] = 'M';
18318                if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_8) == RETRO_MEMDESC_MINSIZE_8)
18319                   flags[1] = '8';
18320                else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_4) == RETRO_MEMDESC_MINSIZE_4)
18321                   flags[1] = '4';
18322                else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_2) == RETRO_MEMDESC_MINSIZE_2)
18323                   flags[1] = '2';
18324                else
18325                   flags[1] = '1';
18326 
18327                flags[2] = 'A';
18328                if ((desc->core.flags & RETRO_MEMDESC_ALIGN_8) == RETRO_MEMDESC_ALIGN_8)
18329                   flags[3] = '8';
18330                else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_4) == RETRO_MEMDESC_ALIGN_4)
18331                   flags[3] = '4';
18332                else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_2) == RETRO_MEMDESC_ALIGN_2)
18333                   flags[3] = '2';
18334                else
18335                   flags[3] = '1';
18336 
18337                flags[4] = (desc->core.flags & RETRO_MEMDESC_BIGENDIAN) ? 'B' : 'b';
18338                flags[5] = (desc->core.flags & RETRO_MEMDESC_CONST) ? 'C' : 'c';
18339                flags[6] = 0;
18340 
18341                RARCH_LOG("   %03u %s %p %08X %08X %08X %08X %08X %s\n",
18342                      i + 1, flags, desc->core.ptr, desc->core.offset, desc->core.start,
18343                      desc->core.select, desc->core.disconnect, desc->core.len,
18344                      desc->core.addrspace ? desc->core.addrspace : "");
18345             }
18346          }
18347          else
18348          {
18349             RARCH_WARN("[Environ]: SET_MEMORY_MAPS, but system pointer not initialized..\n");
18350          }
18351 
18352          break;
18353       }
18354 
18355       case RETRO_ENVIRONMENT_SET_GEOMETRY:
18356       {
18357          struct retro_system_av_info *av_info      = &p_rarch->video_driver_av_info;
18358          struct retro_game_geometry  *geom         = (struct retro_game_geometry*)&av_info->geometry;
18359          const struct retro_game_geometry *in_geom = (const struct retro_game_geometry*)data;
18360 
18361          if (!geom)
18362             return false;
18363 
18364          /* Can potentially be called every frame,
18365           * don't do anything unless required. */
18366          if (  (geom->base_width   != in_geom->base_width)  ||
18367                (geom->base_height  != in_geom->base_height) ||
18368                (geom->aspect_ratio != in_geom->aspect_ratio))
18369          {
18370             geom->base_width   = in_geom->base_width;
18371             geom->base_height  = in_geom->base_height;
18372             geom->aspect_ratio = in_geom->aspect_ratio;
18373 
18374             RARCH_LOG("[Environ]: SET_GEOMETRY: %ux%u, aspect: %.3f.\n",
18375                   geom->base_width, geom->base_height, geom->aspect_ratio);
18376 
18377             /* Forces recomputation of aspect ratios if
18378              * using core-dependent aspect ratios. */
18379             video_driver_set_aspect_ratio();
18380 
18381             /* TODO: Figure out what to do, if anything, with recording. */
18382          }
18383          else
18384          {
18385             RARCH_LOG("[Environ]: SET_GEOMETRY.\n");
18386          }
18387          break;
18388       }
18389 
18390       case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER:
18391       {
18392          struct retro_framebuffer *fb = (struct retro_framebuffer*)data;
18393          if (
18394                   p_rarch->video_driver_poke
18395                && p_rarch->video_driver_poke->get_current_software_framebuffer
18396                && p_rarch->video_driver_poke->get_current_software_framebuffer(
18397                   p_rarch->video_driver_data, fb))
18398             return true;
18399 
18400          return false;
18401       }
18402 
18403       case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE:
18404       {
18405          const struct retro_hw_render_interface **iface = (const struct retro_hw_render_interface **)data;
18406          if (
18407                   p_rarch->video_driver_poke
18408                && p_rarch->video_driver_poke->get_hw_render_interface
18409                && p_rarch->video_driver_poke->get_hw_render_interface(
18410                   p_rarch->video_driver_data, iface))
18411             return true;
18412 
18413          return false;
18414       }
18415 
18416       case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS:
18417 #ifdef HAVE_CHEEVOS
18418          {
18419             bool state = *(const bool*)data;
18420             RARCH_LOG("[Environ]: SET_SUPPORT_ACHIEVEMENTS: %s.\n", state ? "yes" : "no");
18421             rcheevos_set_support_cheevos(state);
18422          }
18423 #endif
18424          break;
18425 
18426       case RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE:
18427       {
18428          const struct retro_hw_render_context_negotiation_interface *iface =
18429             (const struct retro_hw_render_context_negotiation_interface*)data;
18430          RARCH_LOG("[Environ]: SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE.\n");
18431          p_rarch->hw_render_context_negotiation = iface;
18432          break;
18433       }
18434 
18435       case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS:
18436       {
18437          uint64_t *quirks = (uint64_t *) data;
18438          RARCH_LOG("[Environ]: SET_SERIALIZATION_QUIRKS.\n");
18439          p_rarch->current_core.serialization_quirks_v = *quirks;
18440          break;
18441       }
18442 
18443       case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT:
18444 #ifdef HAVE_LIBNX
18445          RARCH_LOG("[Environ]: SET_HW_SHARED_CONTEXT - ignored for now.\n");
18446          /* TODO/FIXME - Force this off for now for Switch
18447           * until shared HW context can work there */
18448          return false;
18449 #else
18450          RARCH_LOG("[Environ]: SET_HW_SHARED_CONTEXT.\n");
18451          p_rarch->core_set_shared_context = true;
18452 #endif
18453          break;
18454 
18455       case RETRO_ENVIRONMENT_GET_VFS_INTERFACE:
18456       {
18457          const uint32_t supported_vfs_version = 3;
18458          static struct retro_vfs_interface vfs_iface =
18459          {
18460             /* VFS API v1 */
18461             retro_vfs_file_get_path_impl,
18462             retro_vfs_file_open_impl,
18463             retro_vfs_file_close_impl,
18464             retro_vfs_file_size_impl,
18465             retro_vfs_file_tell_impl,
18466             retro_vfs_file_seek_impl,
18467             retro_vfs_file_read_impl,
18468             retro_vfs_file_write_impl,
18469             retro_vfs_file_flush_impl,
18470             retro_vfs_file_remove_impl,
18471             retro_vfs_file_rename_impl,
18472             /* VFS API v2 */
18473             retro_vfs_file_truncate_impl,
18474             /* VFS API v3 */
18475             retro_vfs_stat_impl,
18476             retro_vfs_mkdir_impl,
18477             retro_vfs_opendir_impl,
18478             retro_vfs_readdir_impl,
18479             retro_vfs_dirent_get_name_impl,
18480             retro_vfs_dirent_is_dir_impl,
18481             retro_vfs_closedir_impl
18482          };
18483 
18484          struct retro_vfs_interface_info *vfs_iface_info = (struct retro_vfs_interface_info *) data;
18485          if (vfs_iface_info->required_interface_version <= supported_vfs_version)
18486          {
18487             RARCH_LOG("Core requested VFS version >= v%d, providing v%d\n", vfs_iface_info->required_interface_version, supported_vfs_version);
18488             vfs_iface_info->required_interface_version = supported_vfs_version;
18489             vfs_iface_info->iface                      = &vfs_iface;
18490             system->supports_vfs = true;
18491          }
18492          else
18493          {
18494             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);
18495             return false;
18496          }
18497 
18498          break;
18499       }
18500 
18501       case RETRO_ENVIRONMENT_GET_LED_INTERFACE:
18502       {
18503          struct retro_led_interface *ledintf =
18504             (struct retro_led_interface *)data;
18505          if (ledintf)
18506             ledintf->set_led_state = led_driver_set_led;
18507       }
18508       break;
18509 
18510       case RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE:
18511       {
18512          int result = 0;
18513          if ( !p_rarch->audio_suspended &&
18514                p_rarch->audio_driver_active)
18515             result |= 2;
18516          if (p_rarch->video_driver_active
18517                && !(p_rarch->current_video->frame == video_null.frame))
18518             result |= 1;
18519 #ifdef HAVE_RUNAHEAD
18520          if (p_rarch->request_fast_savestate)
18521             result |= 4;
18522          if (p_rarch->hard_disable_audio)
18523             result |= 8;
18524 #endif
18525 #ifdef HAVE_NETWORKING
18526          if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_REPLAYING, NULL))
18527             result &= ~(1|2);
18528          if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
18529             result |= 4;
18530 #endif
18531          if (data)
18532          {
18533             int* result_p = (int*)data;
18534             *result_p = result;
18535          }
18536          break;
18537       }
18538 
18539       case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
18540       {
18541          struct retro_midi_interface *midi_interface =
18542                (struct retro_midi_interface *)data;
18543 
18544          if (midi_interface)
18545          {
18546             midi_interface->input_enabled  = midi_driver_input_enabled;
18547             midi_interface->output_enabled = midi_driver_output_enabled;
18548             midi_interface->read           = midi_driver_read;
18549             midi_interface->write          = midi_driver_write;
18550             midi_interface->flush          = midi_driver_flush;
18551          }
18552          break;
18553       }
18554 
18555       case RETRO_ENVIRONMENT_GET_FASTFORWARDING:
18556          *(bool *)data = runloop_state.fastmotion;
18557          break;
18558 
18559       case RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE:
18560       {
18561          struct retro_fastforwarding_override *fastforwarding_override =
18562                (struct retro_fastforwarding_override *)data;
18563 
18564          if (fastforwarding_override)
18565          {
18566             runloop_state_t *p_runloop                         = &runloop_state;
18567             bool frame_time_counter_reset_after_fastforwarding = settings ?
18568                   settings->bools.frame_time_counter_reset_after_fastforwarding : false;
18569             float fastforward_ratio_default                    = settings ?
18570                   settings->floats.fastforward_ratio : 0.0f;
18571             float fastforward_ratio_last                       =
18572                      (p_runloop->fastmotion_override.fastforward &&
18573                            (p_runloop->fastmotion_override.ratio >= 0.0f)) ?
18574                                  p_runloop->fastmotion_override.ratio :
18575                                        fastforward_ratio_default;
18576             float fastforward_ratio_current;
18577 
18578             memcpy(&p_runloop->fastmotion_override,
18579                   fastforwarding_override,
18580                   sizeof(p_runloop->fastmotion_override));
18581 
18582             /* Check if 'fastmotion' state has changed */
18583             if (p_runloop->fastmotion !=
18584                   p_runloop->fastmotion_override.fastforward)
18585             {
18586                p_runloop->fastmotion =
18587                      p_runloop->fastmotion_override.fastforward;
18588 
18589                if (p_runloop->fastmotion)
18590                   p_rarch->input_driver_nonblock_state = true;
18591                else
18592                {
18593                   p_rarch->input_driver_nonblock_state = false;
18594                   p_rarch->fastforward_after_frames    = 1;
18595                }
18596                driver_set_nonblock_state();
18597 
18598                /* Reset frame time counter when toggling
18599                 * fast-forward off, if required */
18600                if (!p_runloop->fastmotion &&
18601                    frame_time_counter_reset_after_fastforwarding)
18602                   p_rarch->video_driver_frame_time_count = 0;
18603 
18604                /* Ensure fast forward widget is disabled when
18605                 * toggling fast-forward off
18606                 * (required if RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
18607                 * is called during core de-initialisation) */
18608 #if defined(HAVE_GFX_WIDGETS)
18609                if (p_rarch->widgets_active && !p_runloop->fastmotion)
18610                   p_rarch->gfx_widgets_fast_forward = false;
18611 #endif
18612             }
18613 
18614             /* Update frame limit, if required */
18615             fastforward_ratio_current = (p_runloop->fastmotion_override.fastforward &&
18616                   (p_runloop->fastmotion_override.ratio >= 0.0f)) ?
18617                         p_runloop->fastmotion_override.ratio :
18618                               fastforward_ratio_default;
18619 
18620             if (fastforward_ratio_current != fastforward_ratio_last)
18621                retroarch_set_frame_limit(p_rarch, fastforward_ratio_current);
18622          }
18623 
18624          break;
18625       }
18626 
18627       case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS:
18628          /* Just falldown, the function will return true */
18629          break;
18630 
18631       case RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION:
18632          RARCH_LOG("[Environ]: GET_CORE_OPTIONS_VERSION.\n");
18633          /* Current API version is 1 */
18634          *(unsigned *)data = 1;
18635          break;
18636 
18637       case RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE:
18638       {
18639          /* Try to use the polled refresh rate first.  */
18640          float target_refresh_rate = video_driver_get_refresh_rate();
18641          float video_refresh_rate  = settings ? settings->floats.video_refresh_rate : 0.0;
18642 
18643          /* If the above function failed [possibly because it is not
18644           * implemented], use the refresh rate set in the config instead. */
18645          if (target_refresh_rate == 0.0f && video_refresh_rate != 0.0f)
18646             target_refresh_rate = video_refresh_rate;
18647 
18648          *(float *)data = target_refresh_rate;
18649          break;
18650       }
18651 
18652       case RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS:
18653          *(unsigned *)data = p_rarch->input_driver_max_users;
18654          break;
18655 
18656       /* Private environment callbacks.
18657        *
18658        * Should all be properly addressed in version 2.
18659        * */
18660 
18661       case RETRO_ENVIRONMENT_POLL_TYPE_OVERRIDE:
18662          {
18663             const unsigned *poll_type_data = (const unsigned*)data;
18664 
18665             if (poll_type_data)
18666                p_rarch->core_poll_type_override = (enum poll_type_override_t)*poll_type_data;
18667          }
18668          break;
18669 
18670       case RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB:
18671          *(retro_environment_t *)data = rarch_clear_all_thread_waits;
18672          break;
18673 
18674       case RETRO_ENVIRONMENT_SET_SAVE_STATE_IN_BACKGROUND:
18675          {
18676             bool state = *(const bool*)data;
18677             RARCH_LOG("[Environ]: SET_SAVE_STATE_IN_BACKGROUND: %s.\n", state ? "yes" : "no");
18678 
18679             set_save_state_in_background(state);
18680 
18681          }
18682          break;
18683 
18684       case RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE:
18685          {
18686             const struct retro_system_content_info_override *overrides =
18687                   (const struct retro_system_content_info_override *)data;
18688 
18689             RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE.\n");
18690 
18691             /* Passing NULL always results in 'success' - this
18692              * allows cores to test for frontend support of
18693              * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
18694              * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks */
18695             if (!overrides)
18696                return true;
18697 
18698             return content_file_override_set(overrides);
18699          }
18700          break;
18701 
18702       case RETRO_ENVIRONMENT_GET_GAME_INFO_EXT:
18703          {
18704             content_state_t *p_content                       =
18705                   content_state_get_ptr();
18706             const struct retro_game_info_ext **game_info_ext =
18707                   (const struct retro_game_info_ext **)data;
18708 
18709             RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_GET_GAME_INFO_EXT.\n");
18710 
18711             if (!game_info_ext)
18712                return false;
18713 
18714             if (p_content &&
18715                 p_content->content_list &&
18716                 p_content->content_list->game_info_ext)
18717                *game_info_ext = p_content->content_list->game_info_ext;
18718             else
18719             {
18720                RARCH_ERR("[Environ]: Failed to retrieve extended game info\n");
18721                *game_info_ext = NULL;
18722                return false;
18723             }
18724          }
18725          break;
18726 
18727       default:
18728          RARCH_LOG("[Environ]: UNSUPPORTED (#%u).\n", cmd);
18729          return false;
18730    }
18731 
18732    return true;
18733 }
18734 
18735 #ifdef HAVE_DYNAMIC
18736 /**
18737  * libretro_get_environment_info:
18738  * @func                         : Function pointer for get_environment_info.
18739  * @load_no_content              : If true, core should be able to auto-start
18740  *                                 without any content loaded.
18741  *
18742  * Sets environment callback in order to get statically known
18743  * information from it.
18744  *
18745  * Fetched via environment callbacks instead of
18746  * retro_get_system_info(), as this info is part of extensions.
18747  *
18748  * Should only be called once right after core load to
18749  * avoid overwriting the "real" environ callback.
18750  *
18751  * For statically linked cores, pass retro_set_environment as argument.
18752  */
libretro_get_environment_info(void (* func)(retro_environment_t),bool * load_no_content)18753 static void libretro_get_environment_info(
18754       void (*func)(retro_environment_t),
18755       bool *load_no_content)
18756 {
18757    struct rarch_state *p_rarch   = &rarch_st;
18758 
18759    p_rarch->load_no_content_hook = load_no_content;
18760 
18761    /* load_no_content gets set in this callback. */
18762    func(environ_cb_get_system_info);
18763 
18764    /* It's possible that we just set get_system_info callback
18765     * to the currently running core.
18766     *
18767     * Make sure we reset it to the actual environment callback.
18768     * Ignore any environment callbacks here in case we're running
18769     * on the non-current core. */
18770    p_rarch->ignore_environment_cb = true;
18771    func(rarch_environment_cb);
18772    p_rarch->ignore_environment_cb = false;
18773 }
18774 
load_dynamic_core(struct rarch_state * p_rarch,const char * path,char * buf,size_t size)18775 static dylib_t load_dynamic_core(
18776       struct rarch_state *p_rarch,
18777       const char *path, char *buf, size_t size)
18778 {
18779 #if defined(ANDROID)
18780    /* Can't resolve symlinks when dealing with cores
18781     * installed via play feature delivery, because the
18782     * source files have non-standard file names (which
18783     * will not be recognised by regular core handling
18784     * routines) */
18785    bool resolve_symlinks = !play_feature_delivery_enabled();
18786 #else
18787    bool resolve_symlinks = true;
18788 #endif
18789 
18790    /* Can't lookup symbols in itself on UWP */
18791 #if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
18792    if (dylib_proc(NULL, "retro_init"))
18793    {
18794       /* Try to verify that -lretro was not linked in from other modules
18795        * since loading it dynamically and with -l will fail hard. */
18796       RARCH_ERR("Serious problem. RetroArch wants to load libretro cores"
18797             " dynamically, but it is already linked.\n");
18798       RARCH_ERR("This could happen if other modules RetroArch depends on "
18799             "link against libretro directly.\n");
18800       RARCH_ERR("Proceeding could cause a crash. Aborting ...\n");
18801       retroarch_fail(p_rarch, 1, "init_libretro_symbols()");
18802    }
18803 #endif
18804 
18805    /* Need to use absolute path for this setting. It can be
18806     * saved to content history, and a relative path would
18807     * break in that scenario. */
18808    path_resolve_realpath(buf, size, resolve_symlinks);
18809    return dylib_load(path);
18810 }
18811 
libretro_get_system_info_lib(const char * path,struct retro_system_info * info,bool * load_no_content)18812 static dylib_t libretro_get_system_info_lib(const char *path,
18813       struct retro_system_info *info, bool *load_no_content)
18814 {
18815    dylib_t lib = dylib_load(path);
18816    void (*proc)(struct retro_system_info*);
18817 
18818    if (!lib)
18819       return NULL;
18820 
18821    proc = (void (*)(struct retro_system_info*))
18822       dylib_proc(lib, "retro_get_system_info");
18823 
18824    if (!proc)
18825    {
18826       dylib_close(lib);
18827       return NULL;
18828    }
18829 
18830    proc(info);
18831 
18832    if (load_no_content)
18833    {
18834       void (*set_environ)(retro_environment_t);
18835       *load_no_content = false;
18836       set_environ = (void (*)(retro_environment_t))
18837          dylib_proc(lib, "retro_set_environment");
18838 
18839       if (set_environ)
18840          libretro_get_environment_info(set_environ, load_no_content);
18841    }
18842 
18843    return lib;
18844 }
18845 #endif
18846 
18847 /**
18848  * libretro_get_system_info:
18849  * @path                         : Path to libretro library.
18850  * @info                         : Pointer to system info information.
18851  * @load_no_content              : If true, core should be able to auto-start
18852  *                                 without any content loaded.
18853  *
18854  * Gets system info from an arbitrary lib.
18855  * The struct returned must be freed as strings are allocated dynamically.
18856  *
18857  * Returns: true (1) if successful, otherwise false (0).
18858  **/
libretro_get_system_info(struct rarch_state * p_rarch,const char * path,struct retro_system_info * info,bool * load_no_content)18859 static bool libretro_get_system_info(
18860       struct rarch_state *p_rarch,
18861       const char *path,
18862       struct retro_system_info *info,
18863       bool *load_no_content)
18864 {
18865    struct retro_system_info dummy_info;
18866 #ifdef HAVE_DYNAMIC
18867    dylib_t lib;
18868 #endif
18869 
18870    if (string_ends_with_size(path,
18871             "builtin", strlen(path), STRLEN_CONST("builtin")))
18872       return false;
18873 
18874    dummy_info.library_name      = NULL;
18875    dummy_info.library_version   = NULL;
18876    dummy_info.valid_extensions  = NULL;
18877    dummy_info.need_fullpath     = false;
18878    dummy_info.block_extract     = false;
18879 
18880 #ifdef HAVE_DYNAMIC
18881    lib                         = libretro_get_system_info_lib(
18882          path, &dummy_info, load_no_content);
18883 
18884    if (!lib)
18885    {
18886       RARCH_ERR("%s: \"%s\"\n",
18887             msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
18888             path);
18889       RARCH_ERR("Error(s): %s\n", dylib_error());
18890       return false;
18891    }
18892 #else
18893    if (load_no_content)
18894    {
18895       p_rarch->load_no_content_hook = load_no_content;
18896 
18897       /* load_no_content gets set in this callback. */
18898       retro_set_environment(environ_cb_get_system_info);
18899 
18900       /* It's possible that we just set get_system_info callback
18901        * to the currently running core.
18902        *
18903        * Make sure we reset it to the actual environment callback.
18904        * Ignore any environment callbacks here in case we're running
18905        * on the non-current core. */
18906       p_rarch->ignore_environment_cb = true;
18907       retro_set_environment(rarch_environment_cb);
18908       p_rarch->ignore_environment_cb = false;
18909    }
18910 
18911    retro_get_system_info(&dummy_info);
18912 #endif
18913 
18914    memcpy(info, &dummy_info, sizeof(*info));
18915 
18916    p_rarch->current_library_name[0]    = '\0';
18917    p_rarch->current_library_version[0] = '\0';
18918    p_rarch->current_valid_extensions[0] = '\0';
18919 
18920    if (!string_is_empty(dummy_info.library_name))
18921       strlcpy(p_rarch->current_library_name,
18922             dummy_info.library_name, sizeof(p_rarch->current_library_name));
18923    if (!string_is_empty(dummy_info.library_version))
18924       strlcpy(p_rarch->current_library_version,
18925             dummy_info.library_version, sizeof(p_rarch->current_library_version));
18926    if (dummy_info.valid_extensions)
18927       strlcpy(p_rarch->current_valid_extensions,
18928             dummy_info.valid_extensions, sizeof(p_rarch->current_valid_extensions));
18929 
18930    info->library_name     = p_rarch->current_library_name;
18931    info->library_version  = p_rarch->current_library_version;
18932    info->valid_extensions = p_rarch->current_valid_extensions;
18933 
18934 #ifdef HAVE_DYNAMIC
18935    dylib_close(lib);
18936 #endif
18937    return true;
18938 }
18939 
18940 /**
18941  * load_symbols:
18942  * @type                        : Type of core to be loaded.
18943  *                                If CORE_TYPE_DUMMY, will
18944  *                                load dummy symbols.
18945  *
18946  * Setup libretro callback symbols. Returns true on success,
18947  * or false if symbols could not be loaded.
18948  **/
init_libretro_symbols_custom(struct rarch_state * p_rarch,enum rarch_core_type type,struct retro_core_t * current_core,const char * lib_path,void * _lib_handle_p)18949 static bool init_libretro_symbols_custom(
18950       struct rarch_state *p_rarch,
18951       enum rarch_core_type type,
18952       struct retro_core_t *current_core,
18953       const char *lib_path,
18954       void *_lib_handle_p)
18955 {
18956 #ifdef HAVE_DYNAMIC
18957    /* the library handle for use with the SYMBOL macro */
18958    dylib_t lib_handle_local;
18959 #endif
18960 
18961    switch (type)
18962    {
18963       case CORE_TYPE_PLAIN:
18964          {
18965 #ifdef HAVE_DYNAMIC
18966 #ifdef HAVE_RUNAHEAD
18967             dylib_t *lib_handle_p = (dylib_t*)_lib_handle_p;
18968             if (!lib_path || !lib_handle_p)
18969 #endif
18970             {
18971                const char *path = path_get(RARCH_PATH_CORE);
18972 
18973                if (string_is_empty(path))
18974                {
18975                   RARCH_ERR("[Core]: Frontend is built for dynamic libretro cores, but "
18976                         "path is not set. Cannot continue.\n");
18977                   retroarch_fail(p_rarch, 1, "init_libretro_symbols()");
18978                }
18979 
18980                RARCH_LOG("[Core]: Loading dynamic libretro core from: \"%s\"\n",
18981                      path);
18982 
18983                if (!(p_rarch->lib_handle = load_dynamic_core(
18984                            p_rarch,
18985                            path,
18986                            path_get_ptr(RARCH_PATH_CORE),
18987                            path_get_realsize(RARCH_PATH_CORE)
18988                            )))
18989                {
18990                   RARCH_ERR("%s: \"%s\"\nError(s): %s\n",
18991                         msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
18992                         path, dylib_error());
18993                   runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
18994                         1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
18995                   return false;
18996                }
18997                lib_handle_local = p_rarch->lib_handle;
18998             }
18999 #ifdef HAVE_RUNAHEAD
19000             else
19001             {
19002                /* for a secondary core, we already have a
19003                 * primary library loaded, so we can skip
19004                 * some checks and just load the library */
19005                retro_assert(lib_path != NULL && lib_handle_p != NULL);
19006                lib_handle_local = dylib_load(lib_path);
19007 
19008                if (!lib_handle_local)
19009                   return false;
19010                *lib_handle_p = lib_handle_local;
19011             }
19012 #endif
19013 #endif
19014 
19015             CORE_SYMBOLS(SYMBOL);
19016          }
19017          break;
19018       case CORE_TYPE_DUMMY:
19019          CORE_SYMBOLS(SYMBOL_DUMMY);
19020          break;
19021       case CORE_TYPE_FFMPEG:
19022 #ifdef HAVE_FFMPEG
19023          CORE_SYMBOLS(SYMBOL_FFMPEG);
19024 #endif
19025          break;
19026       case CORE_TYPE_MPV:
19027 #ifdef HAVE_MPV
19028          CORE_SYMBOLS(SYMBOL_MPV);
19029 #endif
19030          break;
19031       case CORE_TYPE_IMAGEVIEWER:
19032 #ifdef HAVE_IMAGEVIEWER
19033          CORE_SYMBOLS(SYMBOL_IMAGEVIEWER);
19034 #endif
19035          break;
19036       case CORE_TYPE_NETRETROPAD:
19037 #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
19038          CORE_SYMBOLS(SYMBOL_NETRETROPAD);
19039 #endif
19040          break;
19041       case CORE_TYPE_VIDEO_PROCESSOR:
19042 #if defined(HAVE_VIDEOPROCESSOR)
19043          CORE_SYMBOLS(SYMBOL_VIDEOPROCESSOR);
19044 #endif
19045          break;
19046       case CORE_TYPE_GONG:
19047 #ifdef HAVE_GONG
19048          CORE_SYMBOLS(SYMBOL_GONG);
19049 #endif
19050          break;
19051    }
19052 
19053    return true;
19054 }
19055 
19056 /**
19057  * init_libretro_symbols:
19058  * @type                        : Type of core to be loaded.
19059  *                                If CORE_TYPE_DUMMY, will
19060  *                                load dummy symbols.
19061  *
19062  * Initializes libretro symbols and
19063  * setups environment callback functions. Returns true on success,
19064  * or false if symbols could not be loaded.
19065  **/
init_libretro_symbols(struct rarch_state * p_rarch,enum rarch_core_type type,struct retro_core_t * current_core)19066 static bool init_libretro_symbols(
19067       struct rarch_state *p_rarch,
19068       enum rarch_core_type type,
19069       struct retro_core_t *current_core)
19070 {
19071    /* Load symbols */
19072    if (!init_libretro_symbols_custom(p_rarch,
19073             type, current_core, NULL, NULL))
19074       return false;
19075 
19076 #ifdef HAVE_RUNAHEAD
19077    /* remember last core type created, so creating a
19078     * secondary core will know what core type to use. */
19079    p_rarch->last_core_type = type;
19080 #endif
19081    return true;
19082 }
19083 
libretro_get_shared_context(void)19084 bool libretro_get_shared_context(void)
19085 {
19086    struct rarch_state *p_rarch  = &rarch_st;
19087    bool core_set_shared_context = p_rarch->core_set_shared_context;
19088    return core_set_shared_context;
19089 }
19090 
19091 /**
19092  * uninit_libretro_sym:
19093  *
19094  * Frees libretro core.
19095  *
19096  * Frees all core options,
19097  * associated state, and
19098  * unbind all libretro callback symbols.
19099  **/
uninit_libretro_symbols(struct rarch_state * p_rarch,struct retro_core_t * current_core)19100 static void uninit_libretro_symbols(
19101       struct rarch_state *p_rarch,
19102       struct retro_core_t *current_core)
19103 {
19104 #ifdef HAVE_DYNAMIC
19105    if (p_rarch->lib_handle)
19106       dylib_close(p_rarch->lib_handle);
19107    p_rarch->lib_handle = NULL;
19108 #endif
19109 
19110    memset(current_core, 0, sizeof(struct retro_core_t));
19111 
19112    p_rarch->core_set_shared_context   = false;
19113 
19114    if (runloop_state.core_options)
19115       retroarch_deinit_core_options(p_rarch,
19116             path_get(RARCH_PATH_CORE_OPTIONS));
19117    retroarch_system_info_free(p_rarch);
19118    retroarch_frame_time_free(p_rarch);
19119    retroarch_audio_buffer_status_free(p_rarch);
19120    retroarch_game_focus_free(p_rarch);
19121    retroarch_fastmotion_override_free(p_rarch, &runloop_state);
19122    p_rarch->camera_driver_active      = false;
19123    p_rarch->location_driver_active    = false;
19124 
19125    /* Core has finished utilising the input driver;
19126     * reset 'analog input requested' flags */
19127    memset(&p_rarch->input_driver_analog_requested, 0,
19128          sizeof(p_rarch->input_driver_analog_requested));
19129 
19130    /* Performance counters no longer valid. */
19131    p_rarch->perf_ptr_libretro  = 0;
19132    memset(p_rarch->perf_counters_libretro, 0,
19133          sizeof(p_rarch->perf_counters_libretro));
19134 }
19135 
19136 #if defined(HAVE_RUNAHEAD)
free_retro_ctx_load_content_info(struct retro_ctx_load_content_info * dest)19137 static void free_retro_ctx_load_content_info(struct
19138       retro_ctx_load_content_info *dest)
19139 {
19140    if (!dest)
19141       return;
19142 
19143    string_list_free((struct string_list*)dest->content);
19144    if (dest->info)
19145       free(dest->info);
19146 
19147    dest->info    = NULL;
19148    dest->content = NULL;
19149 }
19150 
clone_retro_game_info(const struct retro_game_info * src)19151 static struct retro_game_info* clone_retro_game_info(const
19152       struct retro_game_info *src)
19153 {
19154    struct retro_game_info *dest = (struct retro_game_info*)malloc(
19155          sizeof(struct retro_game_info));
19156 
19157    if (!dest)
19158       return NULL;
19159 
19160    /* content_file_init() guarantees that all
19161     * elements of the source retro_game_info
19162     * struct will persist for the lifetime of
19163     * the core. This means we do not have to
19164     * copy any data; pointer assignment is
19165     * sufficient */
19166    dest->path = src->path;
19167    dest->data = src->data;
19168    dest->size = src->size;
19169    dest->meta = src->meta;
19170 
19171    return dest;
19172 }
19173 
19174 static struct retro_ctx_load_content_info
clone_retro_ctx_load_content_info(const struct retro_ctx_load_content_info * src)19175 *clone_retro_ctx_load_content_info(
19176       const struct retro_ctx_load_content_info *src)
19177 {
19178    struct retro_ctx_load_content_info *dest = NULL;
19179    if (!src || src->special)
19180       return NULL;   /* refuse to deal with the Special field */
19181 
19182    dest          = (struct retro_ctx_load_content_info*)
19183       malloc(sizeof(*dest));
19184 
19185    if (!dest)
19186       return NULL;
19187 
19188    dest->info       = NULL;
19189    dest->content    = NULL;
19190    dest->special    = NULL;
19191 
19192    if (src->info)
19193       dest->info    = clone_retro_game_info(src->info);
19194    if (src->content)
19195       dest->content = string_list_clone(src->content);
19196 
19197    return dest;
19198 }
19199 
set_load_content_info(struct rarch_state * p_rarch,const retro_ctx_load_content_info_t * ctx)19200 static void set_load_content_info(
19201       struct rarch_state *p_rarch,
19202       const retro_ctx_load_content_info_t *ctx)
19203 {
19204    free_retro_ctx_load_content_info(p_rarch->load_content_info);
19205    free(p_rarch->load_content_info);
19206    p_rarch->load_content_info = clone_retro_ctx_load_content_info(ctx);
19207 }
19208 
19209 /* RUNAHEAD - SECONDARY CORE  */
19210 #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
strcat_alloc(char ** dst,const char * s)19211 static void strcat_alloc(char **dst, const char *s)
19212 {
19213    size_t len1;
19214    char *src          = *dst;
19215 
19216    if (!src)
19217    {
19218       if (s)
19219       {
19220          size_t   len = strlen(s);
19221          if (len != 0)
19222          {
19223             char *dst = (char*)malloc(len + 1);
19224             strcpy_literal(dst, s);
19225             src       = dst;
19226          }
19227          else
19228             src       = NULL;
19229       }
19230       else
19231          src          = (char*)calloc(1,1);
19232 
19233       *dst            = src;
19234       return;
19235    }
19236 
19237    if (!s)
19238       return;
19239 
19240    len1               = strlen(src);
19241 
19242    if (!(src = (char*)realloc(src, len1 + strlen(s) + 1)))
19243       return;
19244 
19245    *dst               = src;
19246    strcpy_literal(src + len1, s);
19247 }
19248 
secondary_core_destroy(struct rarch_state * p_rarch)19249 static void secondary_core_destroy(struct rarch_state *p_rarch)
19250 {
19251    if (!p_rarch || !p_rarch->secondary_lib_handle)
19252       return;
19253 
19254    /* unload game from core */
19255    if (p_rarch->secondary_core.retro_unload_game)
19256       p_rarch->secondary_core.retro_unload_game();
19257    p_rarch->core_poll_type_override = POLL_TYPE_OVERRIDE_DONTCARE;
19258 
19259    /* deinit */
19260    if (p_rarch->secondary_core.retro_deinit)
19261       p_rarch->secondary_core.retro_deinit();
19262    memset(&p_rarch->secondary_core, 0, sizeof(struct retro_core_t));
19263 
19264    dylib_close(p_rarch->secondary_lib_handle);
19265    p_rarch->secondary_lib_handle = NULL;
19266    filestream_delete(p_rarch->secondary_library_path);
19267    if (p_rarch->secondary_library_path)
19268       free(p_rarch->secondary_library_path);
19269    p_rarch->secondary_library_path = NULL;
19270 }
19271 
secondary_core_ensure_exists(struct rarch_state * p_rarch,settings_t * settings)19272 static bool secondary_core_ensure_exists(struct rarch_state *p_rarch,
19273       settings_t *settings)
19274 {
19275    if (!p_rarch->secondary_lib_handle)
19276       if (!secondary_core_create(p_rarch, settings))
19277          return false;
19278    return true;
19279 }
19280 
19281 #if defined(HAVE_RUNAHEAD) && defined(HAVE_DYNAMIC)
secondary_core_deserialize(struct rarch_state * p_rarch,settings_t * settings,const void * buffer,int size)19282 static bool secondary_core_deserialize(
19283       struct rarch_state *p_rarch,
19284       settings_t *settings,
19285       const void *buffer, int size)
19286 {
19287    if (secondary_core_ensure_exists(p_rarch, settings))
19288       return p_rarch->secondary_core.retro_unserialize(buffer, size);
19289    secondary_core_destroy(p_rarch);
19290    return false;
19291 }
19292 #endif
19293 
remember_controller_port_device(struct rarch_state * p_rarch,long port,long device)19294 static void remember_controller_port_device(
19295       struct rarch_state *p_rarch,
19296       long port, long device)
19297 {
19298    if (port >= 0 && port < MAX_USERS)
19299       p_rarch->port_map[port] = (int)device;
19300    if (     p_rarch->secondary_lib_handle
19301          && p_rarch->secondary_core.retro_set_controller_port_device)
19302       p_rarch->secondary_core.retro_set_controller_port_device((unsigned)port, (unsigned)device);
19303 }
19304 
clear_controller_port_map(struct rarch_state * p_rarch)19305 static void clear_controller_port_map(struct rarch_state *p_rarch)
19306 {
19307    unsigned port;
19308 
19309    for (port = 0; port < MAX_USERS; port++)
19310       p_rarch->port_map[port] = -1;
19311 }
19312 
get_temp_directory_alloc(const char * override_dir)19313 static char *get_temp_directory_alloc(const char *override_dir)
19314 {
19315    const char *src    = NULL;
19316    char *path         = NULL;
19317 #ifdef _WIN32
19318 #ifdef LEGACY_WIN32
19319    DWORD plen         = GetTempPath(0, NULL) + 1;
19320 
19321    if (!(path = (char*)malloc(plen * sizeof(char))))
19322       return NULL;
19323 
19324    path[plen - 1]     = 0;
19325    GetTempPath(plen, path);
19326 #else
19327    DWORD plen         = GetTempPathW(0, NULL) + 1;
19328    wchar_t *wide_str  = (wchar_t*)malloc(plen * sizeof(wchar_t));
19329 
19330    if (!wide_str)
19331       return NULL;
19332 
19333    wide_str[plen - 1] = 0;
19334    GetTempPathW(plen, wide_str);
19335 
19336    path               = utf16_to_utf8_string_alloc(wide_str);
19337    free(wide_str);
19338 #endif
19339 #else
19340 #if defined ANDROID
19341    src                = override_dir;
19342 #else
19343    {
19344       char *tmpdir    = getenv("TMPDIR");
19345       if (tmpdir)
19346          src          = tmpdir;
19347       else
19348          src          = "/tmp";
19349    }
19350 #endif
19351    if (src)
19352    {
19353       size_t   len    = strlen(src);
19354       if (len != 0)
19355       {
19356          char *dst    = (char*)malloc(len + 1);
19357          strcpy_literal(dst, src);
19358          path         = dst;
19359       }
19360    }
19361    else
19362       path            = (char*)calloc(1,1);
19363 #endif
19364    return path;
19365 }
19366 
write_file_with_random_name(char ** temp_dll_path,const char * retroarch_tmp_path,const void * data,ssize_t dataSize)19367 static bool write_file_with_random_name(char **temp_dll_path,
19368       const char *retroarch_tmp_path, const void* data, ssize_t dataSize)
19369 {
19370    int ext_len;
19371    unsigned i;
19372    char number_buf[32];
19373    bool okay                = false;
19374    const char *prefix       = "tmp";
19375    char *ext                = NULL;
19376    time_t time_value        = time(NULL);
19377    unsigned _number_value   = (unsigned)time_value;
19378    const char *src          = path_get_extension(*temp_dll_path);
19379 
19380    if (src)
19381    {
19382       size_t   len          = strlen(src);
19383       if (len != 0)
19384       {
19385          char *dst          = (char*)malloc(len + 1);
19386          strcpy_literal(dst, src);
19387          ext                = dst;
19388       }
19389    }
19390    else
19391       ext                   = (char*)calloc(1,1);
19392 
19393    ext_len                  = (int)strlen(ext);
19394 
19395    if (ext_len > 0)
19396    {
19397       strcat_alloc(&ext, ".");
19398       memmove(ext + 1, ext, ext_len);
19399       ext[0] = '.';
19400       ext_len++;
19401    }
19402 
19403    /* Try up to 30 'random' filenames before giving up */
19404    for (i = 0; i < 30; i++)
19405    {
19406       int number_value = _number_value * 214013 + 2531011;
19407       int number       = (number_value >> 14) % 100000;
19408 
19409       snprintf(number_buf, sizeof(number_buf), "%05d", number);
19410 
19411       if (*temp_dll_path)
19412          free(*temp_dll_path);
19413       *temp_dll_path = NULL;
19414 
19415       strcat_alloc(temp_dll_path, retroarch_tmp_path);
19416       strcat_alloc(temp_dll_path, PATH_DEFAULT_SLASH());
19417       strcat_alloc(temp_dll_path, prefix);
19418       strcat_alloc(temp_dll_path, number_buf);
19419       strcat_alloc(temp_dll_path, ext);
19420 
19421       if (filestream_write_file(*temp_dll_path, data, dataSize))
19422       {
19423          okay = true;
19424          break;
19425       }
19426    }
19427 
19428    if (ext)
19429       free(ext);
19430    ext = NULL;
19431    return okay;
19432 }
19433 
copy_core_to_temp_file(struct rarch_state * p_rarch,const char * dir_libretro)19434 static char *copy_core_to_temp_file(struct rarch_state *p_rarch,
19435       const char *dir_libretro)
19436 {
19437    char retroarch_tmp_path[PATH_MAX_LENGTH];
19438    bool  failed                = false;
19439    char  *tmp_directory        = NULL;
19440    char  *tmp_dll_path         = NULL;
19441    void  *dll_file_data        = NULL;
19442    int64_t  dll_file_size      = 0;
19443    const char  *core_path      = path_get(RARCH_PATH_CORE);
19444    const char  *core_base_name = path_basename_nocompression(core_path);
19445 
19446    if (strlen(core_base_name) == 0)
19447       return NULL;
19448 
19449    tmp_directory               = get_temp_directory_alloc(dir_libretro);
19450    if (!tmp_directory)
19451       return NULL;
19452 
19453    retroarch_tmp_path[0]       = '\0';
19454    fill_pathname_join(retroarch_tmp_path,
19455          tmp_directory, "retroarch_temp",
19456          sizeof(retroarch_tmp_path));
19457 
19458    if (!path_mkdir(retroarch_tmp_path))
19459    {
19460       failed = true;
19461       goto end;
19462    }
19463 
19464    if (!filestream_read_file(core_path, &dll_file_data, &dll_file_size))
19465    {
19466       failed = true;
19467       goto end;
19468    }
19469 
19470    strcat_alloc(&tmp_dll_path, retroarch_tmp_path);
19471    strcat_alloc(&tmp_dll_path, PATH_DEFAULT_SLASH());
19472    strcat_alloc(&tmp_dll_path, core_base_name);
19473 
19474    if (!filestream_write_file(tmp_dll_path, dll_file_data, dll_file_size))
19475    {
19476       /* try other file names */
19477       if (!write_file_with_random_name(&tmp_dll_path,
19478                retroarch_tmp_path, dll_file_data, dll_file_size))
19479          failed = true;
19480    }
19481 
19482 end:
19483    if (tmp_directory)
19484       free(tmp_directory);
19485    if (dll_file_data)
19486       free(dll_file_data);
19487 
19488    tmp_directory       = NULL;
19489    dll_file_data       = NULL;
19490 
19491    if (!failed)
19492       return tmp_dll_path;
19493 
19494    if (tmp_dll_path)
19495       free(tmp_dll_path);
19496 
19497    tmp_dll_path     = NULL;
19498 
19499    return NULL;
19500 }
19501 
rarch_environment_secondary_core_hook(unsigned cmd,void * data)19502 static bool rarch_environment_secondary_core_hook(
19503       unsigned cmd, void *data)
19504 {
19505    struct rarch_state *p_rarch = &rarch_st;
19506    bool                 result = rarch_environment_cb(cmd, data);
19507 
19508    if (p_rarch->has_variable_update)
19509    {
19510       if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE)
19511       {
19512          bool *bool_p                 = (bool*)data;
19513          *bool_p                      = true;
19514          p_rarch->has_variable_update = false;
19515          return true;
19516       }
19517       else if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE)
19518          p_rarch->has_variable_update = false;
19519    }
19520    return result;
19521 }
19522 
secondary_core_create(struct rarch_state * p_rarch,settings_t * settings)19523 static bool secondary_core_create(struct rarch_state *p_rarch,
19524       settings_t *settings)
19525 {
19526    unsigned port;
19527    bool contentless            = false;
19528    bool is_inited              = false;
19529    const enum rarch_core_type
19530       last_core_type           = p_rarch->last_core_type;
19531    rarch_system_info_t *info   = &runloop_state.system;
19532    unsigned num_active_users   = p_rarch->input_driver_max_users;
19533 
19534    if (   last_core_type != CORE_TYPE_PLAIN          ||
19535          !p_rarch->load_content_info                 ||
19536           p_rarch->load_content_info->special)
19537       return false;
19538 
19539    if (p_rarch->secondary_library_path)
19540       free(p_rarch->secondary_library_path);
19541    p_rarch->secondary_library_path = NULL;
19542    p_rarch->secondary_library_path = copy_core_to_temp_file(p_rarch,
19543          settings->paths.directory_libretro);
19544 
19545    if (!p_rarch->secondary_library_path)
19546       return false;
19547 
19548    /* Load Core */
19549    if (!init_libretro_symbols_custom(p_rarch,
19550             CORE_TYPE_PLAIN, &p_rarch->secondary_core,
19551             p_rarch->secondary_library_path,
19552             &p_rarch->secondary_lib_handle))
19553       return false;
19554 
19555    p_rarch->secondary_core.symbols_inited = true;
19556    p_rarch->secondary_core.retro_set_environment(
19557          rarch_environment_secondary_core_hook);
19558 #ifdef HAVE_RUNAHEAD
19559    p_rarch->has_variable_update  = true;
19560 #endif
19561 
19562    p_rarch->secondary_core.retro_init();
19563 
19564    content_get_status(&contentless, &is_inited);
19565    p_rarch->secondary_core.inited = is_inited;
19566 
19567    /* Load Content */
19568    /* disabled due to crashes */
19569    if ( !p_rarch->load_content_info ||
19570          p_rarch->load_content_info->special)
19571       return false;
19572 
19573    if ( (p_rarch->load_content_info->content->size > 0) &&
19574          p_rarch->load_content_info->content->elems[0].data)
19575    {
19576       p_rarch->secondary_core.game_loaded = p_rarch->secondary_core.retro_load_game(
19577             p_rarch->load_content_info->info);
19578       if (!p_rarch->secondary_core.game_loaded)
19579          goto error;
19580    }
19581    else if (contentless)
19582    {
19583       p_rarch->secondary_core.game_loaded = p_rarch->secondary_core.retro_load_game(NULL);
19584       if (!p_rarch->secondary_core.game_loaded)
19585          goto error;
19586    }
19587    else
19588       p_rarch->secondary_core.game_loaded = false;
19589 
19590    if (!p_rarch->secondary_core.inited)
19591       goto error;
19592 
19593    core_set_default_callbacks(&p_rarch->secondary_callbacks);
19594    p_rarch->secondary_core.retro_set_video_refresh(p_rarch->secondary_callbacks.frame_cb);
19595    p_rarch->secondary_core.retro_set_audio_sample(p_rarch->secondary_callbacks.sample_cb);
19596    p_rarch->secondary_core.retro_set_audio_sample_batch(p_rarch->secondary_callbacks.sample_batch_cb);
19597    p_rarch->secondary_core.retro_set_input_state(p_rarch->secondary_callbacks.state_cb);
19598    p_rarch->secondary_core.retro_set_input_poll(p_rarch->secondary_callbacks.poll_cb);
19599 
19600    if (info)
19601       for (port = 0; port < MAX_USERS; port++)
19602       {
19603          if (port < info->ports.size)
19604          {
19605             unsigned device = (port < num_active_users) ?
19606                   p_rarch->port_map[port] : RETRO_DEVICE_NONE;
19607 
19608             p_rarch->secondary_core.retro_set_controller_port_device(
19609                   port, device);
19610          }
19611       }
19612 
19613    clear_controller_port_map(p_rarch);
19614 
19615    return true;
19616 
19617 error:
19618    secondary_core_destroy(p_rarch);
19619    return false;
19620 }
19621 
secondary_core_input_poll_null(void)19622 static void secondary_core_input_poll_null(void) { }
19623 
secondary_core_run_use_last_input(struct rarch_state * p_rarch)19624 static bool secondary_core_run_use_last_input(struct rarch_state *p_rarch)
19625 {
19626    retro_input_poll_t old_poll_function;
19627    retro_input_state_t old_input_function;
19628 
19629    if (!secondary_core_ensure_exists(p_rarch, p_rarch->configuration_settings))
19630    {
19631       secondary_core_destroy(p_rarch);
19632       return false;
19633    }
19634 
19635    old_poll_function                     = p_rarch->secondary_callbacks.poll_cb;
19636    old_input_function                    = p_rarch->secondary_callbacks.state_cb;
19637 
19638    p_rarch->secondary_callbacks.poll_cb  = secondary_core_input_poll_null;
19639    p_rarch->secondary_callbacks.state_cb = input_state_get_last;
19640 
19641    p_rarch->secondary_core.retro_set_input_poll(p_rarch->secondary_callbacks.poll_cb);
19642    p_rarch->secondary_core.retro_set_input_state(p_rarch->secondary_callbacks.state_cb);
19643 
19644    p_rarch->secondary_core.retro_run();
19645 
19646    p_rarch->secondary_callbacks.poll_cb  = old_poll_function;
19647    p_rarch->secondary_callbacks.state_cb = old_input_function;
19648 
19649    p_rarch->secondary_core.retro_set_input_poll(p_rarch->secondary_callbacks.poll_cb);
19650    p_rarch->secondary_core.retro_set_input_state(p_rarch->secondary_callbacks.state_cb);
19651 
19652    return true;
19653 }
19654 #else
secondary_core_destroy(struct rarch_state * p_rarch)19655 static void secondary_core_destroy(struct rarch_state *p_rarch) { }
remember_controller_port_device(struct rarch_state * p_rarch,long port,long device)19656 static void remember_controller_port_device(
19657       struct rarch_state *p_rarch,
19658       long port, long device) { }
clear_controller_port_map(struct rarch_state * p_rarch)19659 static void clear_controller_port_map(struct rarch_state *p_rarch) { }
19660 #endif
19661 
19662 #endif
19663 
19664 /* BLUETOOTH DRIVER  */
19665 
19666 /**
19667  * config_get_bluetooth_driver_options:
19668  *
19669  * Get an enumerated list of all bluetooth driver names,
19670  * separated by '|'.
19671  *
19672  * Returns: string listing of all bluetooth driver names,
19673  * separated by '|'.
19674  **/
config_get_bluetooth_driver_options(void)19675 const char* config_get_bluetooth_driver_options(void)
19676 {
19677    return char_list_new_special(STRING_LIST_BLUETOOTH_DRIVERS, NULL);
19678 }
19679 
driver_bluetooth_scan(void)19680 void driver_bluetooth_scan(void)
19681 {
19682    struct rarch_state       *p_rarch = &rarch_st;
19683    if ( (p_rarch->bluetooth_driver_active) &&
19684         (p_rarch->bluetooth_driver->scan) )
19685       p_rarch->bluetooth_driver->scan(p_rarch->bluetooth_data);
19686 }
19687 
driver_bluetooth_get_devices(struct string_list * devices)19688 void driver_bluetooth_get_devices(struct string_list* devices)
19689 {
19690    struct rarch_state       *p_rarch = &rarch_st;
19691    if ( (p_rarch->bluetooth_driver_active) &&
19692         (p_rarch->bluetooth_driver->get_devices) )
19693       p_rarch->bluetooth_driver->get_devices(p_rarch->bluetooth_data, devices);
19694 }
19695 
driver_bluetooth_device_is_connected(unsigned i)19696 bool driver_bluetooth_device_is_connected(unsigned i)
19697 {
19698    struct rarch_state       *p_rarch = &rarch_st;
19699    if ( (p_rarch->bluetooth_driver_active) &&
19700         (p_rarch->bluetooth_driver->device_is_connected) )
19701       return p_rarch->bluetooth_driver->device_is_connected(p_rarch->bluetooth_data, i);
19702    return false;
19703 }
19704 
driver_bluetooth_device_get_sublabel(char * s,unsigned i,size_t len)19705 void driver_bluetooth_device_get_sublabel(char *s, unsigned i, size_t len)
19706 {
19707    struct rarch_state       *p_rarch = &rarch_st;
19708    if ( (p_rarch->bluetooth_driver_active) &&
19709         (p_rarch->bluetooth_driver->device_get_sublabel) )
19710       p_rarch->bluetooth_driver->device_get_sublabel(p_rarch->bluetooth_data, s, i, len);
19711 }
19712 
driver_bluetooth_connect_device(unsigned i)19713 bool driver_bluetooth_connect_device(unsigned i)
19714 {
19715    struct rarch_state       *p_rarch = &rarch_st;
19716    if (p_rarch->bluetooth_driver_active)
19717       return p_rarch->bluetooth_driver->connect_device(p_rarch->bluetooth_data, i);
19718    return false;
19719 }
19720 
bluetooth_driver_ctl(enum rarch_bluetooth_ctl_state state,void * data)19721 bool bluetooth_driver_ctl(enum rarch_bluetooth_ctl_state state, void *data)
19722 {
19723    struct rarch_state     *p_rarch  = &rarch_st;
19724    settings_t             *settings = p_rarch->configuration_settings;
19725 
19726    switch (state)
19727    {
19728       case RARCH_BLUETOOTH_CTL_DESTROY:
19729          p_rarch->bluetooth_driver          = NULL;
19730          p_rarch->bluetooth_data            = NULL;
19731          p_rarch->bluetooth_driver_active   = false;
19732          break;
19733       case RARCH_BLUETOOTH_CTL_FIND_DRIVER:
19734          {
19735             const char *prefix   = "bluetooth driver";
19736             int i                = (int)driver_find_index(
19737                   "bluetooth_driver",
19738                   settings->arrays.bluetooth_driver);
19739 
19740             if (i >= 0)
19741                p_rarch->bluetooth_driver = (const bluetooth_driver_t*)bluetooth_drivers[i];
19742             else
19743             {
19744                if (verbosity_is_enabled())
19745                {
19746                   unsigned d;
19747                   RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
19748                         settings->arrays.bluetooth_driver);
19749                   RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
19750                   for (d = 0; bluetooth_drivers[d]; d++)
19751                      RARCH_LOG_OUTPUT("\t%s\n", bluetooth_drivers[d]->ident);
19752 
19753                   RARCH_WARN("Going to default to first %s...\n", prefix);
19754                }
19755 
19756                p_rarch->bluetooth_driver = (const bluetooth_driver_t*)bluetooth_drivers[0];
19757 
19758                if (!p_rarch->bluetooth_driver)
19759                   retroarch_fail(p_rarch, 1, "find_bluetooth_driver()");
19760             }
19761          }
19762          break;
19763       case RARCH_BLUETOOTH_CTL_DEINIT:
19764         if (p_rarch->bluetooth_data && p_rarch->bluetooth_driver)
19765         {
19766            if (p_rarch->bluetooth_driver->free)
19767               p_rarch->bluetooth_driver->free(p_rarch->bluetooth_data);
19768         }
19769 
19770         p_rarch->bluetooth_data = NULL;
19771         p_rarch->bluetooth_driver_active = false;
19772         break;
19773       case RARCH_BLUETOOTH_CTL_INIT:
19774         /* Resource leaks will follow if bluetooth is initialized twice. */
19775         if (p_rarch->bluetooth_data)
19776            return false;
19777 
19778         bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_FIND_DRIVER, NULL);
19779 
19780         if (p_rarch->bluetooth_driver && p_rarch->bluetooth_driver->init)
19781         {
19782            p_rarch->bluetooth_driver_active = true;
19783            p_rarch->bluetooth_data = p_rarch->bluetooth_driver->init();
19784 
19785            if (!p_rarch->bluetooth_data)
19786            {
19787               RARCH_ERR("Failed to initialize bluetooth driver. Will continue without bluetooth.\n");
19788               p_rarch->bluetooth_driver_active = false;
19789            }
19790         } else {
19791            p_rarch->bluetooth_driver_active = false;
19792         }
19793 
19794         break;
19795       default:
19796          break;
19797    }
19798 
19799    return false;
19800 }
19801 
19802 /* WIFI DRIVER  */
19803 
19804 /**
19805  * config_get_wifi_driver_options:
19806  *
19807  * Get an enumerated list of all wifi driver names,
19808  * separated by '|'.
19809  *
19810  * Returns: string listing of all wifi driver names,
19811  * separated by '|'.
19812  **/
config_get_wifi_driver_options(void)19813 const char* config_get_wifi_driver_options(void)
19814 {
19815    return char_list_new_special(STRING_LIST_WIFI_DRIVERS, NULL);
19816 }
19817 
driver_wifi_scan(void)19818 void driver_wifi_scan(void)
19819 {
19820    struct rarch_state       *p_rarch = &rarch_st;
19821    p_rarch->wifi_driver->scan(p_rarch->wifi_data);
19822 }
19823 
driver_wifi_enable(bool enabled)19824 bool driver_wifi_enable(bool enabled)
19825 {
19826    struct rarch_state       *p_rarch = &rarch_st;
19827    return p_rarch->wifi_driver->enable(p_rarch->wifi_data, enabled);
19828 }
19829 
driver_wifi_connection_info(wifi_network_info_t * netinfo)19830 bool driver_wifi_connection_info(wifi_network_info_t *netinfo)
19831 {
19832    struct rarch_state       *p_rarch = &rarch_st;
19833    return p_rarch->wifi_driver->connection_info(p_rarch->wifi_data, netinfo);
19834 }
19835 
driver_wifi_get_ssids()19836 wifi_network_scan_t* driver_wifi_get_ssids()
19837 {
19838    struct rarch_state       *p_rarch = &rarch_st;
19839    return p_rarch->wifi_driver->get_ssids(p_rarch->wifi_data);
19840 }
19841 
driver_wifi_ssid_is_online(unsigned i)19842 bool driver_wifi_ssid_is_online(unsigned i)
19843 {
19844    struct rarch_state       *p_rarch = &rarch_st;
19845    return p_rarch->wifi_driver->ssid_is_online(p_rarch->wifi_data, i);
19846 }
19847 
driver_wifi_connect_ssid(const wifi_network_info_t * net)19848 bool driver_wifi_connect_ssid(const wifi_network_info_t* net)
19849 {
19850    struct rarch_state       *p_rarch = &rarch_st;
19851    return p_rarch->wifi_driver->connect_ssid(p_rarch->wifi_data, net);
19852 }
19853 
driver_wifi_disconnect_ssid(const wifi_network_info_t * net)19854 bool driver_wifi_disconnect_ssid(const wifi_network_info_t* net)
19855 {
19856    struct rarch_state       *p_rarch = &rarch_st;
19857    return p_rarch->wifi_driver->disconnect_ssid(p_rarch->wifi_data, net);
19858 }
19859 
driver_wifi_tether_start_stop(bool start,char * configfile)19860 void driver_wifi_tether_start_stop(bool start, char* configfile)
19861 {
19862    struct rarch_state       *p_rarch = &rarch_st;
19863    p_rarch->wifi_driver->tether_start_stop(p_rarch->wifi_data, start, configfile);
19864 }
19865 
wifi_driver_ctl(enum rarch_wifi_ctl_state state,void * data)19866 bool wifi_driver_ctl(enum rarch_wifi_ctl_state state, void *data)
19867 {
19868    struct rarch_state     *p_rarch  = &rarch_st;
19869    settings_t             *settings = p_rarch->configuration_settings;
19870 
19871    switch (state)
19872    {
19873       case RARCH_WIFI_CTL_DESTROY:
19874          p_rarch->wifi_driver_active   = false;
19875          p_rarch->wifi_driver          = NULL;
19876          p_rarch->wifi_data            = NULL;
19877          break;
19878       case RARCH_WIFI_CTL_SET_ACTIVE:
19879          p_rarch->wifi_driver_active   = true;
19880          break;
19881       case RARCH_WIFI_CTL_FIND_DRIVER:
19882          {
19883             const char *prefix   = "wifi driver";
19884             int i                = (int)driver_find_index(
19885                   "wifi_driver",
19886                   settings->arrays.wifi_driver);
19887 
19888             if (i >= 0)
19889                p_rarch->wifi_driver = (const wifi_driver_t*)wifi_drivers[i];
19890             else
19891             {
19892                if (verbosity_is_enabled())
19893                {
19894                   unsigned d;
19895                   RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
19896                         settings->arrays.wifi_driver);
19897                   RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
19898                   for (d = 0; wifi_drivers[d]; d++)
19899                      RARCH_LOG_OUTPUT("\t%s\n", wifi_drivers[d]->ident);
19900 
19901                   RARCH_WARN("Going to default to first %s...\n", prefix);
19902                }
19903 
19904                p_rarch->wifi_driver = (const wifi_driver_t*)wifi_drivers[0];
19905 
19906                if (!p_rarch->wifi_driver)
19907                   retroarch_fail(p_rarch, 1, "find_wifi_driver()");
19908             }
19909          }
19910          break;
19911       case RARCH_WIFI_CTL_UNSET_ACTIVE:
19912          p_rarch->wifi_driver_active = false;
19913          break;
19914       case RARCH_WIFI_CTL_IS_ACTIVE:
19915         return p_rarch->wifi_driver_active;
19916       case RARCH_WIFI_CTL_DEINIT:
19917         if (p_rarch->wifi_data && p_rarch->wifi_driver)
19918         {
19919            if (p_rarch->wifi_driver->free)
19920               p_rarch->wifi_driver->free(p_rarch->wifi_data);
19921         }
19922 
19923         p_rarch->wifi_data = NULL;
19924         break;
19925       case RARCH_WIFI_CTL_STOP:
19926         if (     p_rarch->wifi_driver
19927               && p_rarch->wifi_driver->stop
19928               && p_rarch->wifi_data)
19929            p_rarch->wifi_driver->stop(p_rarch->wifi_data);
19930         break;
19931       case RARCH_WIFI_CTL_START:
19932         if (     p_rarch->wifi_driver
19933               && p_rarch->wifi_data
19934               && p_rarch->wifi_driver->start)
19935         {
19936            bool wifi_allow      = settings->bools.wifi_allow;
19937            if (wifi_allow)
19938               return p_rarch->wifi_driver->start(p_rarch->wifi_data);
19939         }
19940         return false;
19941       case RARCH_WIFI_CTL_INIT:
19942         /* Resource leaks will follow if wifi is initialized twice. */
19943         if (p_rarch->wifi_data)
19944            return false;
19945 
19946         wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL);
19947 
19948         if (p_rarch->wifi_driver && p_rarch->wifi_driver->init)
19949         {
19950            p_rarch->wifi_data = p_rarch->wifi_driver->init();
19951 
19952            if (p_rarch->wifi_data)
19953            {
19954               p_rarch->wifi_driver->enable(p_rarch->wifi_data,
19955                  settings->bools.wifi_enabled);
19956            }
19957            else
19958            {
19959               RARCH_ERR("Failed to initialize wifi driver. Will continue without wifi.\n");
19960               wifi_driver_ctl(RARCH_WIFI_CTL_UNSET_ACTIVE, NULL);
19961            }
19962         }
19963 
19964         break;
19965       default:
19966          break;
19967    }
19968 
19969    return false;
19970 }
19971 
19972 /* UI COMPANION */
19973 
ui_companion_set_foreground(unsigned enable)19974 void ui_companion_set_foreground(unsigned enable)
19975 {
19976    struct rarch_state     *p_rarch = &rarch_st;
19977    p_rarch->main_ui_companion_is_on_foreground = enable;
19978 }
19979 
ui_companion_is_on_foreground(void)19980 bool ui_companion_is_on_foreground(void)
19981 {
19982    struct rarch_state     *p_rarch = &rarch_st;
19983    return p_rarch->main_ui_companion_is_on_foreground;
19984 }
19985 
ui_companion_event_command(enum event_command action)19986 void ui_companion_event_command(enum event_command action)
19987 {
19988    struct rarch_state     *p_rarch = &rarch_st;
19989 #ifdef HAVE_QT
19990    bool qt_is_inited               = p_rarch->qt_is_inited;
19991 #endif
19992    const ui_companion_driver_t *ui = p_rarch->ui_companion;
19993 
19994    if (ui && ui->event_command)
19995       ui->event_command(p_rarch->ui_companion_data, action);
19996 #ifdef HAVE_QT
19997    if (ui_companion_qt.toggle && qt_is_inited)
19998       ui_companion_qt.event_command(
19999             p_rarch->ui_companion_qt_data, action);
20000 #endif
20001 }
20002 
ui_companion_driver_deinit(struct rarch_state * p_rarch)20003 static void ui_companion_driver_deinit(struct rarch_state *p_rarch)
20004 {
20005 #ifdef HAVE_QT
20006    bool qt_is_inited               = p_rarch->qt_is_inited;
20007 #endif
20008    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20009 
20010    if (!ui)
20011       return;
20012    if (ui->deinit)
20013       ui->deinit(p_rarch->ui_companion_data);
20014 
20015 #ifdef HAVE_QT
20016    if (qt_is_inited)
20017    {
20018       ui_companion_qt.deinit(p_rarch->ui_companion_qt_data);
20019       p_rarch->ui_companion_qt_data = NULL;
20020    }
20021 #endif
20022    p_rarch->ui_companion_data = NULL;
20023 }
20024 
ui_companion_driver_toggle(struct rarch_state * p_rarch,bool desktop_menu_enable,bool ui_companion_toggle,bool force)20025 static void ui_companion_driver_toggle(
20026       struct rarch_state *p_rarch,
20027       bool desktop_menu_enable,
20028       bool ui_companion_toggle,
20029       bool force)
20030 {
20031    if (p_rarch->ui_companion && p_rarch->ui_companion->toggle)
20032       p_rarch->ui_companion->toggle(p_rarch->ui_companion_data, false);
20033 
20034 #ifdef HAVE_QT
20035    if (desktop_menu_enable)
20036    {
20037       if ((ui_companion_toggle || force) && !p_rarch->qt_is_inited)
20038       {
20039          p_rarch->ui_companion_qt_data   = ui_companion_qt.init();
20040          p_rarch->qt_is_inited           = true;
20041       }
20042 
20043       if (ui_companion_qt.toggle && p_rarch->qt_is_inited)
20044          ui_companion_qt.toggle(p_rarch->ui_companion_qt_data, force);
20045    }
20046 #endif
20047 }
20048 
ui_companion_driver_init_first(settings_t * settings,struct rarch_state * p_rarch)20049 static void ui_companion_driver_init_first(
20050       settings_t *settings,
20051       struct rarch_state *p_rarch)
20052 {
20053 #ifdef HAVE_QT
20054    bool desktop_menu_enable            = settings->bools.desktop_menu_enable;
20055    bool ui_companion_toggle            = settings->bools.ui_companion_toggle;
20056 
20057    if (desktop_menu_enable && ui_companion_toggle)
20058    {
20059       p_rarch->ui_companion_qt_data    = ui_companion_qt.init();
20060       p_rarch->qt_is_inited            = true;
20061    }
20062 #else
20063    bool desktop_menu_enable            = false;
20064    bool ui_companion_toggle            = false;
20065 #endif
20066    unsigned ui_companion_start_on_boot =
20067       settings->bools.ui_companion_start_on_boot;
20068    p_rarch->ui_companion               = (ui_companion_driver_t*)ui_companion_drivers[0];
20069 
20070    if (p_rarch->ui_companion)
20071       if (ui_companion_start_on_boot)
20072       {
20073          if (p_rarch->ui_companion->init)
20074             p_rarch->ui_companion_data = p_rarch->ui_companion->init();
20075 
20076          ui_companion_driver_toggle(p_rarch,
20077                                     desktop_menu_enable,
20078                                     ui_companion_toggle,
20079                                     false);
20080       }
20081 }
20082 
ui_companion_driver_notify_refresh(void)20083 void ui_companion_driver_notify_refresh(void)
20084 {
20085    struct rarch_state *p_rarch     = &rarch_st;
20086    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20087 #ifdef HAVE_QT
20088    settings_t      *settings       = p_rarch->configuration_settings;
20089    bool desktop_menu_enable        = settings->bools.desktop_menu_enable;
20090    bool qt_is_inited               = p_rarch->qt_is_inited;
20091 #endif
20092 
20093    if (!ui)
20094       return;
20095    if (ui->notify_refresh)
20096       ui->notify_refresh(p_rarch->ui_companion_data);
20097 
20098 #ifdef HAVE_QT
20099    if (desktop_menu_enable)
20100       if (ui_companion_qt.notify_refresh && qt_is_inited)
20101          ui_companion_qt.notify_refresh(p_rarch->ui_companion_qt_data);
20102 #endif
20103 }
20104 
ui_companion_driver_notify_list_loaded(file_list_t * list,file_list_t * menu_list)20105 void ui_companion_driver_notify_list_loaded(
20106       file_list_t *list, file_list_t *menu_list)
20107 {
20108    struct rarch_state *p_rarch     = &rarch_st;
20109    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20110    if (ui && ui->notify_list_loaded)
20111       ui->notify_list_loaded(p_rarch->ui_companion_data, list, menu_list);
20112 }
20113 
ui_companion_driver_notify_content_loaded(void)20114 void ui_companion_driver_notify_content_loaded(void)
20115 {
20116    struct rarch_state *p_rarch     = &rarch_st;
20117    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20118    if (ui && ui->notify_content_loaded)
20119       ui->notify_content_loaded(p_rarch->ui_companion_data);
20120 }
20121 
ui_companion_driver_free(void)20122 void ui_companion_driver_free(void)
20123 {
20124    struct rarch_state *p_rarch     = &rarch_st;
20125 
20126    p_rarch->ui_companion = NULL;
20127 }
20128 
ui_companion_driver_get_msg_window_ptr(void)20129 const ui_msg_window_t *ui_companion_driver_get_msg_window_ptr(void)
20130 {
20131    struct rarch_state *p_rarch     = &rarch_st;
20132    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20133    if (!ui)
20134       return NULL;
20135    return ui->msg_window;
20136 }
20137 
ui_companion_driver_get_window_ptr(void)20138 const ui_window_t *ui_companion_driver_get_window_ptr(void)
20139 {
20140    struct rarch_state *p_rarch     = &rarch_st;
20141    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20142    if (!ui)
20143       return NULL;
20144    return ui->window;
20145 }
20146 
ui_companion_driver_get_browser_window_ptr(void)20147 const ui_browser_window_t *ui_companion_driver_get_browser_window_ptr(void)
20148 {
20149    struct rarch_state *p_rarch     = &rarch_st;
20150    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20151    if (!ui)
20152       return NULL;
20153    return ui->browser_window;
20154 }
20155 
ui_companion_driver_msg_queue_push(struct rarch_state * p_rarch,const char * msg,unsigned priority,unsigned duration,bool flush)20156 static void ui_companion_driver_msg_queue_push(
20157       struct rarch_state *p_rarch,
20158       const char *msg, unsigned priority, unsigned duration, bool flush)
20159 {
20160    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20161 
20162    if (ui && ui->msg_queue_push)
20163       ui->msg_queue_push(p_rarch->ui_companion_data, msg, priority, duration, flush);
20164 
20165 #ifdef HAVE_QT
20166    {
20167       settings_t *settings     = p_rarch->configuration_settings;
20168       bool qt_is_inited        = p_rarch->qt_is_inited;
20169       bool desktop_menu_enable = settings->bools.desktop_menu_enable;
20170 
20171       if (desktop_menu_enable)
20172          if (ui_companion_qt.msg_queue_push && qt_is_inited)
20173             ui_companion_qt.msg_queue_push(
20174                   p_rarch->ui_companion_qt_data,
20175                   msg, priority, duration, flush);
20176    }
20177 #endif
20178 }
20179 
ui_companion_driver_get_main_window(void)20180 void *ui_companion_driver_get_main_window(void)
20181 {
20182    struct rarch_state
20183       *p_rarch                     = &rarch_st;
20184    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20185    if (!ui || !ui->get_main_window)
20186       return NULL;
20187    return ui->get_main_window(p_rarch->ui_companion_data);
20188 }
20189 
ui_companion_driver_get_ident(void)20190 const char *ui_companion_driver_get_ident(void)
20191 {
20192    struct rarch_state
20193       *p_rarch                     = &rarch_st;
20194    const ui_companion_driver_t *ui = p_rarch->ui_companion;
20195    if (!ui)
20196       return "null";
20197    return ui->ident;
20198 }
20199 
ui_companion_driver_log_msg(const char * msg)20200 void ui_companion_driver_log_msg(const char *msg)
20201 {
20202 #ifdef HAVE_QT
20203    struct rarch_state *p_rarch = &rarch_st;
20204    settings_t *settings        = p_rarch->configuration_settings;
20205    bool qt_is_inited           = p_rarch->qt_is_inited;
20206    bool desktop_menu_enable    = settings->bools.desktop_menu_enable;
20207    bool window_is_active       = p_rarch->ui_companion_qt_data && qt_is_inited
20208       && ui_companion_qt.is_active(p_rarch->ui_companion_qt_data);
20209 
20210    if (desktop_menu_enable)
20211       if (window_is_active)
20212          ui_companion_qt.log_msg(p_rarch->ui_companion_qt_data, msg);
20213 #endif
20214 }
20215 
20216 /* RECORDING */
20217 
20218 /**
20219  * config_get_record_driver_options:
20220  *
20221  * Get an enumerated list of all record driver names, separated by '|'.
20222  *
20223  * Returns: string listing of all record driver names, separated by '|'.
20224  **/
config_get_record_driver_options(void)20225 const char* config_get_record_driver_options(void)
20226 {
20227    return char_list_new_special(STRING_LIST_RECORD_DRIVERS, NULL);
20228 }
20229 
20230 #if 0
20231 /* TODO/FIXME - not used apparently */
20232 static void find_record_driver(struct rarch_state *p_rarch, const char *prefix,
20233       bool verbosity_enabled)
20234 {
20235    settings_t *settings = p_rarch->configuration_settings;
20236    int i                = (int)driver_find_index(
20237          "record_driver",
20238          settings->arrays.record_driver);
20239 
20240    if (i >= 0)
20241       p_rarch->recording_driver = (const record_driver_t*)record_drivers[i];
20242    else
20243    {
20244       if (verbosity_enabled)
20245       {
20246          unsigned d;
20247 
20248          RARCH_ERR("[recording] Couldn't find any %s named \"%s\"\n", prefix,
20249                settings->arrays.record_driver);
20250          RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
20251          for (d = 0; record_drivers[d]; d++)
20252             RARCH_LOG_OUTPUT("\t%s\n", record_drivers[d].ident);
20253          RARCH_WARN("[recording] Going to default to first %s...\n", prefix);
20254       }
20255 
20256       p_rarch->recording_driver = (const record_driver_t*)record_drivers[0];
20257 
20258       if (!p_rarch->recording_driver)
20259          retroarch_fail(p_rarch, 1, "find_record_driver()");
20260    }
20261 }
20262 
20263 /**
20264  * ffemu_find_backend:
20265  * @ident                   : Identifier of driver to find.
20266  *
20267  * Finds a recording driver with the name @ident.
20268  *
20269  * Returns: recording driver handle if successful, otherwise
20270  * NULL.
20271  **/
20272 static const record_driver_t *ffemu_find_backend(const char *ident)
20273 {
20274    unsigned i;
20275 
20276    for (i = 0; record_drivers[i]; i++)
20277    {
20278       if (string_is_equal(record_drivers[i]->ident, ident))
20279          return record_drivers[i];
20280    }
20281 
20282    return NULL;
20283 }
20284 
20285 static void recording_driver_free_state(struct rarch_state *p_rarch)
20286 {
20287    /* TODO/FIXME - this is not being called anywhere */
20288    p_rarch->recording_gpu_width      = 0;
20289    p_rarch->recording_gpu_height     = 0;
20290    p_rarch->recording_width          = 0;
20291    p_rarch->recording_height         = 0;
20292 }
20293 #endif
20294 
20295 /**
20296  * gfx_ctx_init_first:
20297  * @backend                 : Recording backend handle.
20298  * @data                    : Recording data handle.
20299  * @params                  : Recording info parameters.
20300  *
20301  * Finds first suitable recording context driver and initializes.
20302  *
20303  * Returns: true (1) if successful, otherwise false (0).
20304  **/
record_driver_init_first(const record_driver_t ** backend,void ** data,const struct record_params * params)20305 static bool record_driver_init_first(
20306       const record_driver_t **backend, void **data,
20307       const struct record_params *params)
20308 {
20309    unsigned i;
20310 
20311    for (i = 0; record_drivers[i]; i++)
20312    {
20313       void *handle = record_drivers[i]->init(params);
20314 
20315       if (!handle)
20316          continue;
20317 
20318       *backend = record_drivers[i];
20319       *data = handle;
20320       return true;
20321    }
20322 
20323    return false;
20324 }
20325 
recording_dump_frame(struct rarch_state * p_rarch,const void * data,unsigned width,unsigned height,size_t pitch,bool is_idle)20326 static void recording_dump_frame(
20327       struct rarch_state *p_rarch,
20328       const void *data, unsigned width,
20329       unsigned height, size_t pitch, bool is_idle)
20330 {
20331    struct record_video_data ffemu_data;
20332 
20333    ffemu_data.data     = data;
20334    ffemu_data.width    = width;
20335    ffemu_data.height   = height;
20336    ffemu_data.pitch    = (int)pitch;
20337    ffemu_data.is_dupe  = false;
20338 
20339    if (p_rarch->video_driver_record_gpu_buffer)
20340    {
20341       struct video_viewport vp;
20342 
20343       vp.x                        = 0;
20344       vp.y                        = 0;
20345       vp.width                    = 0;
20346       vp.height                   = 0;
20347       vp.full_width               = 0;
20348       vp.full_height              = 0;
20349 
20350       video_driver_get_viewport_info(&vp);
20351 
20352       if (!vp.width || !vp.height)
20353       {
20354          RARCH_WARN("[recording] %s \n",
20355                msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED));
20356          video_driver_gpu_record_deinit(p_rarch);
20357          recording_dump_frame(p_rarch,
20358                data, width, height, pitch, is_idle);
20359          return;
20360       }
20361 
20362       /* User has resized. We kinda have a problem now. */
20363       if (  vp.width  != p_rarch->recording_gpu_width ||
20364             vp.height != p_rarch->recording_gpu_height)
20365       {
20366          RARCH_WARN("[recording] %s\n",
20367                msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE));
20368 
20369          runloop_msg_queue_push(
20370                msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE),
20371                1, 180, true,
20372                NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
20373          command_event(CMD_EVENT_RECORD_DEINIT, NULL);
20374          return;
20375       }
20376 
20377       /* Big bottleneck.
20378        * Since we might need to do read-backs asynchronously,
20379        * it might take 3-4 times before this returns true. */
20380       if (!video_driver_read_viewport(p_rarch->video_driver_record_gpu_buffer, is_idle))
20381          return;
20382 
20383       ffemu_data.pitch  = (int)(p_rarch->recording_gpu_width * 3);
20384       ffemu_data.width  = (unsigned)p_rarch->recording_gpu_width;
20385       ffemu_data.height = (unsigned)p_rarch->recording_gpu_height;
20386       ffemu_data.data   = p_rarch->video_driver_record_gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch;
20387 
20388       ffemu_data.pitch  = -ffemu_data.pitch;
20389    }
20390    else
20391       ffemu_data.is_dupe = !data;
20392 
20393    p_rarch->recording_driver->push_video(p_rarch->recording_data, &ffemu_data);
20394 }
20395 
recording_deinit(struct rarch_state * p_rarch)20396 static bool recording_deinit(struct rarch_state *p_rarch)
20397 {
20398    if (!p_rarch->recording_data || !p_rarch->recording_driver)
20399       return false;
20400 
20401    if (p_rarch->recording_driver->finalize)
20402       p_rarch->recording_driver->finalize(p_rarch->recording_data);
20403 
20404    if (p_rarch->recording_driver->free)
20405       p_rarch->recording_driver->free(p_rarch->recording_data);
20406 
20407    p_rarch->recording_data            = NULL;
20408    p_rarch->recording_driver          = NULL;
20409 
20410    video_driver_gpu_record_deinit(p_rarch);
20411 
20412    return true;
20413 }
20414 
recording_is_enabled(void)20415 bool recording_is_enabled(void)
20416 {
20417    struct rarch_state *p_rarch          = &rarch_st;
20418    return p_rarch->recording_enable;
20419 }
20420 
streaming_is_enabled(void)20421 bool streaming_is_enabled(void)
20422 {
20423    struct rarch_state *p_rarch = &rarch_st;
20424    return p_rarch->streaming_enable;
20425 }
20426 
streaming_set_state(bool state)20427 void streaming_set_state(bool state)
20428 {
20429    struct rarch_state *p_rarch = &rarch_st;
20430    p_rarch->streaming_enable = state;
20431 }
20432 
video_driver_gpu_record_deinit(struct rarch_state * p_rarch)20433 static void video_driver_gpu_record_deinit(struct rarch_state *p_rarch)
20434 {
20435    if (p_rarch->video_driver_record_gpu_buffer)
20436       free(p_rarch->video_driver_record_gpu_buffer);
20437    p_rarch->video_driver_record_gpu_buffer = NULL;
20438 }
20439 
20440 /**
20441  * recording_init:
20442  *
20443  * Initializes recording.
20444  *
20445  * Returns: true (1) if successful, otherwise false (0).
20446  **/
recording_init(settings_t * settings,struct rarch_state * p_rarch)20447 static bool recording_init(
20448       settings_t *settings,
20449       struct rarch_state *p_rarch)
20450 {
20451    char output[PATH_MAX_LENGTH];
20452    char buf[PATH_MAX_LENGTH];
20453    struct record_params params          = {0};
20454    struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
20455    global_t *global                     = &p_rarch->g_extern;
20456    bool video_gpu_record                = settings->bools.video_gpu_record;
20457    bool video_force_aspect              = settings->bools.video_force_aspect;
20458    const enum rarch_core_type
20459       current_core_type                 = p_rarch->current_core_type;
20460    const enum retro_pixel_format
20461       video_driver_pix_fmt              = p_rarch->video_driver_pix_fmt;
20462    bool recording_enable                = p_rarch->recording_enable;
20463 
20464    if (!recording_enable)
20465       return false;
20466 
20467    output[0] = '\0';
20468 
20469    if (current_core_type == CORE_TYPE_DUMMY)
20470    {
20471       RARCH_WARN("[recording] %s\n",
20472             msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED));
20473       return false;
20474    }
20475 
20476    if (!video_gpu_record && video_driver_is_hw_context())
20477    {
20478       RARCH_WARN("[recording] %s.\n",
20479             msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING));
20480       return false;
20481    }
20482 
20483    RARCH_LOG("[recording] %s: FPS: %.4f, Sample rate: %.4f\n",
20484          msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN),
20485          (float)av_info->timing.fps,
20486          (float)av_info->timing.sample_rate);
20487 
20488    if (!string_is_empty(global->record.path))
20489       strlcpy(output, global->record.path, sizeof(output));
20490    else
20491    {
20492       const char *stream_url        = settings->paths.path_stream_url;
20493       unsigned video_record_quality = settings->uints.video_record_quality;
20494       unsigned video_stream_port    = settings->uints.video_stream_port;
20495       if (p_rarch->streaming_enable)
20496          if (!string_is_empty(stream_url))
20497             strlcpy(output, stream_url, sizeof(output));
20498          else
20499             /* Fallback, stream locally to 127.0.0.1 */
20500             snprintf(output, sizeof(output), "udp://127.0.0.1:%u",
20501                   video_stream_port);
20502       else
20503       {
20504          const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME));
20505          /* Fallback to core name if started without content */
20506          if (string_is_empty(game_name))
20507             game_name = runloop_state.system.info.library_name;
20508 
20509          if (video_record_quality < RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST)
20510          {
20511             fill_str_dated_filename(buf, game_name,
20512                      "mkv", sizeof(buf));
20513             fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
20514          }
20515          else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST
20516                && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_GIF)
20517          {
20518             fill_str_dated_filename(buf, game_name,
20519                      "webm", sizeof(buf));
20520             fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
20521          }
20522          else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_GIF
20523                && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_APNG)
20524          {
20525             fill_str_dated_filename(buf, game_name,
20526                      "gif", sizeof(buf));
20527             fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
20528          }
20529          else
20530          {
20531             fill_str_dated_filename(buf, game_name,
20532                      "png", sizeof(buf));
20533             fill_pathname_join(output, global->record.output_dir, buf, sizeof(output));
20534          }
20535       }
20536    }
20537 
20538    params.audio_resampler           = settings->arrays.audio_resampler;
20539    params.video_gpu_record          = settings->bools.video_gpu_record;
20540    params.video_record_scale_factor = settings->uints.video_record_scale_factor;
20541    params.video_stream_scale_factor = settings->uints.video_stream_scale_factor;
20542    params.video_record_threads      = settings->uints.video_record_threads;
20543    params.streaming_mode            = settings->uints.streaming_mode;
20544 
20545    params.out_width                 = av_info->geometry.base_width;
20546    params.out_height                = av_info->geometry.base_height;
20547    params.fb_width                  = av_info->geometry.max_width;
20548    params.fb_height                 = av_info->geometry.max_height;
20549    params.channels                  = 2;
20550    params.filename                  = output;
20551    params.fps                       = av_info->timing.fps;
20552    params.samplerate                = av_info->timing.sample_rate;
20553    params.pix_fmt                   =
20554       (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
20555       ? FFEMU_PIX_ARGB8888
20556       : FFEMU_PIX_RGB565;
20557    params.config                    = NULL;
20558 
20559    if (!string_is_empty(global->record.config))
20560       params.config                 = global->record.config;
20561    else
20562    {
20563       if (p_rarch->streaming_enable)
20564       {
20565          params.config = settings->paths.path_stream_config;
20566          params.preset = (enum record_config_type)
20567             settings->uints.video_stream_quality;
20568       }
20569       else
20570       {
20571          params.config = settings->paths.path_record_config;
20572          params.preset = (enum record_config_type)
20573             settings->uints.video_record_quality;
20574       }
20575    }
20576 
20577    if (settings->bools.video_gpu_record
20578       && p_rarch->current_video->read_viewport)
20579    {
20580       unsigned gpu_size;
20581       struct video_viewport vp;
20582 
20583       vp.x                        = 0;
20584       vp.y                        = 0;
20585       vp.width                    = 0;
20586       vp.height                   = 0;
20587       vp.full_width               = 0;
20588       vp.full_height              = 0;
20589 
20590       video_driver_get_viewport_info(&vp);
20591 
20592       if (!vp.width || !vp.height)
20593       {
20594          RARCH_ERR("[recording] Failed to get viewport information from video driver. "
20595                "Cannot start recording ...\n");
20596          return false;
20597       }
20598 
20599       params.out_width                    = vp.width;
20600       params.out_height                   = vp.height;
20601       params.fb_width                     = next_pow2(vp.width);
20602       params.fb_height                    = next_pow2(vp.height);
20603 
20604       if (video_force_aspect &&
20605             (p_rarch->video_driver_aspect_ratio > 0.0f))
20606          params.aspect_ratio              = p_rarch->video_driver_aspect_ratio;
20607       else
20608          params.aspect_ratio              = (float)vp.width / vp.height;
20609 
20610       params.pix_fmt                      = FFEMU_PIX_BGR24;
20611       p_rarch->recording_gpu_width        = vp.width;
20612       p_rarch->recording_gpu_height       = vp.height;
20613 
20614       RARCH_LOG("[recording] %s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF),
20615             vp.width, vp.height);
20616 
20617       gpu_size = vp.width * vp.height * 3;
20618       if (!(p_rarch->video_driver_record_gpu_buffer = (uint8_t*)malloc(gpu_size)))
20619          return false;
20620    }
20621    else
20622    {
20623       if (p_rarch->recording_width || p_rarch->recording_height)
20624       {
20625          params.out_width  = p_rarch->recording_width;
20626          params.out_height = p_rarch->recording_height;
20627       }
20628 
20629       if (video_force_aspect &&
20630             (p_rarch->video_driver_aspect_ratio > 0.0f))
20631          params.aspect_ratio = p_rarch->video_driver_aspect_ratio;
20632       else
20633          params.aspect_ratio = (float)params.out_width / params.out_height;
20634 
20635 #ifdef HAVE_VIDEO_FILTER
20636       if (settings->bools.video_post_filter_record
20637             && !!p_rarch->video_driver_state_filter)
20638       {
20639          unsigned max_width  = 0;
20640          unsigned max_height = 0;
20641 
20642          params.pix_fmt      = FFEMU_PIX_RGB565;
20643 
20644          if (p_rarch->video_driver_state_out_rgb32)
20645             params.pix_fmt = FFEMU_PIX_ARGB8888;
20646 
20647          rarch_softfilter_get_max_output_size(
20648                p_rarch->video_driver_state_filter,
20649                &max_width, &max_height);
20650          params.fb_width  = next_pow2(max_width);
20651          params.fb_height = next_pow2(max_height);
20652       }
20653 #endif
20654    }
20655 
20656    RARCH_LOG("[recording] %s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
20657          msg_hash_to_str(MSG_RECORDING_TO),
20658          output,
20659          params.out_width, params.out_height,
20660          params.fb_width, params.fb_height,
20661          (unsigned)params.pix_fmt);
20662 
20663    if (!record_driver_init_first(
20664             &p_rarch->recording_driver, &p_rarch->recording_data, &params))
20665    {
20666       RARCH_ERR("[recording] %s\n",
20667             msg_hash_to_str(MSG_FAILED_TO_START_RECORDING));
20668       video_driver_gpu_record_deinit(p_rarch);
20669 
20670       return false;
20671    }
20672 
20673    return true;
20674 }
20675 
recording_driver_update_streaming_url(void)20676 void recording_driver_update_streaming_url(void)
20677 {
20678    struct rarch_state *p_rarch = &rarch_st;
20679    settings_t     *settings    = p_rarch->configuration_settings;
20680    const char     *youtube_url = "rtmp://a.rtmp.youtube.com/live2/";
20681    const char     *twitch_url  = "rtmp://live.twitch.tv/app/";
20682    const char     *facebook_url  = "rtmps://live-api-s.facebook.com:443/rtmp/";
20683 
20684    if (!settings)
20685       return;
20686 
20687    switch (settings->uints.streaming_mode)
20688    {
20689       case STREAMING_MODE_TWITCH:
20690          if (!string_is_empty(settings->arrays.twitch_stream_key))
20691          {
20692             strlcpy(settings->paths.path_stream_url,
20693                   twitch_url,
20694                   sizeof(settings->paths.path_stream_url));
20695             strlcat(settings->paths.path_stream_url,
20696                   settings->arrays.twitch_stream_key,
20697                   sizeof(settings->paths.path_stream_url));
20698          }
20699          break;
20700       case STREAMING_MODE_YOUTUBE:
20701          if (!string_is_empty(settings->arrays.youtube_stream_key))
20702          {
20703             strlcpy(settings->paths.path_stream_url,
20704                   youtube_url,
20705                   sizeof(settings->paths.path_stream_url));
20706             strlcat(settings->paths.path_stream_url,
20707                   settings->arrays.youtube_stream_key,
20708                   sizeof(settings->paths.path_stream_url));
20709          }
20710          break;
20711       case STREAMING_MODE_LOCAL:
20712          /* TODO: figure out default interface and bind to that instead */
20713          snprintf(settings->paths.path_stream_url, sizeof(settings->paths.path_stream_url),
20714             "udp://%s:%u", "127.0.0.1", settings->uints.video_stream_port);
20715          break;
20716       case STREAMING_MODE_CUSTOM:
20717       default:
20718          /* Do nothing, let the user input the URL */
20719          break;
20720       case STREAMING_MODE_FACEBOOK:
20721          if (!string_is_empty(settings->arrays.facebook_stream_key))
20722          {
20723             strlcpy(settings->paths.path_stream_url,
20724                   facebook_url,
20725                   sizeof(settings->paths.path_stream_url));
20726             strlcat(settings->paths.path_stream_url,
20727                   settings->arrays.facebook_stream_key,
20728                   sizeof(settings->paths.path_stream_url));
20729          }
20730          break;
20731    }
20732 }
20733 
20734 #ifdef HAVE_BSV_MOVIE
20735 /* BSV MOVIE */
bsv_movie_init_playback(bsv_movie_t * handle,const char * path)20736 static bool bsv_movie_init_playback(
20737       bsv_movie_t *handle, const char *path)
20738 {
20739    uint32_t state_size       = 0;
20740    uint32_t content_crc      = 0;
20741    uint32_t header[4]        = {0};
20742    intfstream_t *file        = intfstream_open_file(path,
20743          RETRO_VFS_FILE_ACCESS_READ,
20744          RETRO_VFS_FILE_ACCESS_HINT_NONE);
20745 
20746    if (!file)
20747    {
20748       RARCH_ERR("Could not open BSV file for playback, path : \"%s\".\n", path);
20749       return false;
20750    }
20751 
20752    handle->file              = file;
20753    handle->playback          = true;
20754 
20755    intfstream_read(handle->file, header, sizeof(uint32_t) * 4);
20756    /* Compatibility with old implementation that
20757     * used incorrect documentation. */
20758    if (swap_if_little32(header[MAGIC_INDEX]) != BSV_MAGIC
20759          && swap_if_big32(header[MAGIC_INDEX]) != BSV_MAGIC)
20760    {
20761       RARCH_ERR("%s\n", msg_hash_to_str(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE));
20762       return false;
20763    }
20764 
20765    content_crc               = content_get_crc();
20766 
20767    if (content_crc != 0)
20768       if (swap_if_big32(header[CRC_INDEX]) != content_crc)
20769          RARCH_WARN("%s.\n", msg_hash_to_str(MSG_CRC32_CHECKSUM_MISMATCH));
20770 
20771    state_size = swap_if_big32(header[STATE_SIZE_INDEX]);
20772 
20773 #if 0
20774    RARCH_ERR("----- debug %u -----\n", header[0]);
20775    RARCH_ERR("----- debug %u -----\n", header[1]);
20776    RARCH_ERR("----- debug %u -----\n", header[2]);
20777    RARCH_ERR("----- debug %u -----\n", header[3]);
20778 #endif
20779 
20780    if (state_size)
20781    {
20782       retro_ctx_size_info_t info;
20783       retro_ctx_serialize_info_t serial_info;
20784       uint8_t *buf       = (uint8_t*)malloc(state_size);
20785 
20786       if (!buf)
20787          return false;
20788 
20789       handle->state      = buf;
20790       handle->state_size = state_size;
20791       if (intfstream_read(handle->file,
20792                handle->state, state_size) != state_size)
20793       {
20794          RARCH_ERR("%s\n", msg_hash_to_str(MSG_COULD_NOT_READ_STATE_FROM_MOVIE));
20795          return false;
20796       }
20797 
20798       core_serialize_size( &info);
20799 
20800       if (info.size == state_size)
20801       {
20802          serial_info.data_const = handle->state;
20803          serial_info.size       = state_size;
20804          core_unserialize(&serial_info);
20805       }
20806       else
20807          RARCH_WARN("%s\n",
20808                msg_hash_to_str(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION));
20809    }
20810 
20811    handle->min_file_pos = sizeof(header) + state_size;
20812 
20813    return true;
20814 }
20815 
bsv_movie_init_record(bsv_movie_t * handle,const char * path)20816 static bool bsv_movie_init_record(
20817       bsv_movie_t *handle, const char *path)
20818 {
20819    retro_ctx_size_info_t info;
20820    uint32_t state_size       = 0;
20821    uint32_t content_crc      = 0;
20822    uint32_t header[4]        = {0};
20823    intfstream_t *file        = intfstream_open_file(path,
20824          RETRO_VFS_FILE_ACCESS_WRITE,
20825          RETRO_VFS_FILE_ACCESS_HINT_NONE);
20826 
20827    if (!file)
20828    {
20829       RARCH_ERR("Could not open BSV file for recording, path : \"%s\".\n", path);
20830       return false;
20831    }
20832 
20833    handle->file             = file;
20834 
20835    content_crc              = content_get_crc();
20836 
20837    /* This value is supposed to show up as
20838     * BSV1 in a HEX editor, big-endian. */
20839    header[MAGIC_INDEX]      = swap_if_little32(BSV_MAGIC);
20840    header[CRC_INDEX]        = swap_if_big32(content_crc);
20841 
20842    core_serialize_size(&info);
20843 
20844    state_size               = (unsigned)info.size;
20845 
20846    header[STATE_SIZE_INDEX] = swap_if_big32(state_size);
20847 
20848    intfstream_write(handle->file, header, 4 * sizeof(uint32_t));
20849 
20850    handle->min_file_pos     = sizeof(header) + state_size;
20851    handle->state_size       = state_size;
20852 
20853    if (state_size)
20854    {
20855       retro_ctx_serialize_info_t serial_info;
20856       uint8_t *st      = (uint8_t*)malloc(state_size);
20857 
20858       if (!st)
20859          return false;
20860 
20861       handle->state    = st;
20862 
20863       serial_info.data = handle->state;
20864       serial_info.size = state_size;
20865 
20866       core_serialize(&serial_info);
20867 
20868       intfstream_write(handle->file,
20869             handle->state, state_size);
20870    }
20871 
20872    return true;
20873 }
20874 
bsv_movie_free(bsv_movie_t * handle)20875 static void bsv_movie_free(bsv_movie_t *handle)
20876 {
20877    if (!handle)
20878       return;
20879 
20880    intfstream_close(handle->file);
20881    free(handle->file);
20882 
20883    free(handle->state);
20884    free(handle->frame_pos);
20885    free(handle);
20886 }
20887 
bsv_movie_init_internal(const char * path,enum rarch_movie_type type)20888 static bsv_movie_t *bsv_movie_init_internal(const char *path,
20889       enum rarch_movie_type type)
20890 {
20891    size_t *frame_pos   = NULL;
20892    bsv_movie_t *handle = (bsv_movie_t*)calloc(1, sizeof(*handle));
20893 
20894    if (!handle)
20895       return NULL;
20896 
20897    if (type == RARCH_MOVIE_PLAYBACK)
20898    {
20899       if (!bsv_movie_init_playback(handle, path))
20900          goto error;
20901    }
20902    else if (!bsv_movie_init_record(handle, path))
20903       goto error;
20904 
20905    /* Just pick something really large
20906     * ~1 million frames rewind should do the trick. */
20907    if (!(frame_pos = (size_t*)calloc((1 << 20), sizeof(size_t))))
20908       goto error;
20909 
20910    handle->frame_pos       = frame_pos;
20911 
20912    handle->frame_pos[0]    = handle->min_file_pos;
20913    handle->frame_mask      = (1 << 20) - 1;
20914 
20915    return handle;
20916 
20917 error:
20918    bsv_movie_free(handle);
20919    return NULL;
20920 }
20921 
bsv_movie_frame_rewind(void)20922 void bsv_movie_frame_rewind(void)
20923 {
20924    struct rarch_state *p_rarch = &rarch_st;
20925    bsv_movie_t         *handle = p_rarch->bsv_movie_state_handle;
20926 
20927    if (!handle)
20928       return;
20929 
20930    handle->did_rewind = true;
20931 
20932    if (     (handle->frame_ptr <= 1)
20933          && (handle->frame_pos[0] == handle->min_file_pos))
20934    {
20935       /* If we're at the beginning... */
20936       handle->frame_ptr = 0;
20937       intfstream_seek(handle->file, (int)handle->min_file_pos, SEEK_SET);
20938    }
20939    else
20940    {
20941       /* First time rewind is performed, the old frame is simply replayed.
20942        * However, playing back that frame caused us to read data, and push
20943        * data to the ring buffer.
20944        *
20945        * Sucessively rewinding frames, we need to rewind past the read data,
20946        * plus another. */
20947       handle->frame_ptr = (handle->frame_ptr -
20948             (handle->first_rewind ? 1 : 2)) & handle->frame_mask;
20949       intfstream_seek(handle->file,
20950             (int)handle->frame_pos[handle->frame_ptr], SEEK_SET);
20951    }
20952 
20953    if (intfstream_tell(handle->file) <= (long)handle->min_file_pos)
20954    {
20955       /* We rewound past the beginning. */
20956 
20957       if (!handle->playback)
20958       {
20959          retro_ctx_serialize_info_t serial_info;
20960 
20961          /* If recording, we simply reset
20962           * the starting point. Nice and easy. */
20963 
20964          intfstream_seek(handle->file, 4 * sizeof(uint32_t), SEEK_SET);
20965 
20966          serial_info.data = handle->state;
20967          serial_info.size = handle->state_size;
20968 
20969          core_serialize(&serial_info);
20970 
20971          intfstream_write(handle->file, handle->state, handle->state_size);
20972       }
20973       else
20974          intfstream_seek(handle->file, (int)handle->min_file_pos, SEEK_SET);
20975    }
20976 }
20977 
bsv_movie_init_handle(struct rarch_state * p_rarch,const char * path,enum rarch_movie_type type)20978 static bool bsv_movie_init_handle(
20979       struct rarch_state *p_rarch,
20980       const char *path,
20981       enum rarch_movie_type type)
20982 {
20983    bsv_movie_t *state              = bsv_movie_init_internal(path, type);
20984    if (!state)
20985       return false;
20986 
20987    p_rarch->bsv_movie_state_handle = state;
20988    return true;
20989 }
20990 
bsv_movie_init(struct rarch_state * p_rarch)20991 static bool bsv_movie_init(struct rarch_state *p_rarch)
20992 {
20993    if (p_rarch->bsv_movie_state.movie_start_playback)
20994    {
20995       if (!bsv_movie_init_handle(p_rarch,
20996                p_rarch->bsv_movie_state.movie_start_path,
20997                   RARCH_MOVIE_PLAYBACK))
20998       {
20999          RARCH_ERR("%s: \"%s\".\n",
21000                msg_hash_to_str(MSG_FAILED_TO_LOAD_MOVIE_FILE),
21001                p_rarch->bsv_movie_state.movie_start_path);
21002          return false;
21003       }
21004 
21005       p_rarch->bsv_movie_state.movie_playback = true;
21006       runloop_msg_queue_push(msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK),
21007             2, 180, false,
21008             NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21009       RARCH_LOG("%s.\n", msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK));
21010 
21011       return true;
21012    }
21013    else if (p_rarch->bsv_movie_state.movie_start_recording)
21014    {
21015       char msg[8192];
21016 
21017       if (!bsv_movie_init_handle(
21018                p_rarch,
21019                p_rarch->bsv_movie_state.movie_start_path,
21020                RARCH_MOVIE_RECORD))
21021       {
21022          runloop_msg_queue_push(
21023                msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD),
21024                1, 180, true,
21025                NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21026          RARCH_ERR("%s.\n",
21027                msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD));
21028          return false;
21029       }
21030 
21031       snprintf(msg, sizeof(msg),
21032             "%s \"%s\".",
21033             msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
21034             p_rarch->bsv_movie_state.movie_start_path);
21035 
21036       runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21037       RARCH_LOG("%s \"%s\".\n",
21038             msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
21039             p_rarch->bsv_movie_state.movie_start_path);
21040 
21041       return true;
21042    }
21043 
21044    return false;
21045 }
21046 
bsv_movie_deinit(struct rarch_state * p_rarch)21047 static void bsv_movie_deinit(struct rarch_state *p_rarch)
21048 {
21049    if (p_rarch->bsv_movie_state_handle)
21050       bsv_movie_free(p_rarch->bsv_movie_state_handle);
21051    p_rarch->bsv_movie_state_handle = NULL;
21052 }
21053 
runloop_check_movie_init(struct rarch_state * p_rarch,settings_t * settings)21054 static bool runloop_check_movie_init(struct rarch_state *p_rarch,
21055       settings_t *settings)
21056 {
21057    char msg[16384], path[8192];
21058    int state_slot              = settings->ints.state_slot;
21059 
21060    msg[0] = path[0]            = '\0';
21061 
21062    configuration_set_uint(settings, settings->uints.rewind_granularity, 1);
21063 
21064    if (state_slot > 0)
21065       snprintf(path, sizeof(path), "%s%d.bsv",
21066             p_rarch->bsv_movie_state.movie_path,
21067             state_slot);
21068    else
21069       snprintf(path, sizeof(path), "%s.bsv",
21070             p_rarch->bsv_movie_state.movie_path);
21071 
21072    snprintf(msg, sizeof(msg), "%s \"%s\".",
21073          msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
21074          path);
21075 
21076    bsv_movie_init_handle(
21077          p_rarch,
21078          path, RARCH_MOVIE_RECORD);
21079 
21080    if (!p_rarch->bsv_movie_state_handle)
21081    {
21082       runloop_msg_queue_push(
21083             msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD),
21084             2, 180, true,
21085             NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21086       RARCH_ERR("%s\n",
21087             msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD));
21088       return false;
21089    }
21090 
21091    runloop_msg_queue_push(msg, 2, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21092    RARCH_LOG("%s \"%s\".\n",
21093          msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO),
21094          path);
21095 
21096    return true;
21097 }
21098 
bsv_movie_check(struct rarch_state * p_rarch,settings_t * settings)21099 static bool bsv_movie_check(struct rarch_state *p_rarch,
21100       settings_t *settings)
21101 {
21102    if (!p_rarch->bsv_movie_state_handle)
21103       return runloop_check_movie_init(p_rarch, settings);
21104 
21105    if (p_rarch->bsv_movie_state.movie_playback)
21106    {
21107       /* Checks if movie is being played back. */
21108       if (!p_rarch->bsv_movie_state.movie_end)
21109          return false;
21110       runloop_msg_queue_push(
21111             msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED), 2, 180, false,
21112             NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21113       RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED));
21114 
21115       bsv_movie_deinit(p_rarch);
21116 
21117       p_rarch->bsv_movie_state.movie_end      = false;
21118       p_rarch->bsv_movie_state.movie_playback = false;
21119 
21120       return true;
21121    }
21122 
21123    /* Checks if movie is being recorded. */
21124    if (!p_rarch->bsv_movie_state_handle)
21125       return false;
21126 
21127    runloop_msg_queue_push(
21128          msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED), 2, 180, true,
21129          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
21130    RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED));
21131 
21132    bsv_movie_deinit(p_rarch);
21133 
21134    return true;
21135 }
21136 #endif
21137 
21138 /* INPUT OVERLAY */
21139 
21140 #ifdef HAVE_OVERLAY
21141 static bool video_driver_overlay_interface(
21142       const video_overlay_interface_t **iface);
21143 
21144 /**
21145  * input_overlay_add_inputs:
21146  * @desc : pointer to overlay description
21147  * @ol_state : pointer to overlay state. If valid, inputs
21148  *             that are actually 'touched' on the overlay
21149  *             itself will displayed. If NULL, inputs from
21150  *             the device connected to 'port' will be displayed.
21151  * @port : when ol_state is NULL, specifies the port of
21152  *         the input device from which input will be
21153  *         displayed.
21154  *
21155  * Adds inputs from current_input to the overlay, so it's displayed
21156  * returns true if an input that is pressed will change the overlay
21157  */
input_overlay_add_inputs_inner(overlay_desc_t * desc,input_overlay_state_t * ol_state,unsigned port)21158 static bool input_overlay_add_inputs_inner(overlay_desc_t *desc,
21159       input_overlay_state_t *ol_state, unsigned port)
21160 {
21161    switch(desc->type)
21162    {
21163       case OVERLAY_TYPE_BUTTONS:
21164          {
21165             unsigned i;
21166             bool all_buttons_pressed        = false;
21167 
21168             /* Check each bank of the mask */
21169             for (i = 0; i < ARRAY_SIZE(desc->button_mask.data); ++i)
21170             {
21171                /* Get bank */
21172                uint32_t bank_mask = BITS_GET_ELEM(desc->button_mask,i);
21173                unsigned        id = i * 32;
21174 
21175                /* Worth pursuing? Have we got any bits left in here? */
21176                while (bank_mask)
21177                {
21178                   /* If this bit is set then we need to query the pad
21179                    * The button must be pressed.*/
21180                   if (bank_mask & 1)
21181                   {
21182                      /* Light up the button if pressed */
21183                      if (ol_state ?
21184                            !BIT256_GET(ol_state->buttons, id) :
21185                            !input_state_internal(port, RETRO_DEVICE_JOYPAD, 0, id))
21186                      {
21187                         /* We need ALL of the inputs to be active,
21188                          * abort. */
21189                         desc->updated    = false;
21190                         return false;
21191                      }
21192 
21193                      all_buttons_pressed = true;
21194                      desc->updated       = true;
21195                   }
21196 
21197                   bank_mask >>= 1;
21198                   ++id;
21199                }
21200             }
21201 
21202             return all_buttons_pressed;
21203          }
21204 
21205       case OVERLAY_TYPE_ANALOG_LEFT:
21206       case OVERLAY_TYPE_ANALOG_RIGHT:
21207          {
21208             float analog_x;
21209             float analog_y;
21210             float dx;
21211             float dy;
21212 
21213             if (ol_state)
21214             {
21215                unsigned index_offset = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ? 2 : 0;
21216                analog_x              = (float)ol_state->analog[index_offset];
21217                analog_y              = (float)ol_state->analog[index_offset + 1];
21218             }
21219             else
21220             {
21221                unsigned index        = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ?
21222                   RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT;
21223 
21224                analog_x              = input_state_internal(port, RETRO_DEVICE_ANALOG,
21225                      index, RETRO_DEVICE_ID_ANALOG_X);
21226                analog_y              = input_state_internal(port, RETRO_DEVICE_ANALOG,
21227                      index, RETRO_DEVICE_ID_ANALOG_Y);
21228             }
21229 
21230             dx = (analog_x / (float)0x8000) * (desc->range_x / 2.0f);
21231             dy = (analog_y / (float)0x8000) * (desc->range_y / 2.0f);
21232 
21233             /* Only modify overlay delta_x/delta_y values
21234              * if we are monitoring input from a physical
21235              * controller */
21236             if (!ol_state)
21237             {
21238                desc->delta_x = dx;
21239                desc->delta_y = dy;
21240             }
21241 
21242             /* Maybe use some option here instead of 0, only display
21243              * changes greater than some magnitude */
21244             if ((dx * dx) > 0 || (dy * dy) > 0)
21245                return true;
21246          }
21247          break;
21248 
21249       case OVERLAY_TYPE_KEYBOARD:
21250          if (ol_state ?
21251                OVERLAY_GET_KEY(ol_state, desc->retro_key_idx) :
21252                input_state_internal(port, RETRO_DEVICE_KEYBOARD, 0, desc->retro_key_idx))
21253          {
21254             desc->updated  = true;
21255             return true;
21256          }
21257          break;
21258 
21259       default:
21260          break;
21261    }
21262 
21263    return false;
21264 }
21265 
input_overlay_add_inputs(input_overlay_t * ol,bool show_touched,unsigned port)21266 static bool input_overlay_add_inputs(input_overlay_t *ol,
21267       bool show_touched, unsigned port)
21268 {
21269    unsigned i;
21270    bool button_pressed             = false;
21271    input_overlay_state_t *ol_state = &ol->overlay_state;
21272 
21273    if (!ol_state)
21274       return false;
21275 
21276    for (i = 0; i < ol->active->size; i++)
21277    {
21278       overlay_desc_t *desc  = &(ol->active->descs[i]);
21279       button_pressed       |= input_overlay_add_inputs_inner(desc,
21280             show_touched ? ol_state : NULL, port);
21281    }
21282 
21283    return button_pressed;
21284 }
21285 
input_overlay_parse_layout(const struct overlay * ol,const overlay_layout_desc_t * layout_desc,float display_aspect_ratio,overlay_layout_t * overlay_layout)21286 static void input_overlay_parse_layout(
21287       const struct overlay *ol,
21288       const overlay_layout_desc_t *layout_desc,
21289       float display_aspect_ratio,
21290       overlay_layout_t *overlay_layout)
21291 {
21292    /* Set default values */
21293    overlay_layout->x_scale      = 1.0f;
21294    overlay_layout->y_scale      = 1.0f;
21295    overlay_layout->x_separation = 0.0f;
21296    overlay_layout->y_separation = 0.0f;
21297    overlay_layout->x_offset     = 0.0f;
21298    overlay_layout->y_offset     = 0.0f;
21299 
21300    /* Perform auto-scaling, if required */
21301    if (layout_desc->auto_scale)
21302    {
21303       /* Sanity check - if scaling is blocked,
21304        * or aspect ratios are invalid, then we
21305        * can do nothing */
21306       if (ol->block_scale ||
21307           (ol->aspect_ratio <= 0.0f) ||
21308           (display_aspect_ratio <= 0.0f))
21309          return;
21310 
21311       /* If display is wider than overlay,
21312        * reduce width */
21313       if (display_aspect_ratio >
21314             ol->aspect_ratio)
21315       {
21316          overlay_layout->x_scale = ol->aspect_ratio /
21317                display_aspect_ratio;
21318 
21319          if (overlay_layout->x_scale <= 0.0f)
21320          {
21321             overlay_layout->x_scale = 1.0f;
21322             return;
21323          }
21324 
21325          /* If X separation is permitted, move elements
21326           * horizontally towards the edges of the screen */
21327          if (!ol->block_x_separation)
21328             overlay_layout->x_separation = ((1.0f / overlay_layout->x_scale) - 1.0f) * 0.5f;
21329       }
21330       /* If display is taller than overlay,
21331        * reduce height */
21332       else
21333       {
21334          overlay_layout->y_scale = display_aspect_ratio /
21335                ol->aspect_ratio;
21336 
21337          if (overlay_layout->y_scale <= 0.0f)
21338          {
21339             overlay_layout->y_scale = 1.0f;
21340             return;
21341          }
21342 
21343          /* If Y separation is permitted and display has
21344           * a *landscape* orientation, move elements
21345           * vertically towards the edges of the screen
21346           * > Portrait overlays typically have all elements
21347           *   below the centre line, so Y separation
21348           *   provides no real benefit */
21349          if ((display_aspect_ratio > 1.0f) &&
21350              !ol->block_y_separation)
21351             overlay_layout->y_separation = ((1.0f / overlay_layout->y_scale) - 1.0f) * 0.5f;
21352       }
21353 
21354       return;
21355    }
21356 
21357    /* Regular 'manual' scaling/position adjustment
21358     * > Landscape display orientations */
21359    if (display_aspect_ratio > 1.0f)
21360    {
21361       float scale         = layout_desc->scale_landscape;
21362       float aspect_adjust = layout_desc->aspect_adjust_landscape;
21363 
21364       /* Note: Y offsets have their sign inverted,
21365        * since from a usability perspective positive
21366        * values should move the overlay upwards */
21367       overlay_layout->x_offset = layout_desc->x_offset_landscape;
21368       overlay_layout->y_offset = layout_desc->y_offset_landscape * -1.0f;
21369 
21370       if (!ol->block_x_separation)
21371          overlay_layout->x_separation = layout_desc->x_separation_landscape;
21372       if (!ol->block_y_separation)
21373          overlay_layout->y_separation = layout_desc->y_separation_landscape;
21374 
21375       if (!ol->block_scale)
21376       {
21377          /* In landscape orientations, aspect correction
21378           * adjusts the overlay width */
21379          overlay_layout->x_scale = (aspect_adjust >= 0.0f) ?
21380                (scale * (aspect_adjust + 1.0f)) :
21381                (scale / ((aspect_adjust * -1.0f) + 1.0f));
21382          overlay_layout->y_scale = scale;
21383       }
21384    }
21385    /* > Portrait display orientations */
21386    else
21387    {
21388       float scale         = layout_desc->scale_portrait;
21389       float aspect_adjust = layout_desc->aspect_adjust_portrait;
21390 
21391       overlay_layout->x_offset = layout_desc->x_offset_portrait;
21392       overlay_layout->y_offset = layout_desc->y_offset_portrait * -1.0f;
21393 
21394       if (!ol->block_x_separation)
21395          overlay_layout->x_separation = layout_desc->x_separation_portrait;
21396       if (!ol->block_y_separation)
21397          overlay_layout->y_separation = layout_desc->y_separation_portrait;
21398 
21399       if (!ol->block_scale)
21400       {
21401          /* In portrait orientations, aspect correction
21402           * adjusts the overlay height */
21403          overlay_layout->x_scale = scale;
21404          overlay_layout->y_scale = (aspect_adjust >= 0.0f) ?
21405                (scale * (aspect_adjust + 1.0f)) :
21406                (scale / ((aspect_adjust * -1.0f) + 1.0f));
21407       }
21408    }
21409 }
21410 
21411 /**
21412  * input_overlay_scale:
21413  * @ol                    : Overlay handle.
21414  * @layout                : Scale + offset factors.
21415  *
21416  * Scales the overlay and all its associated descriptors
21417  * and applies any aspect ratio/offset factors.
21418  **/
input_overlay_scale(struct overlay * ol,const overlay_layout_t * layout)21419 static void input_overlay_scale(struct overlay *ol,
21420       const overlay_layout_t *layout)
21421 {
21422    size_t i;
21423 
21424    ol->mod_w = ol->w * layout->x_scale;
21425    ol->mod_h = ol->h * layout->y_scale;
21426    ol->mod_x = (ol->center_x + (ol->x - ol->center_x) *
21427          layout->x_scale) + layout->x_offset;
21428    ol->mod_y = (ol->center_y + (ol->y - ol->center_y) *
21429          layout->y_scale) + layout->y_offset;
21430 
21431    for (i = 0; i < ol->size; i++)
21432    {
21433       struct overlay_desc *desc = &ol->descs[i];
21434       float x_shift_offset      = 0.0f;
21435       float y_shift_offset      = 0.0f;
21436       float scale_w;
21437       float scale_h;
21438       float adj_center_x;
21439       float adj_center_y;
21440 
21441       /* Apply 'x separation' factor */
21442       if (desc->x < (0.5f - 0.0001f))
21443          x_shift_offset = layout->x_separation * -1.0f;
21444       else if (desc->x > (0.5f + 0.0001f))
21445          x_shift_offset = layout->x_separation;
21446 
21447       desc->x_shift = desc->x + x_shift_offset;
21448 
21449       /* Apply 'y separation' factor */
21450       if (desc->y < (0.5f - 0.0001f))
21451          y_shift_offset = layout->y_separation * -1.0f;
21452       else if (desc->y > (0.5f + 0.0001f))
21453          y_shift_offset = layout->y_separation;
21454 
21455       desc->y_shift = desc->y + y_shift_offset;
21456 
21457       scale_w       = ol->mod_w * desc->range_x;
21458       scale_h       = ol->mod_h * desc->range_y;
21459       adj_center_x  = ol->mod_x + desc->x_shift * ol->mod_w;
21460       adj_center_y  = ol->mod_y + desc->y_shift * ol->mod_h;
21461 
21462       desc->mod_w   = 2.0f * scale_w;
21463       desc->mod_h   = 2.0f * scale_h;
21464       desc->mod_x   = adj_center_x - scale_w;
21465       desc->mod_y   = adj_center_y - scale_h;
21466    }
21467 }
21468 
input_overlay_set_vertex_geom(input_overlay_t * ol)21469 static void input_overlay_set_vertex_geom(input_overlay_t *ol)
21470 {
21471    size_t i;
21472 
21473    if (ol->active->image.pixels)
21474       ol->iface->vertex_geom(ol->iface_data, 0,
21475             ol->active->mod_x, ol->active->mod_y,
21476             ol->active->mod_w, ol->active->mod_h);
21477 
21478    if (ol->iface->vertex_geom)
21479       for (i = 0; i < ol->active->size; i++)
21480       {
21481          struct overlay_desc *desc = &ol->active->descs[i];
21482 
21483          if (!desc->image.pixels)
21484             continue;
21485 
21486          ol->iface->vertex_geom(ol->iface_data, desc->image_index,
21487                desc->mod_x, desc->mod_y, desc->mod_w, desc->mod_h);
21488       }
21489 }
21490 
21491 /**
21492  * input_overlay_set_scale_factor:
21493  * @ol                    : Overlay handle.
21494  * @layout_desc           : Scale + offset factors.
21495  *
21496  * Scales the overlay and applies any aspect ratio/
21497  * offset factors.
21498  **/
input_overlay_set_scale_factor(struct rarch_state * p_rarch,input_overlay_t * ol,const overlay_layout_desc_t * layout_desc)21499 static void input_overlay_set_scale_factor(struct rarch_state *p_rarch,
21500       input_overlay_t *ol, const overlay_layout_desc_t *layout_desc)
21501 {
21502    float display_aspect_ratio = 0.0f;
21503    size_t i;
21504 
21505    if (!ol || !layout_desc)
21506       return;
21507 
21508    if (p_rarch->video_driver_height > 0)
21509       display_aspect_ratio = (float)p_rarch->video_driver_width /
21510             (float)p_rarch->video_driver_height;
21511 
21512    for (i = 0; i < ol->size; i++)
21513    {
21514       struct overlay *current_overlay = &ol->overlays[i];
21515       overlay_layout_t overlay_layout;
21516 
21517       input_overlay_parse_layout(current_overlay,
21518             layout_desc, display_aspect_ratio, &overlay_layout);
21519       input_overlay_scale(current_overlay, &overlay_layout);
21520    }
21521 
21522    input_overlay_set_vertex_geom(ol);
21523 }
21524 
input_overlay_free_overlay(struct overlay * overlay)21525 void input_overlay_free_overlay(struct overlay *overlay)
21526 {
21527    size_t i;
21528 
21529    if (!overlay)
21530       return;
21531 
21532    for (i = 0; i < overlay->size; i++)
21533       image_texture_free(&overlay->descs[i].image);
21534 
21535    if (overlay->load_images)
21536       free(overlay->load_images);
21537    overlay->load_images = NULL;
21538    if (overlay->descs)
21539       free(overlay->descs);
21540    overlay->descs       = NULL;
21541    image_texture_free(&overlay->image);
21542 }
21543 
input_overlay_free_overlays(input_overlay_t * ol)21544 static void input_overlay_free_overlays(input_overlay_t *ol)
21545 {
21546    size_t i;
21547 
21548    if (!ol || !ol->overlays)
21549       return;
21550 
21551    for (i = 0; i < ol->size; i++)
21552       input_overlay_free_overlay(&ol->overlays[i]);
21553 
21554    free(ol->overlays);
21555    ol->overlays = NULL;
21556 }
21557 
input_overlay_get_visibility(struct rarch_state * p_rarch,int overlay_idx)21558 static enum overlay_visibility input_overlay_get_visibility(
21559       struct rarch_state *p_rarch,
21560       int overlay_idx)
21561 {
21562    enum overlay_visibility *visibility = p_rarch->overlay_visibility;
21563 
21564     if (!visibility)
21565        return OVERLAY_VISIBILITY_DEFAULT;
21566     if ((overlay_idx < 0) || (overlay_idx >= MAX_VISIBILITY))
21567        return OVERLAY_VISIBILITY_DEFAULT;
21568     return visibility[overlay_idx];
21569 }
21570 
21571 
input_overlay_is_hidden(struct rarch_state * p_rarch,int overlay_idx)21572 static bool input_overlay_is_hidden(
21573       struct rarch_state *p_rarch,
21574       int overlay_idx)
21575 {
21576     return (input_overlay_get_visibility(p_rarch, overlay_idx)
21577           == OVERLAY_VISIBILITY_HIDDEN);
21578 }
21579 
21580 /**
21581  * input_overlay_set_alpha_mod:
21582  * @ol                    : Overlay handle.
21583  * @mod                   : New modulating factor to apply.
21584  *
21585  * Sets a modulating factor for alpha channel. Default is 1.0.
21586  * The alpha factor is applied for all overlays.
21587  **/
input_overlay_set_alpha_mod(struct rarch_state * p_rarch,input_overlay_t * ol,float mod)21588 static void input_overlay_set_alpha_mod(
21589       struct rarch_state *p_rarch,
21590       input_overlay_t *ol, float mod)
21591 {
21592    unsigned i;
21593 
21594    if (!ol)
21595       return;
21596 
21597    for (i = 0; i < ol->active->load_images_size; i++)
21598    {
21599       if (input_overlay_is_hidden(p_rarch, i))
21600           ol->iface->set_alpha(ol->iface_data, i, 0.0);
21601       else
21602           ol->iface->set_alpha(ol->iface_data, i, mod);
21603    }
21604 }
21605 
21606 
input_overlay_load_active(struct rarch_state * p_rarch,input_overlay_t * ol,float opacity)21607 static void input_overlay_load_active(
21608       struct rarch_state *p_rarch,
21609       input_overlay_t *ol, float opacity)
21610 {
21611    if (ol->iface->load)
21612       ol->iface->load(ol->iface_data, ol->active->load_images,
21613             ol->active->load_images_size);
21614 
21615    input_overlay_set_alpha_mod(p_rarch, ol, opacity);
21616    input_overlay_set_vertex_geom(ol);
21617 
21618    if (ol->iface->full_screen)
21619       ol->iface->full_screen(ol->iface_data, ol->active->full_screen);
21620 }
21621 
21622 /* Attempts to automatically rotate the specified overlay.
21623  * Depends upon proper naming conventions in overlay
21624  * config file. */
input_overlay_auto_rotate_(struct rarch_state * p_rarch,bool input_overlay_enable,input_overlay_t * ol)21625 static void input_overlay_auto_rotate_(
21626       struct rarch_state *p_rarch,
21627       bool input_overlay_enable,
21628       input_overlay_t *ol)
21629 {
21630    size_t i;
21631    enum overlay_orientation screen_orientation         = OVERLAY_ORIENTATION_PORTRAIT;
21632    enum overlay_orientation active_overlay_orientation = OVERLAY_ORIENTATION_NONE;
21633    bool tmp                                            = false;
21634 
21635    /* Sanity check */
21636    if (!ol || !ol->alive || !input_overlay_enable)
21637       return;
21638 
21639    /* Get current screen orientation */
21640    if (p_rarch->video_driver_width > p_rarch->video_driver_height)
21641       screen_orientation = OVERLAY_ORIENTATION_LANDSCAPE;
21642 
21643    /* Get orientation of active overlay */
21644    if (!string_is_empty(ol->active->name))
21645    {
21646       if (strstr(ol->active->name, "landscape"))
21647          active_overlay_orientation = OVERLAY_ORIENTATION_LANDSCAPE;
21648       else if (strstr(ol->active->name, "portrait"))
21649          active_overlay_orientation = OVERLAY_ORIENTATION_PORTRAIT;
21650    }
21651 
21652    /* Sanity check */
21653    if (active_overlay_orientation == OVERLAY_ORIENTATION_NONE)
21654       return;
21655 
21656    /* If screen and overlay have the same orientation,
21657     * no action is required */
21658    if (screen_orientation == active_overlay_orientation)
21659       return;
21660 
21661    /* Attempt to find index of overlay corresponding
21662     * to opposite orientation */
21663    for (i = 0; i < p_rarch->overlay_ptr->active->size; i++)
21664    {
21665       overlay_desc_t *desc = &p_rarch->overlay_ptr->active->descs[i];
21666 
21667       if (!desc)
21668          continue;
21669 
21670       if (!string_is_empty(desc->next_index_name))
21671       {
21672          bool next_overlay_found = false;
21673          if (active_overlay_orientation == OVERLAY_ORIENTATION_LANDSCAPE)
21674             next_overlay_found = (strstr(desc->next_index_name, "portrait") != 0);
21675          else
21676             next_overlay_found = (strstr(desc->next_index_name, "landscape") != 0);
21677 
21678          if (next_overlay_found)
21679          {
21680             /* We have a valid target overlay
21681              * > Trigger 'overly next' command event
21682              * Note: tmp == false. This prevents CMD_EVENT_OVERLAY_NEXT
21683              * from calling input_overlay_auto_rotate_() again */
21684             ol->next_index     = desc->next_index;
21685             command_event(CMD_EVENT_OVERLAY_NEXT, &tmp);
21686             break;
21687          }
21688       }
21689    }
21690 }
21691 
21692 /**
21693  * inside_hitbox:
21694  * @desc                  : Overlay descriptor handle.
21695  * @x                     : X coordinate value.
21696  * @y                     : Y coordinate value.
21697  *
21698  * Check whether the given @x and @y coordinates of the overlay
21699  * descriptor @desc is inside the overlay descriptor's hitbox.
21700  *
21701  * Returns: true (1) if X, Y coordinates are inside a hitbox,
21702  * otherwise false (0).
21703  **/
inside_hitbox(const struct overlay_desc * desc,float x,float y)21704 static bool inside_hitbox(const struct overlay_desc *desc, float x, float y)
21705 {
21706    if (!desc)
21707       return false;
21708 
21709    switch (desc->hitbox)
21710    {
21711       case OVERLAY_HITBOX_RADIAL:
21712       {
21713          /* Ellipsis. */
21714          float x_dist  = (x - desc->x_shift) / desc->range_x_mod;
21715          float y_dist  = (y - desc->y_shift) / desc->range_y_mod;
21716          float sq_dist = x_dist * x_dist + y_dist * y_dist;
21717          return (sq_dist <= 1.0f);
21718       }
21719 
21720       case OVERLAY_HITBOX_RECT:
21721          return
21722             (fabs(x - desc->x_shift) <= desc->range_x_mod) &&
21723             (fabs(y - desc->y_shift) <= desc->range_y_mod);
21724    }
21725 
21726    return false;
21727 }
21728 
21729 /**
21730  * input_overlay_poll:
21731  * @out                   : Polled output data.
21732  * @norm_x                : Normalized X coordinate.
21733  * @norm_y                : Normalized Y coordinate.
21734  *
21735  * Polls input overlay.
21736  *
21737  * @norm_x and @norm_y are the result of
21738  * input_translate_coord_viewport().
21739  **/
input_overlay_poll(input_overlay_t * ol,input_overlay_state_t * out,int16_t norm_x,int16_t norm_y,float touch_scale)21740 static void input_overlay_poll(
21741       input_overlay_t *ol,
21742       input_overlay_state_t *out,
21743       int16_t norm_x, int16_t norm_y, float touch_scale)
21744 {
21745    size_t i;
21746 
21747    /* norm_x and norm_y is in [-0x7fff, 0x7fff] range,
21748     * like RETRO_DEVICE_POINTER. */
21749    float x = (float)(norm_x + 0x7fff) / 0xffff;
21750    float y = (float)(norm_y + 0x7fff) / 0xffff;
21751 
21752    x -= ol->active->mod_x;
21753    y -= ol->active->mod_y;
21754    x /= ol->active->mod_w;
21755    y /= ol->active->mod_h;
21756 
21757    x *= touch_scale;
21758    y *= touch_scale;
21759 
21760    for (i = 0; i < ol->active->size; i++)
21761    {
21762       float x_dist, y_dist;
21763       unsigned int base         = 0;
21764       struct overlay_desc *desc = &ol->active->descs[i];
21765 
21766       if (!inside_hitbox(desc, x, y))
21767          continue;
21768 
21769       desc->updated = true;
21770       x_dist        = x - desc->x_shift;
21771       y_dist        = y - desc->y_shift;
21772 
21773       switch (desc->type)
21774       {
21775          case OVERLAY_TYPE_BUTTONS:
21776             {
21777                bits_or_bits(out->buttons.data,
21778                      desc->button_mask.data,
21779                      ARRAY_SIZE(desc->button_mask.data));
21780 
21781                if (BIT256_GET(desc->button_mask, RARCH_OVERLAY_NEXT))
21782                   ol->next_index = desc->next_index;
21783             }
21784             break;
21785          case OVERLAY_TYPE_KEYBOARD:
21786             if (desc->retro_key_idx < RETROK_LAST)
21787                OVERLAY_SET_KEY(out, desc->retro_key_idx);
21788             break;
21789          case OVERLAY_TYPE_ANALOG_RIGHT:
21790             base = 2;
21791             /* fall-through */
21792          default:
21793             {
21794                float x_val           = x_dist / desc->range_x;
21795                float y_val           = y_dist / desc->range_y;
21796                float x_val_sat       = x_val / desc->analog_saturate_pct;
21797                float y_val_sat       = y_val / desc->analog_saturate_pct;
21798                out->analog[base + 0] = clamp_float(x_val_sat, -1.0f, 1.0f)
21799                   * 32767.0f;
21800                out->analog[base + 1] = clamp_float(y_val_sat, -1.0f, 1.0f)
21801                   * 32767.0f;
21802             }
21803             break;
21804       }
21805 
21806       if (desc->movable)
21807       {
21808          desc->delta_x = clamp_float(x_dist, -desc->range_x, desc->range_x)
21809             * ol->active->mod_w;
21810          desc->delta_y = clamp_float(y_dist, -desc->range_y, desc->range_y)
21811             * ol->active->mod_h;
21812       }
21813    }
21814 
21815    if (!bits_any_set(out->buttons.data, ARRAY_SIZE(out->buttons.data)))
21816       ol->blocked = false;
21817    else if (ol->blocked)
21818       memset(out, 0, sizeof(*out));
21819 }
21820 
21821 /**
21822  * input_overlay_update_desc_geom:
21823  * @ol                    : overlay handle.
21824  * @desc                  : overlay descriptors handle.
21825  *
21826  * Update input overlay descriptors' vertex geometry.
21827  **/
input_overlay_update_desc_geom(input_overlay_t * ol,struct overlay_desc * desc)21828 static void input_overlay_update_desc_geom(input_overlay_t *ol,
21829       struct overlay_desc *desc)
21830 {
21831    if (!desc->image.pixels || !desc->movable)
21832       return;
21833 
21834    if (ol->iface->vertex_geom)
21835       ol->iface->vertex_geom(ol->iface_data, desc->image_index,
21836             desc->mod_x + desc->delta_x, desc->mod_y + desc->delta_y,
21837             desc->mod_w, desc->mod_h);
21838 
21839    desc->delta_x = 0.0f;
21840    desc->delta_y = 0.0f;
21841 }
21842 
21843 /**
21844  * input_overlay_post_poll:
21845  *
21846  * Called after all the input_overlay_poll() calls to
21847  * update the range modifiers for pressed/unpressed regions
21848  * and alpha mods.
21849  **/
input_overlay_post_poll(struct rarch_state * p_rarch,input_overlay_t * ol,bool show_input,float opacity)21850 static void input_overlay_post_poll(
21851       struct rarch_state *p_rarch, input_overlay_t *ol,
21852       bool show_input, float opacity)
21853 {
21854    size_t i;
21855 
21856    input_overlay_set_alpha_mod(p_rarch, ol, opacity);
21857 
21858    for (i = 0; i < ol->active->size; i++)
21859    {
21860       struct overlay_desc *desc = &ol->active->descs[i];
21861 
21862       desc->range_x_mod = desc->range_x;
21863       desc->range_y_mod = desc->range_y;
21864 
21865       if (desc->updated)
21866       {
21867          /* If pressed this frame, change the hitbox. */
21868          desc->range_x_mod *= desc->range_mod;
21869          desc->range_y_mod *= desc->range_mod;
21870 
21871          if (show_input && desc->image.pixels)
21872          {
21873             if (ol->iface->set_alpha)
21874                ol->iface->set_alpha(ol->iface_data, desc->image_index,
21875                      desc->alpha_mod * opacity);
21876          }
21877       }
21878 
21879       input_overlay_update_desc_geom(ol, desc);
21880       desc->updated = false;
21881    }
21882 }
21883 
21884 /**
21885  * input_overlay_poll_clear:
21886  * @ol                    : overlay handle
21887  *
21888  * Call when there is nothing to poll. Allows overlay to
21889  * clear certain state.
21890  **/
input_overlay_poll_clear(struct rarch_state * p_rarch,input_overlay_t * ol,float opacity)21891 static void input_overlay_poll_clear(
21892       struct rarch_state *p_rarch,
21893       input_overlay_t *ol, float opacity)
21894 {
21895    size_t i;
21896 
21897    ol->blocked = false;
21898 
21899    input_overlay_set_alpha_mod(p_rarch, ol, opacity);
21900 
21901    for (i = 0; i < ol->active->size; i++)
21902    {
21903       struct overlay_desc *desc = &ol->active->descs[i];
21904 
21905       desc->range_x_mod = desc->range_x;
21906       desc->range_y_mod = desc->range_y;
21907       desc->updated     = false;
21908 
21909       desc->delta_x     = 0.0f;
21910       desc->delta_y     = 0.0f;
21911       input_overlay_update_desc_geom(ol, desc);
21912    }
21913 }
21914 
21915 
21916 /**
21917  * input_overlay_free:
21918  * @ol                    : Overlay handle.
21919  *
21920  * Frees overlay handle.
21921  **/
input_overlay_free(input_overlay_t * ol)21922 static void input_overlay_free(input_overlay_t *ol)
21923 {
21924    if (!ol)
21925       return;
21926 
21927    input_overlay_free_overlays(ol);
21928 
21929    if (ol->iface->enable)
21930       ol->iface->enable(ol->iface_data, false);
21931 
21932    free(ol);
21933 }
21934 
21935 /* task_data = overlay_task_data_t* */
input_overlay_loaded(retro_task_t * task,void * task_data,void * user_data,const char * err)21936 static void input_overlay_loaded(retro_task_t *task,
21937       void *task_data, void *user_data, const char *err)
21938 {
21939    size_t i;
21940    struct rarch_state            *p_rarch = &rarch_st;
21941    overlay_task_data_t              *data = (overlay_task_data_t*)task_data;
21942    input_overlay_t                    *ol = NULL;
21943    const video_overlay_interface_t *iface = NULL;
21944    settings_t *settings                   = p_rarch->configuration_settings;
21945    bool input_overlay_show_mouse_cursor   = settings->bools.input_overlay_show_mouse_cursor;
21946    bool inp_overlay_auto_rotate           = settings->bools.input_overlay_auto_rotate;
21947    bool input_overlay_enable              = settings->bools.input_overlay_enable;
21948    if (err)
21949       return;
21950 
21951    if (data->overlay_enable)
21952    {
21953 #ifdef HAVE_MENU
21954       /* We can't display when the menu is up */
21955       if (data->hide_in_menu && p_rarch->menu_driver_alive)
21956          goto abort_load;
21957 #endif
21958 
21959       /* If 'hide_when_gamepad_connected' is enabled,
21960        * we can't display when a gamepad is connected */
21961       if (data->hide_when_gamepad_connected &&
21962           (input_config_get_device_name(0) != NULL))
21963          goto abort_load;
21964    }
21965 
21966    if (  !data->overlay_enable                   ||
21967          !video_driver_overlay_interface(&iface) ||
21968          !iface)
21969    {
21970       RARCH_ERR("Overlay interface is not present in video driver,"
21971             " or not enabled.\n");
21972       goto abort_load;
21973    }
21974 
21975    ol             = (input_overlay_t*)calloc(1, sizeof(*ol));
21976    ol->overlays   = data->overlays;
21977    ol->size       = data->size;
21978    ol->active     = data->active;
21979    ol->iface      = iface;
21980    ol->iface_data = p_rarch->video_driver_data;
21981 
21982    input_overlay_load_active(p_rarch, ol, data->overlay_opacity);
21983 
21984    /* Enable or disable the overlay. */
21985    ol->enable = data->overlay_enable;
21986 
21987    if (ol->iface->enable)
21988       ol->iface->enable(ol->iface_data, data->overlay_enable);
21989 
21990    input_overlay_set_scale_factor(p_rarch, ol, &data->layout_desc);
21991 
21992    ol->next_index = (unsigned)((ol->index + 1) % ol->size);
21993    ol->state      = OVERLAY_STATUS_NONE;
21994    ol->alive      = true;
21995 
21996    /* Due to the asynchronous nature of overlay loading
21997     * it is possible for overlay_ptr to be non-NULL here
21998     * > Ensure it is free()'d before assigning new pointer */
21999    if (p_rarch->overlay_ptr)
22000    {
22001       input_overlay_free_overlays(p_rarch->overlay_ptr);
22002       free(p_rarch->overlay_ptr);
22003    }
22004    p_rarch->overlay_ptr = ol;
22005 
22006    free(data);
22007 
22008    if (!input_overlay_show_mouse_cursor)
22009       video_driver_hide_mouse();
22010 
22011    /* Attempt to automatically rotate overlay, if required */
22012    if (inp_overlay_auto_rotate)
22013       input_overlay_auto_rotate_(p_rarch,
22014             input_overlay_enable,
22015             p_rarch->overlay_ptr);
22016 
22017    return;
22018 
22019 abort_load:
22020    for (i = 0; i < data->size; i++)
22021       input_overlay_free_overlay(&data->overlays[i]);
22022 
22023    free(data->overlays);
22024    free(data);
22025 }
22026 
input_overlay_set_visibility(int overlay_idx,enum overlay_visibility vis)22027 void input_overlay_set_visibility(int overlay_idx,
22028       enum overlay_visibility vis)
22029 {
22030    struct rarch_state         *p_rarch = &rarch_st;
22031    input_overlay_t                 *ol = p_rarch->overlay_ptr;
22032 
22033    if (!p_rarch->overlay_visibility)
22034    {
22035       unsigned i;
22036       p_rarch->overlay_visibility = (enum overlay_visibility *)calloc(
22037             MAX_VISIBILITY, sizeof(enum overlay_visibility));
22038 
22039       for (i = 0; i < MAX_VISIBILITY; i++)
22040          p_rarch->overlay_visibility[i] = OVERLAY_VISIBILITY_DEFAULT;
22041    }
22042 
22043    p_rarch->overlay_visibility[overlay_idx] = vis;
22044 
22045    if (!ol)
22046       return;
22047    if (vis == OVERLAY_VISIBILITY_HIDDEN)
22048       ol->iface->set_alpha(ol->iface_data, overlay_idx, 0.0);
22049 }
22050 
22051 
22052 /*
22053  * input_poll_overlay:
22054  *
22055  * Poll pressed buttons/keys on currently active overlay.
22056  **/
input_poll_overlay(struct rarch_state * p_rarch,settings_t * settings,input_overlay_t * ol,float opacity,unsigned analog_dpad_mode,float axis_threshold)22057 static void input_poll_overlay(
22058       struct rarch_state *p_rarch,
22059       settings_t *settings,
22060       input_overlay_t *ol, float opacity,
22061       unsigned analog_dpad_mode,
22062       float axis_threshold)
22063 {
22064    input_overlay_state_t old_key_state;
22065    unsigned i, j;
22066    uint16_t key_mod                        = 0;
22067    bool polled                             = false;
22068    bool button_pressed                     = false;
22069    void *input_data                        = p_rarch->current_input_data;
22070    input_overlay_state_t *ol_state         = &ol->overlay_state;
22071    input_driver_t *current_input           = p_rarch->current_input;
22072    enum overlay_show_input_type
22073          input_overlay_show_inputs         = (enum overlay_show_input_type)
22074                settings->uints.input_overlay_show_inputs;
22075    unsigned input_overlay_show_inputs_port = settings->uints.input_overlay_show_inputs_port;
22076    float touch_scale                       = (float)settings->uints.input_touch_scale;
22077 
22078    if (!ol_state)
22079       return;
22080 
22081    memcpy(old_key_state.keys, ol_state->keys,
22082          sizeof(ol_state->keys));
22083    memset(ol_state, 0, sizeof(*ol_state));
22084 
22085    if (current_input->input_state)
22086    {
22087       rarch_joypad_info_t joypad_info;
22088       unsigned device                 = ol->active->full_screen
22089          ? RARCH_DEVICE_POINTER_SCREEN
22090          : RETRO_DEVICE_POINTER;
22091 #ifdef HAVE_MFI
22092       const input_device_driver_t
22093          *sec_joypad                  = p_rarch->sec_joypad;
22094 #else
22095       const input_device_driver_t
22096          *sec_joypad                  = NULL;
22097 #endif
22098 
22099       joypad_info.joy_idx             = 0;
22100       joypad_info.auto_binds          = NULL;
22101       joypad_info.axis_threshold      = 0.0f;
22102 
22103       for (i = 0;
22104             current_input->input_state(
22105                input_data,
22106                p_rarch->joypad,
22107                sec_joypad,
22108                &joypad_info,
22109                NULL,
22110                p_rarch->keyboard_mapping_blocked,
22111                0,
22112                device,
22113                i,
22114                RETRO_DEVICE_ID_POINTER_PRESSED);
22115             i++)
22116       {
22117          input_overlay_state_t polled_data;
22118          int16_t x = current_input->input_state(
22119                input_data,
22120                p_rarch->joypad,
22121                sec_joypad,
22122                &joypad_info,
22123                NULL,
22124                p_rarch->keyboard_mapping_blocked,
22125                0,
22126                device,
22127                i,
22128                RETRO_DEVICE_ID_POINTER_X);
22129          int16_t y = current_input->input_state(
22130                input_data,
22131                p_rarch->joypad,
22132                sec_joypad,
22133                &joypad_info,
22134                NULL,
22135                p_rarch->keyboard_mapping_blocked,
22136                0,
22137                device,
22138                i,
22139                RETRO_DEVICE_ID_POINTER_Y);
22140 
22141          memset(&polled_data, 0, sizeof(struct input_overlay_state));
22142 
22143          if (ol->enable)
22144             input_overlay_poll(ol, &polled_data, x, y, touch_scale);
22145          else
22146             ol->blocked = false;
22147 
22148          bits_or_bits(ol_state->buttons.data,
22149                polled_data.buttons.data,
22150                ARRAY_SIZE(polled_data.buttons.data));
22151 
22152          for (j = 0; j < ARRAY_SIZE(ol_state->keys); j++)
22153             ol_state->keys[j] |= polled_data.keys[j];
22154 
22155          /* Fingers pressed later take priority and matched up
22156           * with overlay poll priorities. */
22157          for (j = 0; j < 4; j++)
22158             if (polled_data.analog[j])
22159                ol_state->analog[j] = polled_data.analog[j];
22160 
22161          polled = true;
22162       }
22163    }
22164 
22165    if (  OVERLAY_GET_KEY(ol_state, RETROK_LSHIFT) ||
22166          OVERLAY_GET_KEY(ol_state, RETROK_RSHIFT))
22167       key_mod |= RETROKMOD_SHIFT;
22168 
22169    if (OVERLAY_GET_KEY(ol_state, RETROK_LCTRL) ||
22170        OVERLAY_GET_KEY(ol_state, RETROK_RCTRL))
22171       key_mod |= RETROKMOD_CTRL;
22172 
22173    if (  OVERLAY_GET_KEY(ol_state, RETROK_LALT) ||
22174          OVERLAY_GET_KEY(ol_state, RETROK_RALT))
22175       key_mod |= RETROKMOD_ALT;
22176 
22177    if (  OVERLAY_GET_KEY(ol_state, RETROK_LMETA) ||
22178          OVERLAY_GET_KEY(ol_state, RETROK_RMETA))
22179       key_mod |= RETROKMOD_META;
22180 
22181    /* CAPSLOCK SCROLLOCK NUMLOCK */
22182    for (i = 0; i < ARRAY_SIZE(ol_state->keys); i++)
22183    {
22184       if (ol_state->keys[i] != old_key_state.keys[i])
22185       {
22186          uint32_t orig_bits = old_key_state.keys[i];
22187          uint32_t new_bits  = ol_state->keys[i];
22188 
22189          for (j = 0; j < 32; j++)
22190             if ((orig_bits & (1 << j)) != (new_bits & (1 << j)))
22191                input_keyboard_event(new_bits & (1 << j),
22192                      i * 32 + j, 0, key_mod, RETRO_DEVICE_POINTER);
22193       }
22194    }
22195 
22196    /* Map "analog" buttons to analog axes like regular input drivers do. */
22197    for (j = 0; j < 4; j++)
22198    {
22199       unsigned bind_plus  = RARCH_ANALOG_LEFT_X_PLUS + 2 * j;
22200       unsigned bind_minus = bind_plus + 1;
22201 
22202       if (ol_state->analog[j])
22203          continue;
22204 
22205       if ((BIT256_GET(ol->overlay_state.buttons, bind_plus)))
22206          ol_state->analog[j] += 0x7fff;
22207       if ((BIT256_GET(ol->overlay_state.buttons, bind_minus)))
22208          ol_state->analog[j] -= 0x7fff;
22209    }
22210 
22211    /* Check for analog_dpad_mode.
22212     * Map analogs to d-pad buttons when configured. */
22213    switch (analog_dpad_mode)
22214    {
22215       case ANALOG_DPAD_LSTICK:
22216       case ANALOG_DPAD_RSTICK:
22217       {
22218          float analog_x, analog_y;
22219          unsigned analog_base = 2;
22220 
22221          if (analog_dpad_mode == ANALOG_DPAD_LSTICK)
22222             analog_base = 0;
22223 
22224          analog_x = (float)ol_state->analog[analog_base + 0] / 0x7fff;
22225          analog_y = (float)ol_state->analog[analog_base + 1] / 0x7fff;
22226 
22227          if (analog_x <= -axis_threshold)
22228             BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_LEFT);
22229          if (analog_x >=  axis_threshold)
22230             BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_RIGHT);
22231          if (analog_y <= -axis_threshold)
22232             BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_UP);
22233          if (analog_y >=  axis_threshold)
22234             BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_DOWN);
22235          break;
22236       }
22237 
22238       default:
22239          break;
22240    }
22241 
22242    if (input_overlay_show_inputs != OVERLAY_SHOW_INPUT_NONE)
22243       button_pressed = input_overlay_add_inputs(ol,
22244             (input_overlay_show_inputs == OVERLAY_SHOW_INPUT_TOUCHED),
22245             input_overlay_show_inputs_port);
22246 
22247    if (button_pressed || polled)
22248       input_overlay_post_poll(p_rarch, ol, button_pressed, opacity);
22249    else
22250       input_overlay_poll_clear(p_rarch, ol, opacity);
22251 }
22252 
retroarch_overlay_deinit(struct rarch_state * p_rarch)22253 static void retroarch_overlay_deinit(struct rarch_state *p_rarch)
22254 {
22255    input_overlay_free(p_rarch->overlay_ptr);
22256    p_rarch->overlay_ptr = NULL;
22257 }
22258 
retroarch_overlay_init(struct rarch_state * p_rarch)22259 static void retroarch_overlay_init(struct rarch_state *p_rarch)
22260 {
22261    settings_t *settings                     = p_rarch->configuration_settings;
22262    bool input_overlay_enable                = settings->bools.input_overlay_enable;
22263    bool input_overlay_auto_scale            = settings->bools.input_overlay_auto_scale;
22264    const char *path_overlay                 = settings->paths.path_overlay;
22265    float overlay_opacity                    = settings->floats.input_overlay_opacity;
22266    float overlay_scale_landscape            = settings->floats.input_overlay_scale_landscape;
22267    float overlay_aspect_adjust_landscape    = settings->floats.input_overlay_aspect_adjust_landscape;
22268    float overlay_x_separation_landscape     = settings->floats.input_overlay_x_separation_landscape;
22269    float overlay_y_separation_landscape     = settings->floats.input_overlay_y_separation_landscape;
22270    float overlay_x_offset_landscape         = settings->floats.input_overlay_x_offset_landscape;
22271    float overlay_y_offset_landscape         = settings->floats.input_overlay_y_offset_landscape;
22272    float overlay_scale_portrait             = settings->floats.input_overlay_scale_portrait;
22273    float overlay_aspect_adjust_portrait     = settings->floats.input_overlay_aspect_adjust_portrait;
22274    float overlay_x_separation_portrait      = settings->floats.input_overlay_x_separation_portrait;
22275    float overlay_y_separation_portrait      = settings->floats.input_overlay_y_separation_portrait;
22276    float overlay_x_offset_portrait          = settings->floats.input_overlay_x_offset_portrait;
22277    float overlay_y_offset_portrait          = settings->floats.input_overlay_y_offset_portrait;
22278    float overlay_touch_scale                = (float)settings->uints.input_touch_scale;
22279 
22280    bool load_enabled                        = input_overlay_enable;
22281 #ifdef HAVE_MENU
22282    bool overlay_hide_in_menu                = settings->bools.input_overlay_hide_in_menu;
22283 #else
22284    bool overlay_hide_in_menu                = false;
22285 #endif
22286    bool overlay_hide_when_gamepad_connected = settings->bools.input_overlay_hide_when_gamepad_connected;
22287 #if defined(GEKKO)
22288    /* Avoid a crash at startup or even when toggling overlay in rgui */
22289    uint64_t memory_free                     = frontend_driver_get_free_memory();
22290    if (memory_free < (3 * 1024 * 1024))
22291       return;
22292 #endif
22293 
22294    retroarch_overlay_deinit(p_rarch);
22295 
22296 #ifdef HAVE_MENU
22297    /* Cancel load if 'hide_in_menu' is enabled and
22298     * menu is currently active */
22299    if (overlay_hide_in_menu)
22300       load_enabled = load_enabled && !p_rarch->menu_driver_alive;
22301 #endif
22302 
22303    /* Cancel load if 'hide_when_gamepad_connected' is
22304     * enabled and a gamepad is currently connected */
22305    if (overlay_hide_when_gamepad_connected)
22306       load_enabled = load_enabled && (input_config_get_device_name(0) == NULL);
22307 
22308    if (load_enabled)
22309    {
22310       overlay_layout_desc_t layout_desc;
22311 
22312       layout_desc.scale_landscape         = overlay_scale_landscape;
22313       layout_desc.aspect_adjust_landscape = overlay_aspect_adjust_landscape;
22314       layout_desc.x_separation_landscape  = overlay_x_separation_landscape;
22315       layout_desc.y_separation_landscape  = overlay_y_separation_landscape;
22316       layout_desc.x_offset_landscape      = overlay_x_offset_landscape;
22317       layout_desc.y_offset_landscape      = overlay_y_offset_landscape;
22318       layout_desc.scale_portrait          = overlay_scale_portrait;
22319       layout_desc.aspect_adjust_portrait  = overlay_aspect_adjust_portrait;
22320       layout_desc.x_separation_portrait   = overlay_x_separation_portrait;
22321       layout_desc.y_separation_portrait   = overlay_y_separation_portrait;
22322       layout_desc.x_offset_portrait       = overlay_x_offset_portrait;
22323       layout_desc.y_offset_portrait       = overlay_y_offset_portrait;
22324       layout_desc.touch_scale             = overlay_touch_scale;
22325       layout_desc.auto_scale              = input_overlay_auto_scale;
22326 
22327       task_push_overlay_load_default(input_overlay_loaded,
22328             path_overlay,
22329             overlay_hide_in_menu,
22330             overlay_hide_when_gamepad_connected,
22331             input_overlay_enable,
22332             overlay_opacity,
22333             &layout_desc,
22334             NULL);
22335    }
22336 }
22337 #endif
22338 
22339 /* INPUT REMOTE */
22340 
22341 #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
input_remote_init_network(input_remote_t * handle,uint16_t port,unsigned user)22342 static bool input_remote_init_network(input_remote_t *handle,
22343       uint16_t port, unsigned user)
22344 {
22345    int fd;
22346    struct addrinfo *res  = NULL;
22347 
22348    port = port + user;
22349 
22350    if (!network_init())
22351       return false;
22352 
22353    RARCH_LOG("Bringing up remote interface on port %hu.\n",
22354          (unsigned short)port);
22355 
22356    fd = socket_init((void**)&res, port, NULL, SOCKET_TYPE_DATAGRAM);
22357 
22358    if (fd < 0)
22359       goto error;
22360 
22361    handle->net_fd[user] = fd;
22362 
22363    if (!socket_nonblock(handle->net_fd[user]))
22364       goto error;
22365 
22366    if (!socket_bind(handle->net_fd[user], res))
22367    {
22368       RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_BIND_SOCKET));
22369       goto error;
22370    }
22371 
22372    freeaddrinfo_retro(res);
22373    return true;
22374 
22375 error:
22376    if (res)
22377       freeaddrinfo_retro(res);
22378    return false;
22379 }
22380 
input_remote_free(input_remote_t * handle,unsigned max_users)22381 static void input_remote_free(input_remote_t *handle, unsigned max_users)
22382 {
22383    unsigned user;
22384    for (user = 0; user < max_users; user ++)
22385       socket_close(handle->net_fd[user]);
22386 
22387    free(handle);
22388 }
22389 
input_remote_new(settings_t * settings,uint16_t port,unsigned max_users)22390 static input_remote_t *input_remote_new(
22391       settings_t *settings,
22392       uint16_t port, unsigned max_users)
22393 {
22394    unsigned user;
22395    input_remote_t      *handle = (input_remote_t*)
22396       calloc(1, sizeof(*handle));
22397 
22398    if (!handle)
22399       return NULL;
22400 
22401    for (user = 0; user < max_users; user ++)
22402    {
22403       handle->net_fd[user] = -1;
22404       if (settings->bools.network_remote_enable_user[user])
22405          if (!input_remote_init_network(handle, port, user))
22406          {
22407             input_remote_free(handle, max_users);
22408             return NULL;
22409          }
22410    }
22411 
22412    return handle;
22413 }
22414 
input_remote_parse_packet(input_remote_state_t * input_state,struct remote_message * msg,unsigned user)22415 static void input_remote_parse_packet(
22416       input_remote_state_t *input_state,
22417       struct remote_message *msg, unsigned user)
22418 {
22419    /* Parse message */
22420    switch (msg->device)
22421    {
22422       case RETRO_DEVICE_JOYPAD:
22423          input_state->buttons[user] &= ~(1 << msg->id);
22424          if (msg->state)
22425             input_state->buttons[user] |= 1 << msg->id;
22426          break;
22427       case RETRO_DEVICE_ANALOG:
22428          input_state->analog[msg->index * 2 + msg->id][user] = msg->state;
22429          break;
22430    }
22431 }
22432 #endif
22433 
22434 /* INPUT */
22435 
set_connection_listener(pad_connection_listener_t * listener)22436 void set_connection_listener(pad_connection_listener_t *listener)
22437 {
22438    struct rarch_state *p_rarch      = &rarch_st;
22439    p_rarch->pad_connection_listener = listener;
22440 }
22441 
22442 /**
22443  * config_get_input_driver_options:
22444  *
22445  * Get an enumerated list of all input driver names, separated by '|'.
22446  *
22447  * Returns: string listing of all input driver names, separated by '|'.
22448  **/
config_get_input_driver_options(void)22449 const char* config_get_input_driver_options(void)
22450 {
22451    return char_list_new_special(STRING_LIST_INPUT_DRIVERS, NULL);
22452 }
22453 
22454 /**
22455  * input_driver_set_rumble_state:
22456  * @port               : User number.
22457  * @effect             : Rumble effect.
22458  * @strength           : Strength of rumble effect.
22459  *
22460  * Sets the rumble state.
22461  * Used by RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE.
22462  **/
input_driver_set_rumble_state(unsigned port,enum retro_rumble_effect effect,uint16_t strength)22463 bool input_driver_set_rumble_state(unsigned port,
22464       enum retro_rumble_effect effect, uint16_t strength)
22465 {
22466    struct rarch_state *p_rarch             = &rarch_st;
22467    settings_t *settings                    = p_rarch->configuration_settings;
22468 #ifdef HAVE_MFI
22469    const input_device_driver_t *sec_joypad = p_rarch->sec_joypad;
22470 #else
22471    const input_device_driver_t *sec_joypad = NULL;
22472 #endif
22473    bool rumble_state                       = false;
22474    unsigned  joy_idx                       = settings->uints.input_joypad_index[port];
22475 
22476    if (joy_idx >= MAX_USERS)
22477       return false;
22478    if (p_rarch->joypad && p_rarch->joypad->set_rumble)
22479       rumble_state = p_rarch->joypad->set_rumble(
22480             joy_idx, effect, strength);
22481    if (sec_joypad      && sec_joypad->set_rumble)
22482       rumble_state = sec_joypad->set_rumble(
22483             joy_idx, effect, strength);
22484    return rumble_state;
22485 }
22486 
joypad_driver_name(unsigned i)22487 const char *joypad_driver_name(unsigned i)
22488 {
22489    struct rarch_state     *p_rarch = &rarch_st;
22490    if (!p_rarch || !p_rarch->joypad || !p_rarch->joypad->name)
22491       return NULL;
22492    return p_rarch->joypad->name(i);
22493 }
22494 
joypad_driver_reinit(void * data,const char * joypad_driver_name)22495 void joypad_driver_reinit(void *data, const char *joypad_driver_name)
22496 {
22497    struct rarch_state     *p_rarch = &rarch_st;
22498    if (!p_rarch)
22499       return;
22500 
22501    if (p_rarch->joypad)
22502       p_rarch->joypad->destroy();
22503    p_rarch->joypad = NULL;
22504 #ifdef HAVE_MFI
22505    if (p_rarch->sec_joypad)
22506       p_rarch->sec_joypad->destroy();
22507    p_rarch->sec_joypad = NULL;
22508 #endif
22509    p_rarch->joypad     = input_joypad_init_driver(joypad_driver_name, data);
22510 #ifdef HAVE_MFI
22511    p_rarch->sec_joypad = input_joypad_init_driver("mfi", data);
22512 #endif
22513 }
22514 
input_driver_get_capabilities(void)22515 static uint64_t input_driver_get_capabilities(void)
22516 {
22517    struct rarch_state *p_rarch = &rarch_st;
22518    if (!p_rarch->current_input || !p_rarch->current_input->get_capabilities)
22519       return 0;
22520    return p_rarch->current_input->get_capabilities(p_rarch->current_input_data);
22521 }
22522 
22523 /**
22524  * input_sensor_set_state:
22525  * @port               : User number.
22526  * @effect             : Sensor action.
22527  * @rate               : Sensor rate update.
22528  *
22529  * Sets the sensor state.
22530  * Used by RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE.
22531  **/
input_sensor_set_state(unsigned port,enum retro_sensor_action action,unsigned rate)22532 bool input_sensor_set_state(unsigned port,
22533       enum retro_sensor_action action, unsigned rate)
22534 {
22535    struct rarch_state *p_rarch = &rarch_st;
22536    settings_t *settings        = p_rarch->configuration_settings;
22537    bool input_sensors_enable   = settings->bools.input_sensors_enable;
22538 
22539    /* If sensors are disabled, inhibit any enable
22540     * actions (but always allow disable actions) */
22541    if (!input_sensors_enable &&
22542        ((action == RETRO_SENSOR_ACCELEROMETER_ENABLE) ||
22543         (action == RETRO_SENSOR_GYROSCOPE_ENABLE) ||
22544         (action == RETRO_SENSOR_ILLUMINANCE_ENABLE)))
22545       return false;
22546 
22547    if (p_rarch->current_input_data &&
22548          p_rarch->current_input->set_sensor_state)
22549       return p_rarch->current_input->set_sensor_state(p_rarch->current_input_data,
22550             port, action, rate);
22551    return false;
22552 }
22553 
input_sensor_get_input(unsigned port,unsigned id)22554 float input_sensor_get_input(unsigned port, unsigned id)
22555 {
22556    struct rarch_state *p_rarch = &rarch_st;
22557    settings_t *settings        = p_rarch->configuration_settings;
22558    bool input_sensors_enable   = settings->bools.input_sensors_enable;
22559 
22560    if (input_sensors_enable &&
22561        p_rarch->current_input_data &&
22562        p_rarch->current_input->get_sensor_input)
22563       return p_rarch->current_input->get_sensor_input(p_rarch->current_input_data,
22564             port, id);
22565    return 0.0f;
22566 }
22567 
22568 /**
22569  * input_poll:
22570  *
22571  * Input polling callback function.
22572  **/
input_driver_poll(void)22573 static void input_driver_poll(void)
22574 {
22575    size_t i, j;
22576    rarch_joypad_info_t joypad_info[MAX_USERS];
22577    struct rarch_state    *p_rarch = &rarch_st;
22578    settings_t *settings           = p_rarch->configuration_settings;
22579 #ifdef HAVE_MFI
22580    const input_device_driver_t
22581       *sec_joypad                 = p_rarch->sec_joypad;
22582 #else
22583    const input_device_driver_t
22584       *sec_joypad                 = NULL;
22585 #endif
22586 #ifdef HAVE_OVERLAY
22587    float input_overlay_opacity    = settings->floats.input_overlay_opacity;
22588 #endif
22589    bool input_remap_binds_enable  = settings->bools.input_remap_binds_enable;
22590    uint8_t max_users              = (uint8_t)p_rarch->input_driver_max_users;
22591 
22592    if (     p_rarch->joypad
22593          && p_rarch->joypad->poll)
22594       p_rarch->joypad->poll();
22595 #ifdef HAVE_MFI
22596    if (     p_rarch->sec_joypad
22597          && p_rarch->sec_joypad->poll)
22598       p_rarch->sec_joypad->poll();
22599 #endif
22600    if (     p_rarch->current_input
22601          && p_rarch->current_input->poll)
22602       p_rarch->current_input->poll(p_rarch->current_input_data);
22603 
22604    p_rarch->input_driver_turbo_btns.count++;
22605 
22606    if (p_rarch->input_driver_block_libretro_input)
22607    {
22608       for (i = 0; i < max_users; i++)
22609          p_rarch->input_driver_turbo_btns.frame_enable[i] = 0;
22610       return;
22611    }
22612 
22613    /* This rarch_joypad_info_t struct contains the device index + autoconfig binds for the
22614     * controller to be queried, and also (for unknown reasons) the analog axis threshold
22615     * when mapping analog stick to dpad input. */
22616    for (i = 0; i < max_users; i++)
22617    {
22618       joypad_info[i].axis_threshold              = p_rarch->input_driver_axis_threshold;
22619       joypad_info[i].joy_idx                     = settings->uints.input_joypad_index[i];
22620       joypad_info[i].auto_binds                  = input_autoconf_binds[joypad_info[i].joy_idx];
22621 
22622       p_rarch->input_driver_turbo_btns.frame_enable[i] = p_rarch->libretro_input_binds[i][RARCH_TURBO_ENABLE].valid ?
22623          input_state_wrap(
22624                p_rarch->current_input,
22625                p_rarch->current_input_data,
22626                p_rarch->joypad,
22627                sec_joypad,
22628                &joypad_info[i],
22629                p_rarch->libretro_input_binds,
22630                p_rarch->keyboard_mapping_blocked,
22631                (unsigned)i,
22632                RETRO_DEVICE_JOYPAD,
22633                0,
22634                RARCH_TURBO_ENABLE) : 0;
22635    }
22636 
22637 #ifdef HAVE_OVERLAY
22638    if (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive)
22639    {
22640       unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[0];
22641 
22642       switch (input_analog_dpad_mode)
22643       {
22644          case ANALOG_DPAD_LSTICK:
22645          case ANALOG_DPAD_RSTICK:
22646             {
22647                unsigned mapped_port = settings->uints.input_remap_ports[0];
22648 
22649                if (p_rarch->input_driver_analog_requested[mapped_port])
22650                   input_analog_dpad_mode = ANALOG_DPAD_NONE;
22651             }
22652             break;
22653          case ANALOG_DPAD_LSTICK_FORCED:
22654             input_analog_dpad_mode = ANALOG_DPAD_LSTICK;
22655             break;
22656          case ANALOG_DPAD_RSTICK_FORCED:
22657             input_analog_dpad_mode = ANALOG_DPAD_RSTICK;
22658             break;
22659          default:
22660             break;
22661       }
22662 
22663       input_poll_overlay(p_rarch,
22664             settings,
22665             p_rarch->overlay_ptr,
22666             input_overlay_opacity,
22667             input_analog_dpad_mode,
22668             p_rarch->input_driver_axis_threshold);
22669    }
22670 #endif
22671 
22672 #ifdef HAVE_MENU
22673    if (!p_rarch->menu_driver_alive)
22674 #endif
22675    if (input_remap_binds_enable)
22676    {
22677 #ifdef HAVE_OVERLAY
22678       input_overlay_t *overlay_pointer = (input_overlay_t*)p_rarch->overlay_ptr;
22679       bool poll_overlay                = (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive);
22680 #endif
22681       input_mapper_t *handle           = &p_rarch->input_driver_mapper;
22682       const input_device_driver_t *joypad_driver
22683                                        = p_rarch->joypad;
22684       float input_analog_deadzone      = settings->floats.input_analog_deadzone;
22685       float input_analog_sensitivity   = settings->floats.input_analog_sensitivity;
22686 
22687       for (i = 0; i < max_users; i++)
22688       {
22689          input_bits_t current_inputs;
22690          unsigned mapped_port            = settings->uints.input_remap_ports[i];
22691          unsigned device                 = settings->uints.input_libretro_device[mapped_port]
22692                                            & RETRO_DEVICE_MASK;
22693          input_bits_t *p_new_state       = (input_bits_t*)&current_inputs;
22694          unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[i];
22695 
22696          switch (input_analog_dpad_mode)
22697          {
22698             case ANALOG_DPAD_LSTICK:
22699             case ANALOG_DPAD_RSTICK:
22700                if (p_rarch->input_driver_analog_requested[mapped_port])
22701                   input_analog_dpad_mode = ANALOG_DPAD_NONE;
22702                break;
22703             case ANALOG_DPAD_LSTICK_FORCED:
22704                input_analog_dpad_mode = ANALOG_DPAD_LSTICK;
22705                break;
22706             case ANALOG_DPAD_RSTICK_FORCED:
22707                input_analog_dpad_mode = ANALOG_DPAD_RSTICK;
22708                break;
22709             default:
22710                break;
22711          }
22712 
22713          switch (device)
22714          {
22715             case RETRO_DEVICE_KEYBOARD:
22716             case RETRO_DEVICE_JOYPAD:
22717             case RETRO_DEVICE_ANALOG:
22718                BIT256_CLEAR_ALL_PTR(&current_inputs);
22719                if (joypad_driver)
22720                {
22721                   unsigned k, j;
22722                   int16_t ret = input_state_wrap(
22723                         p_rarch->current_input,
22724                         p_rarch->current_input_data,
22725                         p_rarch->joypad,
22726                         sec_joypad,
22727                         &joypad_info[i],
22728                         p_rarch->libretro_input_binds,
22729                         p_rarch->keyboard_mapping_blocked,
22730                         (unsigned)i, RETRO_DEVICE_JOYPAD,
22731                         0, RETRO_DEVICE_ID_JOYPAD_MASK);
22732 
22733                   for (k = 0; k < RARCH_FIRST_CUSTOM_BIND; k++)
22734                   {
22735                      if (ret & (1 << k))
22736                      {
22737                         bool valid_bind  =
22738                            p_rarch->libretro_input_binds[i][k].valid;
22739 
22740                         if (valid_bind)
22741                         {
22742                            int16_t   val =
22743                               input_joypad_analog_button(
22744                                     input_analog_deadzone,
22745                                     input_analog_sensitivity,
22746                                     joypad_driver, &joypad_info[i],
22747                                     k,
22748                                     &p_rarch->libretro_input_binds[i][k]
22749                                     );
22750                            if (val)
22751                               p_new_state->analog_buttons[k] = val;
22752                         }
22753 
22754                         BIT256_SET_PTR(p_new_state, k);
22755                      }
22756                   }
22757 
22758                   /* This is the analog joypad index -
22759                    * handles only the two analog axes */
22760                   for (k = 0; k < 2; k++)
22761                   {
22762                      /* This is the analog joypad ident */
22763                      for (j = 0; j < 2; j++)
22764                      {
22765                         unsigned offset = 0 + (k * 4) + (j * 2);
22766                         int16_t     val = input_joypad_analog_axis(
22767                               input_analog_dpad_mode,
22768                               input_analog_deadzone,
22769                               input_analog_sensitivity,
22770                               joypad_driver,
22771                               &joypad_info[i],
22772                               k,
22773                               j,
22774                               p_rarch->libretro_input_binds[i]);
22775 
22776                         if (val >= 0)
22777                            p_new_state->analogs[offset]   = val;
22778                         else
22779                            p_new_state->analogs[offset+1] = val;
22780                      }
22781                   }
22782                }
22783                break;
22784             default:
22785                break;
22786          }
22787 
22788          /* mapper */
22789          switch (device)
22790          {
22791             /* keyboard to gamepad remapping */
22792             case RETRO_DEVICE_KEYBOARD:
22793                for (j = 0; j < RARCH_CUSTOM_BIND_LIST_END; j++)
22794                {
22795                   unsigned current_button_value;
22796                   unsigned remap_key =
22797                         settings->uints.input_keymapper_ids[i][j];
22798 
22799                   if (remap_key == RETROK_UNKNOWN)
22800                      continue;
22801 
22802                   if (j >= RARCH_FIRST_CUSTOM_BIND && j < RARCH_ANALOG_BIND_LIST_END)
22803                   {
22804                      int16_t current_axis_value = p_new_state->analogs[j - RARCH_FIRST_CUSTOM_BIND];
22805                      current_button_value = abs(current_axis_value) >
22806                            p_rarch->input_driver_axis_threshold
22807                             * 32767;
22808                   }
22809                   else
22810                   {
22811                      current_button_value =
22812                         BIT256_GET_PTR(p_new_state, j);
22813                   }
22814 
22815 #ifdef HAVE_OVERLAY
22816                   if (poll_overlay && i == 0)
22817                   {
22818                      input_overlay_state_t *ol_state  =
22819                         overlay_pointer
22820                         ? &overlay_pointer->overlay_state
22821                         : NULL;
22822                      if (ol_state)
22823                         current_button_value |=
22824                            BIT256_GET(ol_state->buttons, j);
22825                   }
22826 #endif
22827                   /* Press */
22828                   if ((current_button_value == 1)
22829                         && !MAPPER_GET_KEY(handle, remap_key))
22830                   {
22831                      handle->key_button[remap_key] = (unsigned)j;
22832 
22833                      MAPPER_SET_KEY(handle, remap_key);
22834                      input_keyboard_event(true,
22835                            remap_key,
22836                            0, 0, RETRO_DEVICE_KEYBOARD);
22837                   }
22838                   /* Release */
22839                   else if ((current_button_value == 0)
22840                         && MAPPER_GET_KEY(handle, remap_key))
22841                   {
22842                      if (handle->key_button[remap_key] != j)
22843                         continue;
22844 
22845                      input_keyboard_event(false,
22846                            remap_key,
22847                            0, 0, RETRO_DEVICE_KEYBOARD);
22848                      MAPPER_UNSET_KEY(handle, remap_key);
22849                   }
22850                }
22851                break;
22852 
22853                /* gamepad remapping */
22854             case RETRO_DEVICE_JOYPAD:
22855             case RETRO_DEVICE_ANALOG:
22856                /* this loop iterates on all users and all buttons,
22857                 * and checks if a pressed button is assigned to any
22858                 * other button than the default one, then it sets
22859                 * the bit on the mapper input bitmap, later on the
22860                 * original input is cleared in input_state */
22861                BIT256_CLEAR_ALL(handle->buttons[i]);
22862 
22863                for (j = 0; j < 8; j++)
22864                   handle->analog_value[i][j] = 0;
22865 
22866                for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++)
22867                {
22868                   bool remap_valid;
22869                   unsigned remap_button         =
22870                         settings->uints.input_remap_ids[i][j];
22871                   unsigned current_button_value =
22872                         BIT256_GET_PTR(p_new_state, j);
22873 
22874 #ifdef HAVE_OVERLAY
22875                   if (poll_overlay && i == 0)
22876                   {
22877                      input_overlay_state_t *ol_state  =
22878                         overlay_pointer
22879                         ? &overlay_pointer->overlay_state
22880                         : NULL;
22881                      if (ol_state)
22882                         current_button_value            |=
22883                            BIT256_GET(ol_state->buttons, j);
22884                   }
22885 #endif
22886                   remap_valid                   =
22887                      (current_button_value == 1) &&
22888                      (j != remap_button)         &&
22889                      (remap_button != RARCH_UNMAPPED);
22890 
22891 #ifdef HAVE_ACCESSIBILITY
22892                   /* gamepad override */
22893                   if (i == 0 &&
22894                         p_rarch->gamepad_input_override & (1 << j))
22895                   {
22896                      BIT256_SET(handle->buttons[i], j);
22897                   }
22898 #endif
22899 
22900                   if (remap_valid)
22901                   {
22902                      if (remap_button < RARCH_FIRST_CUSTOM_BIND)
22903                      {
22904                         BIT256_SET(handle->buttons[i], remap_button);
22905                      }
22906                      else
22907                      {
22908                         int invert = 1;
22909 
22910                         if (remap_button % 2 != 0)
22911                            invert = -1;
22912 
22913                         handle->analog_value[i][
22914                            remap_button - RARCH_FIRST_CUSTOM_BIND] =
22915                               (p_new_state->analog_buttons[j]
22916                                ? p_new_state->analog_buttons[j]
22917                                : 32767) * invert;
22918                      }
22919                   }
22920                }
22921 
22922                for (j = 0; j < 8; j++)
22923                {
22924                   unsigned k                 = (unsigned)j + RARCH_FIRST_CUSTOM_BIND;
22925                   int16_t current_axis_value = p_new_state->analogs[j];
22926                   unsigned remap_axis        = settings->uints.input_remap_ids[i][k];
22927 
22928                   if (
22929                         (abs(current_axis_value) > 0 &&
22930                          (k != remap_axis)            &&
22931                          (remap_axis != RARCH_UNMAPPED)
22932                         ))
22933                   {
22934                      if (remap_axis < RARCH_FIRST_CUSTOM_BIND &&
22935                            abs(current_axis_value) >
22936                            p_rarch->input_driver_axis_threshold
22937                             * 32767)
22938                      {
22939                         BIT256_SET(handle->buttons[i], remap_axis);
22940                      }
22941                      else
22942                      {
22943                         unsigned remap_axis_bind =
22944                            remap_axis - RARCH_FIRST_CUSTOM_BIND;
22945 
22946                         if (remap_axis_bind < sizeof(handle->analog_value[i]))
22947                         {
22948                            int invert = 1;
22949                            if (  (k % 2 == 0 && remap_axis % 2 != 0) ||
22950                                  (k % 2 != 0 && remap_axis % 2 == 0)
22951                               )
22952                               invert = -1;
22953 
22954                            handle->analog_value[i][
22955                               remap_axis_bind] =
22956                                  current_axis_value * invert;
22957                         }
22958                      }
22959                   }
22960 
22961                }
22962                break;
22963             default:
22964                break;
22965          }
22966       }
22967    }
22968 
22969 #ifdef HAVE_COMMAND
22970    for (i = 0; i < ARRAY_SIZE(p_rarch->input_driver_command); i++)
22971    {
22972       if (p_rarch->input_driver_command[i])
22973       {
22974          memset(p_rarch->input_driver_command[i]->state,
22975                 0, sizeof(p_rarch->input_driver_command[i]->state));
22976 
22977          p_rarch->input_driver_command[i]->poll(
22978             p_rarch->input_driver_command[i]);
22979       }
22980    }
22981 #endif
22982 
22983 #ifdef HAVE_NETWORKGAMEPAD
22984    /* Poll remote */
22985    if (p_rarch->input_driver_remote)
22986    {
22987       unsigned user;
22988 
22989       for (user = 0; user < max_users; user++)
22990       {
22991          if (settings->bools.network_remote_enable_user[user])
22992          {
22993 #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
22994             fd_set fds;
22995             ssize_t ret;
22996             struct remote_message msg;
22997 
22998             if (p_rarch->input_driver_remote->net_fd[user] < 0)
22999                return;
23000 
23001             FD_ZERO(&fds);
23002             FD_SET(p_rarch->input_driver_remote->net_fd[user], &fds);
23003 
23004             ret = recvfrom(p_rarch->input_driver_remote->net_fd[user],
23005                   (char*)&msg,
23006                   sizeof(msg), 0, NULL, NULL);
23007 
23008             if (ret == sizeof(msg))
23009                input_remote_parse_packet(&p_rarch->remote_st_ptr, &msg, user);
23010             else if ((ret != -1) || ((errno != EAGAIN) && (errno != ENOENT)))
23011 #endif
23012             {
23013                input_remote_state_t *input_state  = &p_rarch->remote_st_ptr;
23014                input_state->buttons[user]         = 0;
23015                input_state->analog[0][user]       = 0;
23016                input_state->analog[1][user]       = 0;
23017                input_state->analog[2][user]       = 0;
23018                input_state->analog[3][user]       = 0;
23019             }
23020          }
23021       }
23022    }
23023 #endif
23024 }
23025 
input_state_device(struct rarch_state * p_rarch,settings_t * settings,input_mapper_t * handle,unsigned input_analog_dpad_mode,int16_t ret,unsigned port,unsigned device,unsigned idx,unsigned id,bool button_mask)23026 static int16_t input_state_device(
23027       struct rarch_state *p_rarch,
23028       settings_t *settings,
23029       input_mapper_t *handle,
23030       unsigned input_analog_dpad_mode,
23031       int16_t ret,
23032       unsigned port, unsigned device,
23033       unsigned idx, unsigned id,
23034       bool button_mask)
23035 {
23036    int16_t res = 0;
23037 
23038    switch (device)
23039    {
23040       case RETRO_DEVICE_JOYPAD:
23041 
23042          if (id < RARCH_FIRST_META_KEY)
23043          {
23044 #ifdef HAVE_NETWORKGAMEPAD
23045             /* Don't process binds if input is coming from Remote RetroPad */
23046             if (     p_rarch->input_driver_remote
23047                   && INPUT_REMOTE_KEY_PRESSED(p_rarch, id, port))
23048                res |= 1;
23049             else
23050 #endif
23051             {
23052                bool bind_valid       = p_rarch->libretro_input_binds[port]
23053                   && p_rarch->libretro_input_binds[port][id].valid;
23054                unsigned remap_button = settings->uints.input_remap_ids[port][id];
23055 
23056                /* TODO/FIXME: What on earth is this code doing...? */
23057                if (!
23058                      (      bind_valid
23059                             && id != remap_button
23060                      )
23061                   )
23062                {
23063                   if (button_mask)
23064                   {
23065                      if (ret & (1 << id))
23066                         res |= (1 << id);
23067                   }
23068                   else
23069                      res = ret;
23070 
23071                }
23072 
23073                if (BIT256_GET(handle->buttons[port], id))
23074                   res = 1;
23075 
23076 #ifdef HAVE_OVERLAY
23077                /* Check if overlay is active and button
23078                 * corresponding to 'id' has been pressed */
23079                if ((port == 0) &&
23080                    p_rarch->overlay_ptr &&
23081                    p_rarch->overlay_ptr->alive &&
23082                    BIT256_GET(p_rarch->overlay_ptr->overlay_state.buttons, id))
23083                {
23084 #ifdef HAVE_MENU
23085                   bool menu_driver_alive        = p_rarch->menu_driver_alive;
23086 #else
23087                   bool menu_driver_alive        = false;
23088 #endif
23089                   bool input_remap_binds_enable = settings->bools.input_remap_binds_enable;
23090 
23091                   /* This button has already been processed
23092                    * inside input_driver_poll() if all the
23093                    * following are true:
23094                    * > Menu driver is not running
23095                    * > Input remaps are enabled
23096                    * > 'id' is not equal to remapped button index
23097                    * If these conditions are met, input here
23098                    * is ignored */
23099                   if ((menu_driver_alive || !input_remap_binds_enable) ||
23100                       (id == remap_button))
23101                      res |= 1;
23102                }
23103 #endif
23104             }
23105 
23106             /* Don't allow turbo for D-pad. */
23107             if (     (id  < RETRO_DEVICE_ID_JOYPAD_UP)    ||
23108                   (    (id  > RETRO_DEVICE_ID_JOYPAD_RIGHT) &&
23109                        (id <= RETRO_DEVICE_ID_JOYPAD_R3)))
23110             {
23111                /*
23112                 * Apply turbo button if activated.
23113                 */
23114                unsigned turbo_mode = settings->uints.input_turbo_mode;
23115 
23116                if (turbo_mode > INPUT_TURBO_MODE_CLASSIC)
23117                {
23118                   /* Pressing turbo button toggles turbo mode on or off.
23119                    * Holding the button will
23120                    * pass through, else the pressed state will be modulated by a
23121                    * periodic pulse defined by the configured duty cycle.
23122                    */
23123 
23124                   /* Avoid detecting the turbo button being held as multiple toggles */
23125                   if (!p_rarch->input_driver_turbo_btns.frame_enable[port])
23126                      p_rarch->input_driver_turbo_btns.turbo_pressed[port] &= ~(1 << 31);
23127                   else if (p_rarch->input_driver_turbo_btns.turbo_pressed[port]>=0)
23128                   {
23129                      p_rarch->input_driver_turbo_btns.turbo_pressed[port] |= (1 << 31);
23130                      /* Toggle turbo for selected buttons. */
23131                      if (p_rarch->input_driver_turbo_btns.enable[port]
23132                            != (1 << settings->uints.input_turbo_default_button))
23133                      {
23134                         static const int button_map[]={
23135                            RETRO_DEVICE_ID_JOYPAD_B,
23136                            RETRO_DEVICE_ID_JOYPAD_Y,
23137                            RETRO_DEVICE_ID_JOYPAD_A,
23138                            RETRO_DEVICE_ID_JOYPAD_X,
23139                            RETRO_DEVICE_ID_JOYPAD_L,
23140                            RETRO_DEVICE_ID_JOYPAD_R,
23141                            RETRO_DEVICE_ID_JOYPAD_L2,
23142                            RETRO_DEVICE_ID_JOYPAD_R2,
23143                            RETRO_DEVICE_ID_JOYPAD_L3,
23144                            RETRO_DEVICE_ID_JOYPAD_R3};
23145                         p_rarch->input_driver_turbo_btns.enable[port] = 1 << button_map[
23146                            MIN(
23147                                  ARRAY_SIZE(button_map) - 1,
23148                                  settings->uints.input_turbo_default_button)];
23149                      }
23150                      p_rarch->input_driver_turbo_btns.mode1_enable[port] ^= 1;
23151                   }
23152 
23153                   if (p_rarch->input_driver_turbo_btns.turbo_pressed[port] & (1 << 31))
23154                   {
23155                      /* Avoid detecting buttons being held as multiple toggles */
23156                      if (!res)
23157                         p_rarch->input_driver_turbo_btns.turbo_pressed[port] &= ~(1 << id);
23158                      else if (!(p_rarch->input_driver_turbo_btns.turbo_pressed[port] & (1 << id)) &&
23159                            turbo_mode == INPUT_TURBO_MODE_SINGLEBUTTON)
23160                      {
23161                         uint16_t enable_new;
23162                         p_rarch->input_driver_turbo_btns.turbo_pressed[port] |= 1 << id;
23163                         /* Toggle turbo for pressed button but make
23164                          * sure at least one button has turbo */
23165                         enable_new = p_rarch->input_driver_turbo_btns.enable[port] ^ (1 << id);
23166                         if (enable_new)
23167                            p_rarch->input_driver_turbo_btns.enable[port] = enable_new;
23168                      }
23169                   }
23170                   else if (turbo_mode == INPUT_TURBO_MODE_SINGLEBUTTON_HOLD &&
23171                         p_rarch->input_driver_turbo_btns.enable[port] &&
23172                         p_rarch->input_driver_turbo_btns.mode1_enable[port])
23173                   {
23174                      /* Hold mode stops turbo on release */
23175                      p_rarch->input_driver_turbo_btns.mode1_enable[port] = 0;
23176                   }
23177 
23178                   if (!res && p_rarch->input_driver_turbo_btns.mode1_enable[port] &&
23179                         p_rarch->input_driver_turbo_btns.enable[port] & (1 << id))
23180                   {
23181                      /* if turbo button is enabled for this key ID */
23182                      res = ((p_rarch->input_driver_turbo_btns.count
23183                               % settings->uints.input_turbo_period)
23184                            < settings->uints.input_turbo_duty_cycle);
23185                   }
23186                }
23187                else
23188                {
23189                   /* If turbo button is held, all buttons pressed except
23190                    * for D-pad will go into a turbo mode. Until the button is
23191                    * released again, the input state will be modulated by a
23192                    * periodic pulse defined by the configured duty cycle.
23193                    */
23194                   if (res)
23195                   {
23196                      if (p_rarch->input_driver_turbo_btns.frame_enable[port])
23197                         p_rarch->input_driver_turbo_btns.enable[port] |= (1 << id);
23198 
23199                      if (p_rarch->input_driver_turbo_btns.enable[port] & (1 << id))
23200                         /* if turbo button is enabled for this key ID */
23201                         res = ((p_rarch->input_driver_turbo_btns.count
23202                                  % settings->uints.input_turbo_period)
23203                               < settings->uints.input_turbo_duty_cycle);
23204                   }
23205                   else
23206                      p_rarch->input_driver_turbo_btns.enable[port] &= ~(1 << id);
23207                }
23208             }
23209          }
23210 
23211          break;
23212 
23213 
23214       case RETRO_DEVICE_KEYBOARD:
23215 
23216          res = ret;
23217 
23218          if (id < RETROK_LAST)
23219          {
23220 #ifdef HAVE_OVERLAY
23221             if (port == 0)
23222             {
23223                if (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive)
23224                {
23225                   input_overlay_state_t
23226                      *ol_state          = &p_rarch->overlay_ptr->overlay_state;
23227 
23228                   if (OVERLAY_GET_KEY(ol_state, id))
23229                      res               |= 1;
23230                }
23231             }
23232 #endif
23233             if (MAPPER_GET_KEY(handle, id))
23234                res |= 1;
23235          }
23236 
23237          break;
23238 
23239 
23240       case RETRO_DEVICE_ANALOG:
23241          {
23242 #if defined(HAVE_NETWORKGAMEPAD) || defined(HAVE_OVERLAY)
23243 #ifdef HAVE_NETWORKGAMEPAD
23244             input_remote_state_t
23245                *input_state         = &p_rarch->remote_st_ptr;
23246 
23247 #endif
23248             unsigned base           = (idx == RETRO_DEVICE_INDEX_ANALOG_RIGHT)
23249                ? 2 : 0;
23250             if (id == RETRO_DEVICE_ID_ANALOG_Y)
23251                base += 1;
23252 #ifdef HAVE_NETWORKGAMEPAD
23253             if (p_rarch->input_driver_remote
23254                   && input_state && input_state->analog[base][port])
23255                res          = input_state->analog[base][port];
23256             else
23257 #endif
23258 #endif
23259             {
23260                if (id < RARCH_FIRST_META_KEY)
23261                {
23262                   bool bind_valid         = p_rarch->libretro_input_binds[port]
23263                      && p_rarch->libretro_input_binds[port][id].valid;
23264 
23265                   if (bind_valid)
23266                   {
23267                      /* reset_state - used to reset input state of a button
23268                       * when the gamepad mapper is in action for that button*/
23269                      bool reset_state        = false;
23270                      if (idx < 2 && id < 2)
23271                      {
23272                         unsigned offset = RARCH_FIRST_CUSTOM_BIND +
23273                            (idx * 4) + (id * 2);
23274 
23275                         if (settings->uints.input_remap_ids[port][offset] != offset)
23276                            reset_state = true;
23277                         else if (settings->uints.input_remap_ids[port][offset+1] != (offset+1))
23278                            reset_state = true;
23279                      }
23280 
23281                      if (reset_state)
23282                         res = 0;
23283                      else
23284                      {
23285                         res = ret;
23286 
23287 #ifdef HAVE_OVERLAY
23288                         if (p_rarch->overlay_ptr &&
23289                             p_rarch->overlay_ptr->alive &&
23290                             (port == 0) &&
23291                             !(((input_analog_dpad_mode == ANALOG_DPAD_LSTICK) &&
23292                                  (idx == RETRO_DEVICE_INDEX_ANALOG_LEFT)) ||
23293                              ((input_analog_dpad_mode == ANALOG_DPAD_RSTICK) &&
23294                                  (idx == RETRO_DEVICE_INDEX_ANALOG_RIGHT))))
23295                         {
23296                            input_overlay_state_t *ol_state =
23297                               &p_rarch->overlay_ptr->overlay_state;
23298                            int16_t ol_analog               =
23299                                  ol_state->analog[base];
23300 
23301                            /* Analog values are an integer corresponding
23302                             * to the extent of the analog motion; these
23303                             * cannot be OR'd together, we must instead
23304                             * keep the value with the largest magnitude */
23305                            if (ol_analog)
23306                            {
23307                               if (res == 0)
23308                                  res = ol_analog;
23309                               else
23310                               {
23311                                  int16_t ol_analog_abs = (ol_analog >= 0) ?
23312                                        ol_analog : -ol_analog;
23313                                  int16_t res_abs       = (res >= 0) ?
23314                                        res : -res;
23315 
23316                                  res = (ol_analog_abs > res_abs) ?
23317                                        ol_analog : res;
23318                               }
23319                            }
23320                         }
23321 #endif
23322                      }
23323                   }
23324                }
23325             }
23326 
23327             if (idx < 2 && id < 2)
23328             {
23329                unsigned offset = 0 + (idx * 4) + (id * 2);
23330                int        val1 = handle->analog_value[port][offset];
23331                int        val2 = handle->analog_value[port][offset+1];
23332 
23333                /* OR'ing these analog values is 100% incorrect,
23334                 * but I have no idea what this code is supposed
23335                 * to be doing (val1 and val2 always seem to be
23336                 * zero), so I will leave it alone... */
23337                if (val1)
23338                   res          |= val1;
23339                else if (val2)
23340                   res          |= val2;
23341             }
23342          }
23343          break;
23344 
23345       case RETRO_DEVICE_MOUSE:
23346       case RETRO_DEVICE_LIGHTGUN:
23347       case RETRO_DEVICE_POINTER:
23348 
23349          if (id < RARCH_FIRST_META_KEY)
23350          {
23351             bool bind_valid = p_rarch->libretro_input_binds[port]
23352                && p_rarch->libretro_input_binds[port][id].valid;
23353 
23354             if (bind_valid)
23355             {
23356                if (button_mask)
23357                {
23358                   if (ret & (1 << id))
23359                      res |= (1 << id);
23360                }
23361                else
23362                   res = ret;
23363             }
23364          }
23365 
23366          break;
23367    }
23368 
23369    return res;
23370 }
23371 
input_state_internal(unsigned port,unsigned device,unsigned idx,unsigned id)23372 static int16_t input_state_internal(unsigned port, unsigned device,
23373       unsigned idx, unsigned id)
23374 {
23375    rarch_joypad_info_t joypad_info;
23376    unsigned mapped_port;
23377    struct rarch_state *p_rarch             = &rarch_st;
23378    settings_t *settings                    = p_rarch->configuration_settings;
23379    float input_analog_deadzone             = settings->floats.input_analog_deadzone;
23380    float input_analog_sensitivity          = settings->floats.input_analog_sensitivity;
23381    unsigned *input_remap_port_map          = settings->uints.input_remap_port_map[port];
23382    bool input_driver_analog_requested      = p_rarch->input_driver_analog_requested[port];
23383    const input_device_driver_t *joypad     = p_rarch->joypad;
23384 #ifdef HAVE_MFI
23385    const input_device_driver_t *sec_joypad = p_rarch->sec_joypad;
23386 #else
23387    const input_device_driver_t *sec_joypad = NULL;
23388 #endif
23389    bool input_blocked                      = (p_rarch->input_driver_flushing_input > 0) ||
23390                                              p_rarch->input_driver_block_libretro_input;
23391    bool bitmask_enabled                    = false;
23392    unsigned max_users                      = p_rarch->input_driver_max_users;
23393    int16_t result                          = 0;
23394 
23395    device                                 &= RETRO_DEVICE_MASK;
23396    bitmask_enabled                         = (device == RETRO_DEVICE_JOYPAD) &&
23397                                              (id == RETRO_DEVICE_ID_JOYPAD_MASK);
23398    joypad_info.axis_threshold              = p_rarch->input_driver_axis_threshold;
23399 
23400    /* Loop over all 'physical' ports mapped to specified
23401     * 'virtual' port index */
23402    while ((mapped_port = *(input_remap_port_map++)) < MAX_USERS)
23403    {
23404       int16_t ret                     = 0;
23405       int16_t port_result             = 0;
23406       unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[mapped_port];
23407 
23408       joypad_info.joy_idx             = settings->uints.input_joypad_index[mapped_port];
23409       joypad_info.auto_binds          = input_autoconf_binds[joypad_info.joy_idx];
23410 
23411       /* Skip disabled input devices */
23412       if (mapped_port >= max_users)
23413          continue;
23414 
23415       /* If core has requested analog input, disable
23416        * analog to dpad mapping (unless forced) */
23417       switch (input_analog_dpad_mode)
23418       {
23419          case ANALOG_DPAD_LSTICK:
23420          case ANALOG_DPAD_RSTICK:
23421             if (input_driver_analog_requested)
23422                input_analog_dpad_mode = ANALOG_DPAD_NONE;
23423             break;
23424          case ANALOG_DPAD_LSTICK_FORCED:
23425             input_analog_dpad_mode = ANALOG_DPAD_LSTICK;
23426             break;
23427          case ANALOG_DPAD_RSTICK_FORCED:
23428             input_analog_dpad_mode = ANALOG_DPAD_RSTICK;
23429             break;
23430          default:
23431             break;
23432       }
23433 
23434       /* TODO/FIXME: This code is gibberish - a mess of nested
23435        * refactors that make no sense whatsoever. The entire
23436        * thing needs to be rewritten from scratch... */
23437 
23438       ret = input_state_wrap(
23439             p_rarch->current_input,
23440             p_rarch->current_input_data,
23441             joypad,
23442             sec_joypad,
23443             &joypad_info,
23444             p_rarch->libretro_input_binds,
23445             p_rarch->keyboard_mapping_blocked,
23446             mapped_port, device, idx, id);
23447 
23448       if ((device == RETRO_DEVICE_ANALOG) &&
23449           (ret == 0))
23450       {
23451          if (p_rarch->libretro_input_binds[mapped_port])
23452          {
23453             if (idx == RETRO_DEVICE_INDEX_ANALOG_BUTTON)
23454             {
23455                if (id < RARCH_FIRST_CUSTOM_BIND)
23456                {
23457                   bool valid_bind = p_rarch->libretro_input_binds[mapped_port][id].valid;
23458 
23459                   if (valid_bind)
23460                   {
23461                      if (sec_joypad)
23462                         ret = input_joypad_analog_button(
23463                               input_analog_deadzone,
23464                               input_analog_sensitivity,
23465                               sec_joypad, &joypad_info,
23466                               id,
23467                               &p_rarch->libretro_input_binds[mapped_port][id]);
23468 
23469                      if (joypad && (ret == 0))
23470                         ret = input_joypad_analog_button(
23471                               input_analog_deadzone,
23472                               input_analog_sensitivity,
23473                               joypad, &joypad_info,
23474                               id,
23475                               &p_rarch->libretro_input_binds[mapped_port][id]);
23476                   }
23477                }
23478             }
23479             else
23480             {
23481                if (sec_joypad)
23482                   ret = input_joypad_analog_axis(
23483                         input_analog_dpad_mode,
23484                         input_analog_deadzone,
23485                         input_analog_sensitivity,
23486                         sec_joypad,
23487                         &joypad_info,
23488                         idx,
23489                         id,
23490                         p_rarch->libretro_input_binds[mapped_port]);
23491 
23492                if (joypad && (ret == 0))
23493                   ret = input_joypad_analog_axis(
23494                         input_analog_dpad_mode,
23495                         input_analog_deadzone,
23496                         input_analog_sensitivity,
23497                         joypad,
23498                         &joypad_info,
23499                         idx,
23500                         id,
23501                         p_rarch->libretro_input_binds[mapped_port]);
23502             }
23503          }
23504       }
23505 
23506       if (!input_blocked)
23507       {
23508          input_mapper_t *handle = &p_rarch->input_driver_mapper;
23509 
23510          if (bitmask_enabled)
23511          {
23512             unsigned i;
23513             for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
23514                if (input_state_device(p_rarch, settings, handle,
23515                      input_analog_dpad_mode, ret, mapped_port,
23516                            device, idx, i, true))
23517                   port_result |= (1 << i);
23518          }
23519          else
23520             port_result = input_state_device(p_rarch, settings, handle,
23521                   input_analog_dpad_mode, ret, mapped_port,
23522                         device, idx, id, false);
23523       }
23524 
23525       /* Digital values are represented by a bitmap;
23526        * we can just perform the logical OR of
23527        * successive samples.
23528        * Analog values are an integer corresponding
23529        * to the extent of the analog motion; these
23530        * cannot be OR'd together, we must instead
23531        * keep the value with the largest magnitude */
23532       if (device == RETRO_DEVICE_ANALOG)
23533       {
23534          if (result == 0)
23535             result = port_result;
23536          else
23537          {
23538             int16_t port_result_abs = (port_result >= 0) ?
23539                   port_result : -port_result;
23540             int16_t result_abs      = (result >= 0) ?
23541                   result : -result;
23542 
23543             result = (port_result_abs > result_abs) ?
23544                   port_result : result;
23545          }
23546       }
23547       else
23548          result |= port_result;
23549    }
23550 
23551 #ifdef HAVE_BSV_MOVIE
23552    /* Save input to BSV record, if enabled */
23553    if (BSV_MOVIE_IS_PLAYBACK_OFF())
23554    {
23555       result = swap_if_big16(result);
23556       intfstream_write(p_rarch->bsv_movie_state_handle->file, &result, 2);
23557    }
23558 #endif
23559 
23560    return result;
23561 }
23562 
23563 /**
23564  * input_state:
23565  * @port                 : user number.
23566  * @device               : device identifier of user.
23567  * @idx                  : index value of user.
23568  * @id                   : identifier of key pressed by user.
23569  *
23570  * Input state callback function.
23571  *
23572  * Returns: Non-zero if the given key (identified by @id)
23573  * was pressed by the user (assigned to @port).
23574  **/
input_state(unsigned port,unsigned device,unsigned idx,unsigned id)23575 static int16_t input_state(unsigned port, unsigned device,
23576       unsigned idx, unsigned id)
23577 {
23578    struct rarch_state *p_rarch = &rarch_st;
23579    int16_t result              = 0;
23580 
23581 #ifdef HAVE_BSV_MOVIE
23582    /* Load input from BSV record, if enabled */
23583    if (BSV_MOVIE_IS_PLAYBACK_ON())
23584    {
23585       int16_t bsv_result = 0;
23586       if (intfstream_read(p_rarch->bsv_movie_state_handle->file, &bsv_result, 2) == 2)
23587       {
23588 #ifdef HAVE_CHEEVOS
23589          rcheevos_pause_hardcore();
23590 #endif
23591          return swap_if_big16(bsv_result);
23592       }
23593 
23594       p_rarch->bsv_movie_state.movie_end = true;
23595    }
23596 #endif
23597 
23598    /* Read input state */
23599    result = input_state_internal(port, device, idx, id);
23600 
23601    /* Register any analog stick input requests for
23602     * this 'virtual' (core) port */
23603    if ((device == RETRO_DEVICE_ANALOG) &&
23604        ((idx == RETRO_DEVICE_INDEX_ANALOG_LEFT) ||
23605             (idx == RETRO_DEVICE_INDEX_ANALOG_RIGHT)))
23606       p_rarch->input_driver_analog_requested[port] = true;
23607 
23608 #ifdef HAVE_BSV_MOVIE
23609    /* Save input to BSV record, if enabled */
23610    if (BSV_MOVIE_IS_PLAYBACK_OFF())
23611    {
23612       result = swap_if_big16(result);
23613       intfstream_write(p_rarch->bsv_movie_state_handle->file, &result, 2);
23614    }
23615 #endif
23616 
23617    return result;
23618 }
23619 
input_joypad_axis(float input_analog_deadzone,float input_analog_sensitivity,const input_device_driver_t * drv,unsigned port,uint32_t joyaxis,float normal_mag)23620 static int16_t input_joypad_axis(
23621       float input_analog_deadzone,
23622       float input_analog_sensitivity,
23623       const input_device_driver_t *drv,
23624       unsigned port, uint32_t joyaxis, float normal_mag)
23625 {
23626    int16_t val                    = (joyaxis != AXIS_NONE) ? drv->axis(port, joyaxis) : 0;
23627 
23628    if (input_analog_deadzone)
23629    {
23630       /* if analog value is below the deadzone, ignore it
23631        * normal magnitude is calculated radially for analog sticks
23632        * and linearly for analog buttons */
23633       if (normal_mag <= input_analog_deadzone)
23634          return 0;
23635 
23636       /* due to the way normal_mag is calculated differently for buttons and
23637        * sticks, this results in either a radial scaled deadzone for sticks
23638        * or linear scaled deadzone for analog buttons */
23639       val = val * MAX(1.0f,(1.0f / normal_mag)) * MIN(1.0f,
23640             ((normal_mag - input_analog_deadzone)
23641           / (1.0f - input_analog_deadzone)));
23642    }
23643 
23644    if (input_analog_sensitivity != 1.0f)
23645    {
23646       float normalized = (1.0f / 0x7fff) * val;
23647       int      new_val = 0x7fff * normalized  *
23648          input_analog_sensitivity;
23649 
23650       if (new_val > 0x7fff)
23651          return 0x7fff;
23652       else if (new_val < -0x7fff)
23653          return -0x7fff;
23654 
23655       return new_val;
23656    }
23657 
23658    return val;
23659 }
23660 
23661 /* MENU INPUT */
23662 #ifdef HAVE_MENU
23663 /* Must be called inside menu_driver_toggle()
23664  * Prevents phantom input when using an overlay to
23665  * toggle menu ON if overlays are disabled in-menu */
menu_input_driver_toggle(menu_input_t * menu_input,bool overlay_hide_in_menu,bool input_overlay_enable,bool overlay_alive,bool on)23666 static void menu_input_driver_toggle(
23667       menu_input_t *menu_input,
23668       bool overlay_hide_in_menu,
23669       bool input_overlay_enable,
23670       bool overlay_alive,
23671       bool on)
23672 {
23673 #ifdef HAVE_OVERLAY
23674    if (on)
23675    {
23676       /* If an overlay was displayed before the toggle
23677        * and overlays are disabled in menu, need to
23678        * inhibit 'select' input */
23679       if (overlay_hide_in_menu)
23680          if (input_overlay_enable && overlay_alive)
23681          {
23682             /* Inhibits pointer 'select' and 'cancel' actions
23683              * (until the next time 'select'/'cancel' are released) */
23684             menu_input->select_inhibit     = true;
23685             menu_input->cancel_inhibit     = true;
23686          }
23687    }
23688    else
23689 #endif
23690    {
23691       /* Inhibits pointer 'select' and 'cancel' actions
23692        * (until the next time 'select'/'cancel' are released) */
23693       menu_input->select_inhibit           = false;
23694       menu_input->cancel_inhibit           = false;
23695    }
23696 }
23697 
menu_input_read_mouse_hw(struct rarch_state * p_rarch,enum menu_input_mouse_hw_id id)23698 static int16_t menu_input_read_mouse_hw(
23699       struct rarch_state *p_rarch,
23700       enum menu_input_mouse_hw_id id)
23701 {
23702    rarch_joypad_info_t joypad_info;
23703    unsigned type                   = 0;
23704    unsigned device                 = RETRO_DEVICE_MOUSE;
23705    input_driver_t *current_input   = p_rarch->current_input;
23706 #ifdef HAVE_MFI
23707    const input_device_driver_t
23708       *sec_joypad                  = p_rarch->sec_joypad;
23709 #else
23710    const input_device_driver_t
23711       *sec_joypad                  = NULL;
23712 #endif
23713 
23714    joypad_info.joy_idx             = 0;
23715    joypad_info.auto_binds          = NULL;
23716    joypad_info.axis_threshold      = 0.0f;
23717 
23718    switch (id)
23719    {
23720       case MENU_MOUSE_X_AXIS:
23721          device = RARCH_DEVICE_MOUSE_SCREEN;
23722          type   = RETRO_DEVICE_ID_MOUSE_X;
23723          break;
23724       case MENU_MOUSE_Y_AXIS:
23725          device = RARCH_DEVICE_MOUSE_SCREEN;
23726          type   = RETRO_DEVICE_ID_MOUSE_Y;
23727          break;
23728       case MENU_MOUSE_LEFT_BUTTON:
23729          type   = RETRO_DEVICE_ID_MOUSE_LEFT;
23730          break;
23731       case MENU_MOUSE_RIGHT_BUTTON:
23732          type   = RETRO_DEVICE_ID_MOUSE_RIGHT;
23733          break;
23734       case MENU_MOUSE_WHEEL_UP:
23735          type   = RETRO_DEVICE_ID_MOUSE_WHEELUP;
23736          break;
23737       case MENU_MOUSE_WHEEL_DOWN:
23738          type   = RETRO_DEVICE_ID_MOUSE_WHEELDOWN;
23739          break;
23740       case MENU_MOUSE_HORIZ_WHEEL_UP:
23741          type   = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP;
23742          break;
23743       case MENU_MOUSE_HORIZ_WHEEL_DOWN:
23744          type   = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN;
23745          break;
23746    }
23747 
23748    if (!current_input->input_state)
23749       return 0;
23750    return current_input->input_state(
23751          p_rarch->current_input_data,
23752          p_rarch->joypad,
23753          sec_joypad,
23754          &joypad_info,
23755          NULL,
23756          p_rarch->keyboard_mapping_blocked,
23757          0, device, 0, type);
23758 }
23759 
menu_input_get_mouse_hw_state(struct rarch_state * p_rarch,menu_input_pointer_hw_state_t * hw_state)23760 static void menu_input_get_mouse_hw_state(
23761       struct rarch_state *p_rarch,
23762       menu_input_pointer_hw_state_t *hw_state)
23763 {
23764    settings_t *settings            = p_rarch->configuration_settings;
23765    static int16_t last_x           = 0;
23766    static int16_t last_y           = 0;
23767    static bool last_select_pressed = false;
23768    static bool last_cancel_pressed = false;
23769    bool mouse_enabled              = settings->bools.menu_mouse_enable;
23770    menu_handle_t             *menu = p_rarch->menu_driver_data;
23771    bool menu_has_fb                =
23772       (menu &&
23773        menu->driver_ctx &&
23774        menu->driver_ctx->set_texture);
23775 #ifdef HAVE_OVERLAY
23776    bool overlay_enable             = settings->bools.input_overlay_enable;
23777    /* Menu pointer controls are ignored when overlays are enabled. */
23778    bool overlay_active             = overlay_enable && p_rarch->overlay_ptr
23779       && p_rarch->overlay_ptr->alive;
23780    if (overlay_active)
23781       mouse_enabled = false;
23782 #endif
23783 
23784    /* Easiest to set inactive by default, and toggle
23785     * when input is detected */
23786    hw_state->active  = false;
23787 
23788 
23789    if (!mouse_enabled)
23790    {
23791       hw_state->x              = 0;
23792       hw_state->y              = 0;
23793       hw_state->select_pressed = false;
23794       hw_state->cancel_pressed = false;
23795       hw_state->up_pressed     = false;
23796       hw_state->down_pressed   = false;
23797       hw_state->left_pressed   = false;
23798       hw_state->right_pressed  = false;
23799       return;
23800    }
23801 
23802    /* X pos */
23803    hw_state->x = menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_X_AXIS);
23804    if (hw_state->x != last_x)
23805       hw_state->active = true;
23806    last_x = hw_state->x;
23807 
23808    /* Y pos */
23809    hw_state->y = menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_Y_AXIS);
23810    if (hw_state->y != last_y)
23811       hw_state->active = true;
23812    last_y = hw_state->y;
23813 
23814    /* > X/Y adjustment */
23815    if (menu_has_fb)
23816    {
23817       /* RGUI uses a framebuffer texture + custom viewports,
23818        * which means we have to convert from screen space to
23819        * menu space... */
23820       struct video_viewport vp = {0};
23821       gfx_display_t *p_disp    = &p_rarch->dispgfx;
23822       /* Read display/framebuffer info */
23823       unsigned fb_width        = p_disp->framebuf_width;
23824       unsigned fb_height       = p_disp->framebuf_height;
23825 
23826       video_driver_get_viewport_info(&vp);
23827 
23828       /* Adjust X pos */
23829       hw_state->x = (int16_t)(((float)(hw_state->x - vp.x) / (float)vp.width) * (float)fb_width);
23830       hw_state->x = hw_state->x <  0        ? 0            : hw_state->x;
23831       hw_state->x = hw_state->x >= fb_width ? fb_width - 1 : hw_state->x;
23832 
23833       /* Adjust Y pos */
23834       hw_state->y = (int16_t)(((float)(hw_state->y - vp.y) / (float)vp.height) * (float)fb_height);
23835       hw_state->y = hw_state->y <  0         ? 0             : hw_state->y;
23836       hw_state->y = hw_state->y >= fb_height ? fb_height - 1 : hw_state->y;
23837    }
23838 
23839    /* Select (LMB)
23840     * Note that releasing select also counts as activity */
23841    hw_state->select_pressed = (bool)
23842       menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_LEFT_BUTTON);
23843    if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed))
23844       hw_state->active = true;
23845    last_select_pressed = hw_state->select_pressed;
23846 
23847    /* Cancel (RMB)
23848     * Note that releasing cancel also counts as activity */
23849    hw_state->cancel_pressed = (bool)
23850       menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_RIGHT_BUTTON);
23851    if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed))
23852       hw_state->active = true;
23853    last_cancel_pressed = hw_state->cancel_pressed;
23854 
23855    /* Up (mouse wheel up) */
23856    hw_state->up_pressed = (bool)
23857       menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_WHEEL_UP);
23858    if (hw_state->up_pressed)
23859       hw_state->active = true;
23860 
23861    /* Down (mouse wheel down) */
23862    hw_state->down_pressed = (bool)
23863       menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_WHEEL_DOWN);
23864    if (hw_state->down_pressed)
23865       hw_state->active = true;
23866 
23867    /* Left (mouse wheel horizontal left) */
23868    hw_state->left_pressed = (bool)
23869       menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_HORIZ_WHEEL_DOWN);
23870    if (hw_state->left_pressed)
23871       hw_state->active = true;
23872 
23873    /* Right (mouse wheel horizontal right) */
23874    hw_state->right_pressed = (bool)
23875       menu_input_read_mouse_hw(p_rarch, MENU_MOUSE_HORIZ_WHEEL_UP);
23876    if (hw_state->right_pressed)
23877       hw_state->active = true;
23878 }
23879 
menu_input_get_touchscreen_hw_state(struct rarch_state * p_rarch,menu_input_pointer_hw_state_t * hw_state)23880 static void menu_input_get_touchscreen_hw_state(
23881       struct rarch_state *p_rarch,
23882       menu_input_pointer_hw_state_t *hw_state)
23883 {
23884    rarch_joypad_info_t joypad_info;
23885    unsigned fb_width, fb_height;
23886    int pointer_x                                = 0;
23887    int pointer_y                                = 0;
23888    settings_t *settings                         =
23889       p_rarch->configuration_settings;
23890    const struct retro_keybind *binds[MAX_USERS] = {NULL};
23891    input_driver_t *current_input                = p_rarch->current_input;
23892    menu_handle_t             *menu              = p_rarch->menu_driver_data;
23893    /* Is a background texture set for the current menu driver?
23894     * Checks if the menu framebuffer is set.
23895     * This would usually only return true
23896     * for framebuffer-based menu drivers, like RGUI. */
23897    int pointer_device                           =
23898          (menu && menu->driver_ctx && menu->driver_ctx->set_texture) ?
23899                RETRO_DEVICE_POINTER : RARCH_DEVICE_POINTER_SCREEN;
23900    static int16_t last_x                        = 0;
23901    static int16_t last_y                        = 0;
23902    static bool last_select_pressed              = false;
23903    static bool last_cancel_pressed              = false;
23904    bool overlay_active                          = false;
23905    bool pointer_enabled                         = settings->bools.menu_pointer_enable;
23906    unsigned input_touch_scale                   = settings->uints.input_touch_scale;
23907 #ifdef HAVE_MFI
23908    const input_device_driver_t
23909       *sec_joypad                               = p_rarch->sec_joypad;
23910 #else
23911    const input_device_driver_t
23912       *sec_joypad                               = NULL;
23913 #endif
23914    gfx_display_t *p_disp    = &p_rarch->dispgfx;
23915 
23916    /* Easiest to set inactive by default, and toggle
23917     * when input is detected */
23918    hw_state->active        = false;
23919 
23920    /* Touch screens don't have mouse wheels, so these
23921     * are always disabled */
23922    hw_state->up_pressed    = false;
23923    hw_state->down_pressed  = false;
23924    hw_state->left_pressed  = false;
23925    hw_state->right_pressed = false;
23926 
23927 #ifdef HAVE_OVERLAY
23928    /* Menu pointer controls are ignored when overlays are enabled. */
23929    overlay_active          = settings->bools.input_overlay_enable
23930       && p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive;
23931    if (overlay_active)
23932       pointer_enabled = false;
23933 #endif
23934 
23935    /* If touchscreen is disabled, ignore all input */
23936    if (!pointer_enabled)
23937    {
23938       hw_state->x              = 0;
23939       hw_state->y              = 0;
23940       hw_state->select_pressed = false;
23941       hw_state->cancel_pressed = false;
23942       return;
23943    }
23944 
23945    /* TODO/FIXME - this should only be used for framebuffer-based
23946     * menu drivers like RGUI. Touchscreen input as a whole should
23947     * NOT be dependent on this
23948     */
23949    fb_width                   = p_disp->framebuf_width;
23950    fb_height                  = p_disp->framebuf_height;
23951 
23952    joypad_info.joy_idx        = 0;
23953    joypad_info.auto_binds     = NULL;
23954    joypad_info.axis_threshold = 0.0f;
23955 
23956    /* X pos */
23957    if (current_input->input_state)
23958       pointer_x                  = current_input->input_state(
23959             p_rarch->current_input_data,
23960             p_rarch->joypad,
23961             sec_joypad,
23962             &joypad_info, binds,
23963             p_rarch->keyboard_mapping_blocked,
23964             0, pointer_device,
23965             0, RETRO_DEVICE_ID_POINTER_X);
23966    hw_state->x  = ((pointer_x + 0x7fff) * (int)fb_width) / 0xFFFF;
23967    hw_state->x *= input_touch_scale;
23968 
23969    /* > An annoyance - we get different starting positions
23970     *   depending upon whether pointer_device is
23971     *   RETRO_DEVICE_POINTER or RARCH_DEVICE_POINTER_SCREEN,
23972     *   so different 'activity' checks are required to prevent
23973     *   false positives on first run */
23974    if (pointer_device == RARCH_DEVICE_POINTER_SCREEN)
23975    {
23976       if (hw_state->x != last_x)
23977          hw_state->active = true;
23978       last_x = hw_state->x;
23979    }
23980    else
23981    {
23982       if (pointer_x != last_x)
23983          hw_state->active = true;
23984       last_x = pointer_x;
23985    }
23986 
23987    /* Y pos */
23988    if (current_input->input_state)
23989       pointer_y = current_input->input_state(
23990             p_rarch->current_input_data,
23991             p_rarch->joypad,
23992             sec_joypad,
23993             &joypad_info, binds,
23994             p_rarch->keyboard_mapping_blocked,
23995             0, pointer_device,
23996             0, RETRO_DEVICE_ID_POINTER_Y);
23997    hw_state->y  = ((pointer_y + 0x7fff) * (int)fb_height) / 0xFFFF;
23998    hw_state->y *= input_touch_scale;
23999 
24000    if (pointer_device == RARCH_DEVICE_POINTER_SCREEN)
24001    {
24002       if (hw_state->y != last_y)
24003          hw_state->active = true;
24004       last_y = hw_state->y;
24005    }
24006    else
24007    {
24008       if (pointer_y != last_y)
24009          hw_state->active = true;
24010       last_y = pointer_y;
24011    }
24012 
24013    /* Select (touch screen contact)
24014     * Note that releasing select also counts as activity */
24015    if (current_input->input_state)
24016       hw_state->select_pressed = (bool)current_input->input_state(
24017             p_rarch->current_input_data,
24018             p_rarch->joypad,
24019             sec_joypad,
24020             &joypad_info, binds,
24021             p_rarch->keyboard_mapping_blocked,
24022             0, pointer_device,
24023             0, RETRO_DEVICE_ID_POINTER_PRESSED);
24024    if (hw_state->select_pressed || (hw_state->select_pressed != last_select_pressed))
24025       hw_state->active = true;
24026    last_select_pressed = hw_state->select_pressed;
24027 
24028    /* Cancel (touch screen 'back' - don't know what is this, but whatever...)
24029     * Note that releasing cancel also counts as activity */
24030    if (current_input->input_state)
24031       hw_state->cancel_pressed = (bool)current_input->input_state(
24032             p_rarch->current_input_data,
24033             p_rarch->joypad,
24034             sec_joypad,
24035             &joypad_info, binds,
24036             p_rarch->keyboard_mapping_blocked,
24037             0, pointer_device,
24038             0, RARCH_DEVICE_ID_POINTER_BACK);
24039    if (hw_state->cancel_pressed || (hw_state->cancel_pressed != last_cancel_pressed))
24040       hw_state->active = true;
24041    last_cancel_pressed = hw_state->cancel_pressed;
24042 }
24043 
input_event_osk_show_symbol_pages(menu_handle_t * menu)24044 static INLINE bool input_event_osk_show_symbol_pages(
24045       menu_handle_t *menu)
24046 {
24047 #if defined(HAVE_LANGEXTRA)
24048 #if defined(HAVE_RGUI)
24049    bool menu_has_fb      = (menu &&
24050          menu->driver_ctx &&
24051          menu->driver_ctx->set_texture);
24052    unsigned language     = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE);
24053    return !menu_has_fb ||
24054          ((language == RETRO_LANGUAGE_JAPANESE) ||
24055           (language == RETRO_LANGUAGE_KOREAN) ||
24056           (language == RETRO_LANGUAGE_CHINESE_SIMPLIFIED) ||
24057           (language == RETRO_LANGUAGE_CHINESE_TRADITIONAL));
24058 #else  /* HAVE_RGUI */
24059    return true;
24060 #endif /* HAVE_RGUI */
24061 #else  /* HAVE_LANGEXTRA */
24062    return false;
24063 #endif /* HAVE_LANGEXTRA */
24064 }
24065 
input_event_osk_append(struct rarch_state * p_rarch,enum osk_type * osk_idx,int ptr,bool show_symbol_pages,const char * word)24066 static void input_event_osk_append(
24067       struct rarch_state *p_rarch,
24068       enum osk_type *osk_idx, int ptr,
24069       bool show_symbol_pages,
24070       const char *word)
24071 {
24072 #ifdef HAVE_LANGEXTRA
24073    if (string_is_equal(word, "\xe2\x87\xa6")) /* backspace character */
24074       input_keyboard_event(true, '\x7f', '\x7f', 0, RETRO_DEVICE_KEYBOARD);
24075    else if (string_is_equal(word, "\xe2\x8f\x8e")) /* return character */
24076       input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
24077    else
24078    if (string_is_equal(word, "\xe2\x87\xa7")) /* up arrow */
24079       *osk_idx = OSK_UPPERCASE_LATIN;
24080    else if (string_is_equal(word, "\xe2\x87\xa9")) /* down arrow */
24081       *osk_idx = OSK_LOWERCASE_LATIN;
24082    else if (string_is_equal(word,"\xe2\x8a\x95")) /* plus sign (next button) */
24083 #else
24084    if (string_is_equal(word, "Bksp"))
24085       input_keyboard_event(true, '\x7f', '\x7f', 0, RETRO_DEVICE_KEYBOARD);
24086    else if (string_is_equal(word, "Enter"))
24087       input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
24088    else
24089    if (string_is_equal(word, "Upper"))
24090       *osk_idx = OSK_UPPERCASE_LATIN;
24091    else if (string_is_equal(word, "Lower"))
24092       *osk_idx = OSK_LOWERCASE_LATIN;
24093    else if (string_is_equal(word, "Next"))
24094 #endif
24095       if (*osk_idx < (show_symbol_pages ? OSK_TYPE_LAST - 1 : OSK_SYMBOLS_PAGE1))
24096          *osk_idx = (enum osk_type)(*osk_idx + 1);
24097       else
24098          *osk_idx = ((enum osk_type)(OSK_TYPE_UNKNOWN + 1));
24099    else
24100    {
24101       input_keyboard_line_append(&p_rarch->keyboard_line, word);
24102       if (word[0] == 0)
24103       {
24104          p_rarch->osk_last_codepoint       = 0;
24105          p_rarch->osk_last_codepoint_len   = 0;
24106       }
24107       else
24108          osk_update_last_codepoint(
24109                &p_rarch->osk_last_codepoint,
24110                &p_rarch->osk_last_codepoint_len,
24111                word);
24112    }
24113 }
24114 
input_event_osk_iterate(void * osk_grid,enum osk_type osk_idx)24115 static void input_event_osk_iterate(
24116       void *osk_grid,
24117       enum osk_type osk_idx)
24118 {
24119 #ifndef HAVE_LANGEXTRA
24120    /* If HAVE_LANGEXTRA is not defined, define some ASCII-friendly pages. */
24121    static const char *uppercase_grid[] = {
24122       "1","2","3","4","5","6","7","8","9","0","Bksp",
24123       "Q","W","E","R","T","Y","U","I","O","P","Enter",
24124       "A","S","D","F","G","H","J","K","L","+","Lower",
24125       "Z","X","C","V","B","N","M"," ","_","/","Next"};
24126    static const char *lowercase_grid[] = {
24127       "1","2","3","4","5","6","7","8","9","0","Bksp",
24128       "q","w","e","r","t","y","u","i","o","p","Enter",
24129       "a","s","d","f","g","h","j","k","l","@","Upper",
24130       "z","x","c","v","b","n","m"," ","-",".","Next"};
24131    static const char *symbols_page1_grid[] = {
24132       "1","2","3","4","5","6","7","8","9","0","Bksp",
24133       "!","\"","#","$","%","&","'","*","(",")","Enter",
24134       "+",",","-","~","/",":",";","=","<",">","Lower",
24135       "?","@","[","\\","]","^","_","|","{","}","Next"};
24136 #endif
24137    switch (osk_idx)
24138    {
24139 #ifdef HAVE_LANGEXTRA
24140       case OSK_HIRAGANA_PAGE1:
24141          memcpy(osk_grid,
24142                hiragana_page1_grid,
24143                sizeof(hiragana_page1_grid));
24144          break;
24145       case OSK_HIRAGANA_PAGE2:
24146          memcpy(osk_grid,
24147                hiragana_page2_grid,
24148                sizeof(hiragana_page2_grid));
24149          break;
24150       case OSK_KATAKANA_PAGE1:
24151          memcpy(osk_grid,
24152                katakana_page1_grid,
24153                sizeof(katakana_page1_grid));
24154          break;
24155       case OSK_KATAKANA_PAGE2:
24156          memcpy(osk_grid,
24157                katakana_page2_grid,
24158                sizeof(katakana_page2_grid));
24159          break;
24160 #endif
24161       case OSK_SYMBOLS_PAGE1:
24162          memcpy(osk_grid,
24163                symbols_page1_grid,
24164                sizeof(uppercase_grid));
24165          break;
24166       case OSK_UPPERCASE_LATIN:
24167          memcpy(osk_grid,
24168                uppercase_grid,
24169                sizeof(uppercase_grid));
24170          break;
24171       case OSK_LOWERCASE_LATIN:
24172       default:
24173          memcpy(osk_grid,
24174                lowercase_grid,
24175                sizeof(lowercase_grid));
24176          break;
24177    }
24178 }
24179 
24180 /*
24181  * This function gets called in order to process all input events
24182  * for the current frame.
24183  *
24184  * Sends input code to menu for one frame.
24185  *
24186  * It uses as input the local variables 'input' and 'trigger_input'.
24187  *
24188  * Mouse and touch input events get processed inside this function.
24189  *
24190  * NOTE: 'input' and 'trigger_input' is sourced from the keyboard and/or
24191  * the gamepad. It does not contain input state derived from the mouse
24192  * and/or touch - this gets dealt with separately within this function.
24193  *
24194  * TODO/FIXME - maybe needs to be overhauled so we can send multiple
24195  * events per frame if we want to, and we shouldn't send the
24196  * entire button state either but do a separate event per button
24197  * state.
24198  */
menu_event(struct rarch_state * p_rarch,settings_t * settings,input_bits_t * p_input,input_bits_t * p_trigger_input,bool display_kb)24199 static unsigned menu_event(
24200       struct rarch_state *p_rarch,
24201       settings_t *settings,
24202       input_bits_t *p_input,
24203       input_bits_t *p_trigger_input,
24204       bool display_kb)
24205 {
24206    /* Used for key repeat */
24207    static float delay_timer                        = 0.0f;
24208    static float delay_count                        = 0.0f;
24209    static bool initial_held                        = true;
24210    static bool first_held                          = false;
24211    static unsigned ok_old                          = 0;
24212    unsigned ret                                    = MENU_ACTION_NOOP;
24213    bool set_scroll                                 = false;
24214    size_t new_scroll_accel                         = 0;
24215    struct menu_state                     *menu_st  = &p_rarch->menu_driver_state;
24216    menu_input_t *menu_input                        = &p_rarch->menu_input_state;
24217    menu_input_pointer_hw_state_t *pointer_hw_state = &p_rarch->menu_input_pointer_hw_state;
24218    bool menu_mouse_enable                          = settings->bools.menu_mouse_enable;
24219    bool menu_pointer_enable                        = settings->bools.menu_pointer_enable;
24220    bool swap_ok_cancel_btns                        = settings->bools.input_menu_swap_ok_cancel_buttons;
24221    bool menu_scroll_fast                           = settings->bools.menu_scroll_fast;
24222    unsigned menu_ok_btn                            = swap_ok_cancel_btns ?
24223          RETRO_DEVICE_ID_JOYPAD_B : RETRO_DEVICE_ID_JOYPAD_A;
24224    unsigned menu_cancel_btn                        = swap_ok_cancel_btns ?
24225          RETRO_DEVICE_ID_JOYPAD_A : RETRO_DEVICE_ID_JOYPAD_B;
24226    unsigned ok_current                             = BIT256_GET_PTR(p_input, menu_ok_btn);
24227    unsigned ok_trigger                             = ok_current & ~ok_old;
24228    unsigned i                                      = 0;
24229    static unsigned navigation_initial              = 0;
24230    unsigned navigation_current                     = 0;
24231    unsigned navigation_buttons[6] =
24232    {
24233       RETRO_DEVICE_ID_JOYPAD_UP,
24234       RETRO_DEVICE_ID_JOYPAD_DOWN,
24235       RETRO_DEVICE_ID_JOYPAD_LEFT,
24236       RETRO_DEVICE_ID_JOYPAD_RIGHT,
24237       RETRO_DEVICE_ID_JOYPAD_L,
24238       RETRO_DEVICE_ID_JOYPAD_R
24239    };
24240 
24241    ok_old                                          = ok_current;
24242 
24243    /* Get pointer (mouse + touchscreen) input
24244     * Note: Must be done regardless of menu screensaver
24245     *       state */
24246 
24247    /* > If pointer input is disabled, do nothing */
24248    if (!menu_mouse_enable && !menu_pointer_enable)
24249       menu_input->pointer.type = MENU_POINTER_DISABLED;
24250    else
24251    {
24252       menu_input_pointer_hw_state_t mouse_hw_state       = {0};
24253       menu_input_pointer_hw_state_t touchscreen_hw_state = {0};
24254 
24255       /* Read mouse */
24256       if (menu_mouse_enable)
24257          menu_input_get_mouse_hw_state(p_rarch, &mouse_hw_state);
24258 
24259       /* Read touchscreen
24260        * Note: Could forgo this if mouse is currently active,
24261        * but this is 'cleaner' code... (if performance is a
24262        * concern - and it isn't - user can just disable touch
24263        * screen support) */
24264       if (menu_pointer_enable)
24265          menu_input_get_touchscreen_hw_state(
24266                p_rarch, &touchscreen_hw_state);
24267 
24268       /* Mouse takes precedence */
24269       if (mouse_hw_state.active)
24270          menu_input->pointer.type = MENU_POINTER_MOUSE;
24271       else if (touchscreen_hw_state.active)
24272          menu_input->pointer.type = MENU_POINTER_TOUCHSCREEN;
24273 
24274       /* Copy input from the current device */
24275       if (menu_input->pointer.type == MENU_POINTER_MOUSE)
24276          memcpy(pointer_hw_state, &mouse_hw_state, sizeof(menu_input_pointer_hw_state_t));
24277       else if (menu_input->pointer.type == MENU_POINTER_TOUCHSCREEN)
24278          memcpy(pointer_hw_state, &touchscreen_hw_state, sizeof(menu_input_pointer_hw_state_t));
24279 
24280       if (pointer_hw_state->active)
24281          menu_st->input_last_time_us = menu_st->current_time_us;
24282    }
24283 
24284    /* Populate menu_input_state
24285     * Note: dx, dy, ptr, y_accel, etc. entries are set elsewhere */
24286    menu_input->pointer.x          = pointer_hw_state->x;
24287    menu_input->pointer.y          = pointer_hw_state->y;
24288    if (menu_input->select_inhibit || menu_input->cancel_inhibit)
24289    {
24290       menu_input->pointer.active  = false;
24291       menu_input->pointer.pressed = false;
24292    }
24293    else
24294    {
24295       menu_input->pointer.active  = pointer_hw_state->active;
24296       menu_input->pointer.pressed = pointer_hw_state->select_pressed;
24297    }
24298 
24299    /* If menu screensaver is active, any input
24300     * is intercepted and used to switch it off */
24301    if (menu_st->screensaver_active)
24302    {
24303       /* Check pointer input */
24304       bool input_active = (menu_input->pointer.type != MENU_POINTER_DISABLED) &&
24305             menu_input->pointer.active;
24306 
24307       /* Check regular input */
24308       if (!input_active)
24309          input_active = bits_any_set(p_input->data, ARRAY_SIZE(p_input->data));
24310 
24311       if (!input_active)
24312          input_active = bits_any_set(p_trigger_input->data, ARRAY_SIZE(p_trigger_input->data));
24313 
24314       /* Disable screensaver if required */
24315       if (input_active)
24316       {
24317          menu_ctx_environment_t menu_environ;
24318          menu_environ.type           = MENU_ENVIRON_DISABLE_SCREENSAVER;
24319          menu_environ.data           = NULL;
24320          menu_st->screensaver_active = false;
24321          menu_st->input_last_time_us = menu_st->current_time_us;
24322          menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
24323       }
24324 
24325       /* Annul received input */
24326       menu_input->pointer.active      = false;
24327       menu_input->pointer.pressed     = false;
24328       menu_input->select_inhibit      = true;
24329       menu_input->cancel_inhibit      = true;
24330       pointer_hw_state->up_pressed    = false;
24331       pointer_hw_state->down_pressed  = false;
24332       pointer_hw_state->left_pressed  = false;
24333       pointer_hw_state->right_pressed = false;
24334       return MENU_ACTION_NOOP;
24335    }
24336 
24337    /* Accelerate only navigation buttons */
24338    for (i = 0; i < 6; i++)
24339    {
24340       if (BIT256_GET_PTR(p_input, navigation_buttons[i]))
24341          navigation_current |= (1 << navigation_buttons[i]);
24342    }
24343 
24344    if (navigation_current)
24345    {
24346       if (!first_held)
24347       {
24348          /* Store first direction in order to block "diagonals" */
24349          if (!navigation_initial)
24350             navigation_initial = navigation_current;
24351 
24352          /* don't run anything first frame, only capture held inputs
24353           * for old_input_state. */
24354 
24355          first_held  = true;
24356          if (menu_scroll_fast)
24357             delay_timer = initial_held ? settings->uints.menu_scroll_delay : 100;
24358          else
24359             delay_timer = initial_held ? settings->uints.menu_scroll_delay : 20;
24360          delay_count = 0;
24361       }
24362 
24363       if (delay_count >= delay_timer)
24364       {
24365          uint32_t input_repeat = 0;
24366          for (i = 0; i < 6; i++)
24367             BIT32_SET(input_repeat, navigation_buttons[i]);
24368 
24369          set_scroll           = true;
24370          first_held           = false;
24371          p_trigger_input->data[0] |= p_input->data[0] & input_repeat;
24372          new_scroll_accel     = menu_st->scroll.acceleration;
24373 
24374          if (menu_scroll_fast)
24375             new_scroll_accel = MIN(new_scroll_accel + 1, 64);
24376          else
24377             new_scroll_accel = MIN(new_scroll_accel + 1, 5);
24378       }
24379 
24380       initial_held  = false;
24381    }
24382    else
24383    {
24384       set_scroll         = true;
24385       first_held         = false;
24386       initial_held       = true;
24387       navigation_initial = 0;
24388    }
24389 
24390    if (set_scroll)
24391       menu_st->scroll.acceleration = (unsigned)(new_scroll_accel);
24392 
24393    delay_count += p_rarch->anim.delta_time;
24394 
24395    if (display_kb)
24396    {
24397       bool show_osk_symbols = input_event_osk_show_symbol_pages(p_rarch->menu_driver_data);
24398 
24399       input_event_osk_iterate(p_rarch->osk_grid, p_rarch->osk_idx);
24400 
24401       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
24402       {
24403          menu_st->input_last_time_us = menu_st->current_time_us;
24404          if (p_rarch->osk_ptr < 33)
24405             p_rarch->osk_ptr += OSK_CHARS_PER_LINE;
24406       }
24407 
24408       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_UP))
24409       {
24410          menu_st->input_last_time_us = menu_st->current_time_us;
24411          if (p_rarch->osk_ptr >= OSK_CHARS_PER_LINE)
24412             p_rarch->osk_ptr -= OSK_CHARS_PER_LINE;
24413       }
24414 
24415       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_RIGHT))
24416       {
24417          menu_st->input_last_time_us = menu_st->current_time_us;
24418          if (p_rarch->osk_ptr < 43)
24419             p_rarch->osk_ptr += 1;
24420       }
24421 
24422       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_LEFT))
24423       {
24424          menu_st->input_last_time_us = menu_st->current_time_us;
24425          if (p_rarch->osk_ptr >= 1)
24426             p_rarch->osk_ptr -= 1;
24427       }
24428 
24429       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_L))
24430       {
24431          menu_st->input_last_time_us = menu_st->current_time_us;
24432          if (p_rarch->osk_idx > OSK_TYPE_UNKNOWN + 1)
24433             p_rarch->osk_idx = ((enum osk_type)
24434                   (p_rarch->osk_idx - 1));
24435          else
24436             p_rarch->osk_idx = ((enum osk_type)(show_osk_symbols
24437                      ? OSK_TYPE_LAST - 1
24438                      : OSK_SYMBOLS_PAGE1));
24439       }
24440 
24441       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R))
24442       {
24443          menu_st->input_last_time_us = menu_st->current_time_us;
24444          if (p_rarch->osk_idx < (show_osk_symbols
24445                   ? OSK_TYPE_LAST - 1
24446                   : OSK_SYMBOLS_PAGE1))
24447             p_rarch->osk_idx = ((enum osk_type)(
24448                      p_rarch->osk_idx + 1));
24449          else
24450             p_rarch->osk_idx = ((enum osk_type)(OSK_TYPE_UNKNOWN + 1));
24451       }
24452 
24453       if (BIT256_GET_PTR(p_trigger_input, menu_ok_btn))
24454       {
24455          if (p_rarch->osk_ptr >= 0)
24456             input_event_osk_append(
24457                   p_rarch,
24458                   &p_rarch->osk_idx,
24459                   p_rarch->osk_ptr,
24460                   show_osk_symbols,
24461                   p_rarch->osk_grid[p_rarch->osk_ptr]);
24462       }
24463 
24464       if (BIT256_GET_PTR(p_trigger_input, menu_cancel_btn))
24465          input_keyboard_event(true, '\x7f', '\x7f',
24466                0, RETRO_DEVICE_KEYBOARD);
24467 
24468       /* send return key to close keyboard input window */
24469       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_START))
24470          input_keyboard_event(true, '\n', '\n', 0, RETRO_DEVICE_KEYBOARD);
24471 
24472       BIT256_CLEAR_ALL_PTR(p_trigger_input);
24473    }
24474    else
24475    {
24476       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_UP))
24477       {
24478          if (navigation_initial == (1 << RETRO_DEVICE_ID_JOYPAD_UP))
24479             ret = MENU_ACTION_UP;
24480       }
24481       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
24482       {
24483          if (navigation_initial == (1 << RETRO_DEVICE_ID_JOYPAD_DOWN))
24484             ret = MENU_ACTION_DOWN;
24485       }
24486       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_LEFT))
24487       {
24488          if (navigation_initial == (1 << RETRO_DEVICE_ID_JOYPAD_LEFT))
24489             ret = MENU_ACTION_LEFT;
24490       }
24491       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_RIGHT))
24492       {
24493          if (navigation_initial == (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT))
24494             ret = MENU_ACTION_RIGHT;
24495       }
24496 
24497       if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_L))
24498          ret = MENU_ACTION_SCROLL_UP;
24499       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R))
24500          ret = MENU_ACTION_SCROLL_DOWN;
24501       else if (ok_trigger)
24502          ret = MENU_ACTION_OK;
24503       else if (BIT256_GET_PTR(p_trigger_input, menu_cancel_btn))
24504          ret = MENU_ACTION_CANCEL;
24505       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_X))
24506          ret = MENU_ACTION_SEARCH;
24507       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_Y))
24508          ret = MENU_ACTION_SCAN;
24509       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_START))
24510          ret = MENU_ACTION_START;
24511       else if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
24512          ret = MENU_ACTION_INFO;
24513       else if (BIT256_GET_PTR(p_trigger_input, RARCH_MENU_TOGGLE))
24514          ret = MENU_ACTION_TOGGLE;
24515 
24516       if (ret != MENU_ACTION_NOOP)
24517          menu_st->input_last_time_us = menu_st->current_time_us;
24518    }
24519 
24520    return ret;
24521 }
24522 
menu_input_get_pointer_state(menu_input_pointer_t * pointer)24523 void menu_input_get_pointer_state(menu_input_pointer_t *pointer)
24524 {
24525    struct rarch_state  *p_rarch   = &rarch_st;
24526    menu_input_t       *menu_input = &p_rarch->menu_input_state;
24527 
24528    if (!pointer)
24529       return;
24530 
24531    /* Copy parameters from global menu_input_state
24532     * (i.e. don't pass by reference)
24533     * This is a fast operation */
24534    memcpy(pointer, &menu_input->pointer, sizeof(menu_input_pointer_t));
24535 }
24536 
menu_input_get_pointer_selection(void)24537 unsigned menu_input_get_pointer_selection(void)
24538 {
24539    struct rarch_state  *p_rarch   = &rarch_st;
24540    menu_input_t       *menu_input = &p_rarch->menu_input_state;
24541    return menu_input->ptr;
24542 }
24543 
menu_input_set_pointer_selection(unsigned selection)24544 void menu_input_set_pointer_selection(unsigned selection)
24545 {
24546    struct rarch_state  *p_rarch   = &rarch_st;
24547    menu_input_t       *menu_input = &p_rarch->menu_input_state;
24548 
24549    menu_input->ptr                = selection;
24550 }
24551 
menu_input_set_pointer_y_accel(float y_accel)24552 void menu_input_set_pointer_y_accel(float y_accel)
24553 {
24554    struct rarch_state  *p_rarch   = &rarch_st;
24555    menu_input_t    *menu_input    = &p_rarch->menu_input_state;
24556 
24557    menu_input->pointer.y_accel    = y_accel;
24558 }
24559 
menu_input_get_dpi(struct rarch_state * p_rarch,menu_handle_t * menu,gfx_display_t * p_disp)24560 static float menu_input_get_dpi(struct rarch_state *p_rarch,
24561       menu_handle_t *menu,
24562       gfx_display_t *p_disp)
24563 {
24564    static unsigned last_video_width  = 0;
24565    static unsigned last_video_height = 0;
24566    static float dpi                  = 0.0f;
24567    static bool dpi_cached            = false;
24568 
24569    /* Regardless of menu driver, need 'actual' screen DPI
24570     * Note: DPI is a fixed hardware property. To minimise performance
24571     * overheads we therefore only call video_context_driver_get_metrics()
24572     * on first run, or when the current video resolution changes */
24573    if (!dpi_cached ||
24574        (p_rarch->video_driver_width  != last_video_width) ||
24575        (p_rarch->video_driver_height != last_video_height))
24576    {
24577       gfx_ctx_metrics_t mets;
24578       /* Note: If video_context_driver_get_metrics() fails,
24579        * we don't know what happened to dpi - so ensure it
24580        * is reset to a sane value */
24581 
24582       mets.type  = DISPLAY_METRIC_DPI;
24583       mets.value = &dpi;
24584       if (!video_context_driver_get_metrics(&mets))
24585          dpi            = 0.0f;
24586 
24587       dpi_cached        = true;
24588       last_video_width  = p_rarch->video_driver_width;
24589       last_video_height = p_rarch->video_driver_height;
24590    }
24591 
24592    /* RGUI uses a framebuffer texture, which means we
24593     * operate in menu space, not screen space.
24594     * DPI in a traditional sense is therefore meaningless,
24595     * so generate a substitute value based upon framebuffer
24596     * dimensions */
24597    if (dpi > 0.0f)
24598    {
24599       bool menu_has_fb =
24600             menu->driver_ctx
24601          && menu->driver_ctx->set_texture;
24602 
24603       /* Read framebuffer info? */
24604       if (menu_has_fb)
24605       {
24606          unsigned fb_height         = p_disp->framebuf_height;
24607          /* Rationale for current 'DPI' determination method:
24608           * - Divide screen height by DPI, to get number of vertical
24609           *   '1 inch' squares
24610           * - Divide RGUI framebuffer height by number of vertical
24611           *   '1 inch' squares to get number of menu space pixels
24612           *   per inch
24613           * This is crude, but should be sufficient... */
24614          return ((float)fb_height / (float)p_rarch->video_driver_height) * dpi;
24615       }
24616    }
24617 
24618    return dpi;
24619 }
24620 
menu_should_pop_stack(const char * label)24621 static bool menu_should_pop_stack(const char *label)
24622 {
24623    /* > Info box */
24624    if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_INFO_SCREEN)))
24625       return true;
24626    /* > Help box */
24627    if (string_starts_with_size(label, "help", STRLEN_CONST("help")))
24628       if (
24629                string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP))
24630             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CONTROLS))
24631             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE))
24632             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_LOADING_CONTENT))
24633             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SCANNING_CONTENT))
24634             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD))
24635             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING))
24636             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO))
24637             || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION)))
24638          return true;
24639    if (
24640          string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CHEEVOS_DESCRIPTION)))
24641       return true;
24642    return false;
24643 }
24644 
24645 /* Used to close an active message box (help or info)
24646  * TODO/FIXME: The way that message boxes are handled
24647  * is complete garbage. generic_menu_iterate() and
24648  * message boxes in general need a total rewrite.
24649  * I consider this current 'close_messagebox' a hack,
24650  * but at least it prevents undefined/dangerous
24651  * behaviour... */
menu_input_pointer_close_messagebox(struct menu_state * menu_st)24652 static void menu_input_pointer_close_messagebox(struct menu_state *menu_st)
24653 {
24654    const char *label            = NULL;
24655 
24656    /* Determine whether this is a help or info
24657     * message box */
24658    file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0),
24659          NULL, &label, NULL, NULL);
24660 
24661    /* Pop stack, if required */
24662    if (menu_should_pop_stack(label))
24663    {
24664       size_t selection            = menu_st->selection_ptr;
24665       size_t new_selection        = selection;
24666 
24667       menu_entries_pop_stack(&new_selection, 0, 0);
24668       menu_st->selection_ptr      = selection;
24669    }
24670 }
24671 
menu_input_pointer_post_iterate(struct rarch_state * p_rarch,gfx_display_t * p_disp,retro_time_t current_time,menu_file_list_cbs_t * cbs,menu_entry_t * entry,unsigned action)24672 static int menu_input_pointer_post_iterate(
24673       struct rarch_state *p_rarch,
24674       gfx_display_t *p_disp,
24675       retro_time_t current_time,
24676       menu_file_list_cbs_t *cbs,
24677       menu_entry_t *entry, unsigned action)
24678 {
24679    static retro_time_t start_time                  = 0;
24680    static int16_t start_x                          = 0;
24681    static int16_t start_y                          = 0;
24682    static int16_t last_x                           = 0;
24683    static int16_t last_y                           = 0;
24684    static uint16_t dx_start_right_max              = 0;
24685    static uint16_t dx_start_left_max               = 0;
24686    static uint16_t dy_start_up_max                 = 0;
24687    static uint16_t dy_start_down_max               = 0;
24688    static bool last_select_pressed                 = false;
24689    static bool last_cancel_pressed                 = false;
24690    static bool last_left_pressed                   = false;
24691    static bool last_right_pressed                  = false;
24692    static retro_time_t last_left_action_time       = 0;
24693    static retro_time_t last_right_action_time      = 0;
24694    static retro_time_t last_press_direction_time   = 0;
24695    bool attenuate_y_accel                          = true;
24696    bool osk_active                                 = menu_input_dialog_get_display_kb();
24697    bool messagebox_active                          = false;
24698    int ret                                         = 0;
24699    menu_input_pointer_hw_state_t *pointer_hw_state = &p_rarch->menu_input_pointer_hw_state;
24700    menu_input_t *menu_input                        = &p_rarch->menu_input_state;
24701    menu_handle_t *menu                             = p_rarch->menu_driver_data;
24702    struct menu_state *menu_st                      = &p_rarch->menu_driver_state;
24703 
24704    /* Check whether a message box is currently
24705     * being shown
24706     * > Note: This ignores input bind dialogs,
24707     *   since input binding overrides normal input
24708     *   and must be handled separately... */
24709    if (menu)
24710       messagebox_active = BIT64_GET(
24711             menu->state, MENU_STATE_RENDER_MESSAGEBOX) &&
24712             !string_is_empty(menu->menu_state_msg);
24713 
24714    /* If onscreen keyboard is shown and we currently have
24715     * active mouse input, highlight key under mouse cursor */
24716    if (osk_active &&
24717        (menu_input->pointer.type == MENU_POINTER_MOUSE) &&
24718        pointer_hw_state->active)
24719    {
24720       menu_ctx_pointer_t point;
24721 
24722       point.x       = pointer_hw_state->x;
24723       point.y       = pointer_hw_state->y;
24724       point.ptr     = 0;
24725       point.cbs     = NULL;
24726       point.entry   = NULL;
24727       point.action  = 0;
24728       point.gesture = MENU_INPUT_GESTURE_NONE;
24729       point.retcode = 0;
24730 
24731       menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point);
24732       if (point.retcode > -1)
24733          p_rarch->osk_ptr = point.retcode;
24734    }
24735 
24736    /* Select + X/Y position */
24737    if (!menu_input->select_inhibit)
24738    {
24739       if (pointer_hw_state->select_pressed)
24740       {
24741          int16_t x           = pointer_hw_state->x;
24742          int16_t y           = pointer_hw_state->y;
24743          static float accel0 = 0.0f;
24744          static float accel1 = 0.0f;
24745 
24746          /* Transition from select unpressed to select pressed */
24747          if (!last_select_pressed)
24748          {
24749             menu_ctx_pointer_t point;
24750 
24751             /* Initialise variables */
24752             start_time                = current_time;
24753             start_x                   = x;
24754             start_y                   = y;
24755             last_x                    = x;
24756             last_y                    = y;
24757             dx_start_right_max        = 0;
24758             dx_start_left_max         = 0;
24759             dy_start_up_max           = 0;
24760             dy_start_down_max         = 0;
24761             accel0                    = 0.0f;
24762             accel1                    = 0.0f;
24763             last_press_direction_time = 0;
24764 
24765             /* If we are not currently showing the onscreen
24766              * keyboard or a message box, trigger a 'pointer
24767              * down' event */
24768             if (!osk_active && !messagebox_active)
24769             {
24770                point.x       = x;
24771                point.y       = y;
24772                /* Note: menu_input->ptr is meaningless here when
24773                 * using a touchscreen... */
24774                point.ptr     = menu_input->ptr;
24775                point.cbs     = cbs;
24776                point.entry   = entry;
24777                point.action  = action;
24778                point.gesture = MENU_INPUT_GESTURE_NONE;
24779 
24780                menu_driver_ctl(RARCH_MENU_CTL_POINTER_DOWN, &point);
24781                ret = point.retcode;
24782             }
24783          }
24784          else
24785          {
24786             /* Pointer is being held down
24787              * (i.e. for more than one frame) */
24788             float dpi = menu ? menu_input_get_dpi(p_rarch, menu, p_disp) : 0.0f;
24789 
24790             /* > Update deltas + acceleration & detect press direction
24791              *   Note: We only do this if the pointer has moved above
24792              *   a certain threshold - this requires dpi info */
24793             if (dpi > 0.0f)
24794             {
24795                uint16_t dpi_threshold_drag =
24796                      (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_DRAG) + 0.5f);
24797 
24798                int16_t dx_start            = x - start_x;
24799                int16_t dy_start            = y - start_y;
24800                uint16_t dx_start_abs       = dx_start < 0 ? dx_start * -1 : dx_start;
24801                uint16_t dy_start_abs       = dy_start < 0 ? dy_start * -1 : dy_start;
24802 
24803                if ((dx_start_abs > dpi_threshold_drag) ||
24804                    (dy_start_abs > dpi_threshold_drag))
24805                {
24806                   uint16_t dpi_threshold_press_direction_min     =
24807                         (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MIN) + 0.5f);
24808                   uint16_t dpi_threshold_press_direction_max     =
24809                         (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_MAX) + 0.5f);
24810                   uint16_t dpi_threshold_press_direction_tangent =
24811                         (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_PRESS_DIRECTION_TANGENT) + 0.5f);
24812 
24813                   enum menu_input_pointer_press_direction
24814                         press_direction                          = MENU_INPUT_PRESS_DIRECTION_NONE;
24815                   float press_direction_amplitude                = 0.0f;
24816                   retro_time_t press_direction_delay             = MENU_INPUT_PRESS_DIRECTION_DELAY_MAX;
24817 
24818                   /* Pointer has moved a sufficient distance to
24819                    * trigger a 'dragged' state */
24820                   menu_input->pointer.dragged = true;
24821 
24822                   /* Here we diverge:
24823                    * > If onscreen keyboard or a message box is
24824                    *   active, pointer deltas, acceleration and
24825                    *   press direction must be inhibited
24826                    * > If not, input is processed normally */
24827                   if (osk_active || messagebox_active)
24828                   {
24829                      /* Inhibit normal pointer input */
24830                      menu_input->pointer.dx              = 0;
24831                      menu_input->pointer.dy              = 0;
24832                      menu_input->pointer.y_accel         = 0.0f;
24833                      menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
24834                      accel0                              = 0.0f;
24835                      accel1                              = 0.0f;
24836                      attenuate_y_accel                   = false;
24837                   }
24838                   else
24839                   {
24840                      /* Assign current deltas */
24841                      menu_input->pointer.dx = x - last_x;
24842                      menu_input->pointer.dy = y - last_y;
24843 
24844                      /* Update maximum start->current deltas */
24845                      if (dx_start > 0)
24846                         dx_start_right_max = (dx_start_abs > dx_start_right_max) ?
24847                               dx_start_abs : dx_start_right_max;
24848                      else
24849                         dx_start_left_max = (dx_start_abs > dx_start_left_max) ?
24850                               dx_start_abs : dx_start_left_max;
24851 
24852                      if (dy_start > 0)
24853                         dy_start_down_max = (dy_start_abs > dy_start_down_max) ?
24854                               dy_start_abs : dy_start_down_max;
24855                      else
24856                         dy_start_up_max = (dy_start_abs > dy_start_up_max) ?
24857                               dy_start_abs : dy_start_up_max;
24858 
24859                      /* Magic numbers... */
24860                      menu_input->pointer.y_accel = (accel0 + accel1 + (float)menu_input->pointer.dy) / 3.0f;
24861                      accel0                      = accel1;
24862                      accel1                      = menu_input->pointer.y_accel;
24863 
24864                      /* Acceleration decays over time - but if the value
24865                       * has been set on this frame, attenuation should
24866                       * be skipped */
24867                      attenuate_y_accel = false;
24868 
24869                      /* Check if pointer is being held in a particular
24870                       * direction */
24871                      menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
24872 
24873                      /* > Press directions are actually triggered as a pulse train,
24874                       *   since a continuous direction prevents fine control in the
24875                       *   context of menu actions (i.e. it would be the same
24876                       *   as always holding down a cursor key all the time - too fast
24877                       *   to control). We therefore apply a low pass filter, with
24878                       *   a variable frequency based upon the distance the user has
24879                       *   dragged the pointer */
24880 
24881                      /* > Horizontal */
24882                      if ((dx_start_abs >= dpi_threshold_press_direction_min) &&
24883                          (dy_start_abs <  dpi_threshold_press_direction_tangent))
24884                      {
24885                         press_direction = (dx_start > 0) ?
24886                               MENU_INPUT_PRESS_DIRECTION_RIGHT : MENU_INPUT_PRESS_DIRECTION_LEFT;
24887 
24888                         /* Get effective amplitude of press direction offset */
24889                         press_direction_amplitude =
24890                               (float)(dx_start_abs - dpi_threshold_press_direction_min) /
24891                               (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min);
24892                      }
24893                      /* > Vertical */
24894                      else if ((dy_start_abs >= dpi_threshold_press_direction_min) &&
24895                               (dx_start_abs <  dpi_threshold_press_direction_tangent))
24896                      {
24897                         press_direction = (dy_start > 0) ?
24898                               MENU_INPUT_PRESS_DIRECTION_DOWN : MENU_INPUT_PRESS_DIRECTION_UP;
24899 
24900                         /* Get effective amplitude of press direction offset */
24901                         press_direction_amplitude =
24902                               (float)(dy_start_abs - dpi_threshold_press_direction_min) /
24903                               (float)(dpi_threshold_press_direction_max - dpi_threshold_press_direction_min);
24904                      }
24905 
24906                      if (press_direction != MENU_INPUT_PRESS_DIRECTION_NONE)
24907                      {
24908                         /* > Update low pass filter frequency */
24909                         if (press_direction_amplitude > 1.0f)
24910                            press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN;
24911                         else
24912                            press_direction_delay = MENU_INPUT_PRESS_DIRECTION_DELAY_MIN +
24913                                  ((MENU_INPUT_PRESS_DIRECTION_DELAY_MAX - MENU_INPUT_PRESS_DIRECTION_DELAY_MIN)*
24914                                   (1.0f - press_direction_amplitude));
24915 
24916                         /* > Apply low pass filter */
24917                         if (current_time - last_press_direction_time > press_direction_delay)
24918                         {
24919                            menu_input->pointer.press_direction = press_direction;
24920                            last_press_direction_time = current_time;
24921                         }
24922                      }
24923                   }
24924                }
24925                else
24926                {
24927                   /* Pointer is stationary */
24928                   menu_input->pointer.dx              = 0;
24929                   menu_input->pointer.dy              = 0;
24930                   menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
24931 
24932                   /* Standard behaviour (on Android, at least) is to stop
24933                    * scrolling when the user touches the screen. We should
24934                    * therefore 'reset' y acceleration whenever the pointer
24935                    * is stationary - with two caveats:
24936                    * - We only disable scrolling if the pointer *remains*
24937                    *   stationary. If the pointer is held down then
24938                    *   subsequently moves, normal scrolling should resume
24939                    * - Halting the scroll immediately produces a very
24940                    *   unpleasant 'jerky' user experience. To avoid this,
24941                    *   we add a small delay between detecting a pointer
24942                    *   down event and forcing y acceleration to zero
24943                    * NOTE: Of course, we must also 'reset' y acceleration
24944                    * whenever the onscreen keyboard or a message box is
24945                    * shown */
24946                   if ((!menu_input->pointer.dragged &&
24947                         (menu_input->pointer.press_duration > MENU_INPUT_Y_ACCEL_RESET_DELAY)) ||
24948                       (osk_active || messagebox_active))
24949                   {
24950                      menu_input->pointer.y_accel = 0.0f;
24951                      accel0                      = 0.0f;
24952                      accel1                      = 0.0f;
24953                      attenuate_y_accel           = false;
24954                   }
24955                }
24956             }
24957             else
24958             {
24959                /* No dpi info - just fallback to zero... */
24960                menu_input->pointer.dx              = 0;
24961                menu_input->pointer.dy              = 0;
24962                menu_input->pointer.y_accel         = 0.0f;
24963                menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
24964                accel0                              = 0.0f;
24965                accel1                              = 0.0f;
24966                attenuate_y_accel                   = false;
24967             }
24968 
24969             /* > Update remaining variables */
24970             menu_input->pointer.press_duration = current_time - start_time;
24971             last_x                             = x;
24972             last_y                             = y;
24973          }
24974       }
24975       else if (last_select_pressed)
24976       {
24977          /* Transition from select pressed to select unpressed */
24978          int16_t x;
24979          int16_t y;
24980          menu_ctx_pointer_t point;
24981 
24982          if (menu_input->pointer.dragged)
24983          {
24984             /* Pointer has moved.
24985              * When using a touchscreen, releasing a press
24986              * resets the x/y position - so cannot use
24987              * current hardware x/y values. Instead, use
24988              * previous position from last time that a
24989              * press was active */
24990             x = last_x;
24991             y = last_y;
24992          }
24993          else
24994          {
24995             /* Pointer is considered stationary,
24996              * so use start position */
24997             x = start_x;
24998             y = start_y;
24999          }
25000 
25001          point.x       = x;
25002          point.y       = y;
25003          point.ptr     = menu_input->ptr;
25004          point.cbs     = cbs;
25005          point.entry   = entry;
25006          point.action  = action;
25007          point.gesture = MENU_INPUT_GESTURE_NONE;
25008 
25009          /* On screen keyboard overrides normal menu input... */
25010          if (osk_active)
25011          {
25012             /* If pointer has been 'dragged', then it counts as
25013              * a miss. Only register 'release' event if pointer
25014              * has remained stationary */
25015             if (!menu_input->pointer.dragged)
25016             {
25017                menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point);
25018                if (point.retcode > -1)
25019                {
25020                   bool show_osk_symbols = input_event_osk_show_symbol_pages(p_rarch->menu_driver_data);
25021 
25022                   p_rarch->osk_ptr = point.retcode;
25023                   input_event_osk_append(
25024                         p_rarch,
25025                         &p_rarch->osk_idx,
25026                         point.retcode,
25027                         show_osk_symbols,
25028                         p_rarch->osk_grid[p_rarch->osk_ptr]);
25029                }
25030             }
25031          }
25032          /* Message boxes override normal menu input...
25033           * > If a message box is shown, any kind of pointer
25034           *   gesture should close it */
25035          else if (messagebox_active)
25036             menu_input_pointer_close_messagebox(
25037                   &p_rarch->menu_driver_state);
25038          /* Normal menu input */
25039          else
25040          {
25041             /* Detect gesture type */
25042             if (!menu_input->pointer.dragged)
25043             {
25044                /* Pointer hasn't moved - check press duration */
25045                if (menu_input->pointer.press_duration
25046                      < MENU_INPUT_PRESS_TIME_SHORT)
25047                   point.gesture = MENU_INPUT_GESTURE_TAP;
25048                else if (menu_input->pointer.press_duration
25049                      < MENU_INPUT_PRESS_TIME_LONG)
25050                   point.gesture = MENU_INPUT_GESTURE_SHORT_PRESS;
25051                else
25052                   point.gesture = MENU_INPUT_GESTURE_LONG_PRESS;
25053             }
25054             else
25055             {
25056                /* Pointer has moved - check if this is a swipe */
25057                float dpi = menu ? menu_input_get_dpi(p_rarch, menu, p_disp) : 0.0f;
25058 
25059                if ((dpi > 0.0f)
25060                      &&
25061                      (menu_input->pointer.press_duration <
25062                       MENU_INPUT_SWIPE_TIMEOUT))
25063                {
25064                   uint16_t dpi_threshold_swipe         =
25065                         (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE) + 0.5f);
25066                   uint16_t dpi_threshold_swipe_tangent =
25067                         (uint16_t)((dpi * MENU_INPUT_DPI_THRESHOLD_SWIPE_TANGENT) + 0.5f);
25068 
25069                   int16_t dx_start                     = x - start_x;
25070                   int16_t dy_start                     = y - start_y;
25071                   uint16_t dx_start_right_final        = 0;
25072                   uint16_t dx_start_left_final         = 0;
25073                   uint16_t dy_start_up_final           = 0;
25074                   uint16_t dy_start_down_final         = 0;
25075 
25076                   /* Get final deltas */
25077                   if (dx_start > 0)
25078                      dx_start_right_final              = (uint16_t)dx_start;
25079                   else
25080                      dx_start_left_final               = (uint16_t)
25081                         (dx_start * -1);
25082 
25083                   if (dy_start > 0)
25084                      dy_start_down_final               = (uint16_t)dy_start;
25085                   else
25086                      dy_start_up_final                 = (uint16_t)
25087                         (dy_start * -1);
25088 
25089                   /* Swipe right */
25090                   if (     (dx_start_right_final > dpi_threshold_swipe)
25091                         && (dx_start_left_max    < dpi_threshold_swipe_tangent)
25092                         && (dy_start_up_max      < dpi_threshold_swipe_tangent)
25093                         && (dy_start_down_max    < dpi_threshold_swipe_tangent)
25094                      )
25095                      point.gesture = MENU_INPUT_GESTURE_SWIPE_RIGHT;
25096                   /* Swipe left */
25097                   else if (
25098                            (dx_start_right_max  < dpi_threshold_swipe_tangent)
25099                         && (dx_start_left_final > dpi_threshold_swipe)
25100                         && (dy_start_up_max     < dpi_threshold_swipe_tangent)
25101                         && (dy_start_down_max   < dpi_threshold_swipe_tangent)
25102                         )
25103                      point.gesture = MENU_INPUT_GESTURE_SWIPE_LEFT;
25104                   /* Swipe up */
25105                   else if (
25106                            (dx_start_right_max < dpi_threshold_swipe_tangent)
25107                         && (dx_start_left_max  < dpi_threshold_swipe_tangent)
25108                         && (dy_start_up_final  > dpi_threshold_swipe)
25109                         && (dy_start_down_max  < dpi_threshold_swipe_tangent)
25110                         )
25111                      point.gesture = MENU_INPUT_GESTURE_SWIPE_UP;
25112                   /* Swipe down */
25113                   else if (
25114                            (dx_start_right_max  < dpi_threshold_swipe_tangent)
25115                         && (dx_start_left_max   < dpi_threshold_swipe_tangent)
25116                         && (dy_start_up_max     < dpi_threshold_swipe_tangent)
25117                         && (dy_start_down_final > dpi_threshold_swipe)
25118                         )
25119                      point.gesture = MENU_INPUT_GESTURE_SWIPE_DOWN;
25120                }
25121             }
25122 
25123             /* Trigger a 'pointer up' event */
25124             menu_driver_ctl(RARCH_MENU_CTL_POINTER_UP, &point);
25125             ret = point.retcode;
25126          }
25127 
25128          /* Reset variables */
25129          start_x                             = 0;
25130          start_y                             = 0;
25131          last_x                              = 0;
25132          last_y                              = 0;
25133          dx_start_right_max                  = 0;
25134          dx_start_left_max                   = 0;
25135          dy_start_up_max                     = 0;
25136          dy_start_down_max                   = 0;
25137          last_press_direction_time           = 0;
25138          menu_input->pointer.press_duration  = 0;
25139          menu_input->pointer.press_direction = MENU_INPUT_PRESS_DIRECTION_NONE;
25140          menu_input->pointer.dx              = 0;
25141          menu_input->pointer.dy              = 0;
25142          menu_input->pointer.dragged         = false;
25143       }
25144    }
25145 
25146    /* Adjust acceleration
25147     * > If acceleration has not been set on this frame,
25148     *   apply normal attenuation */
25149    if (attenuate_y_accel)
25150       menu_input->pointer.y_accel *= MENU_INPUT_Y_ACCEL_DECAY_FACTOR;
25151 
25152    /* If select has been released, disable any existing
25153     * select inhibit */
25154    if (!pointer_hw_state->select_pressed)
25155       menu_input->select_inhibit   = false;
25156 
25157    /* Cancel */
25158    if (   !menu_input->cancel_inhibit
25159        &&  pointer_hw_state->cancel_pressed
25160        && !last_cancel_pressed)
25161    {
25162       /* If currently showing a message box, close it */
25163       if (messagebox_active)
25164          menu_input_pointer_close_messagebox(&p_rarch->menu_driver_state);
25165       /* ...otherwise, invoke standard MENU_ACTION_CANCEL
25166        * action */
25167       else
25168       {
25169          size_t selection = menu_st->selection_ptr;
25170          ret = menu_entry_action(entry, selection, MENU_ACTION_CANCEL);
25171       }
25172    }
25173 
25174    /* If cancel has been released, disable any existing
25175     * cancel inhibit */
25176    if (!pointer_hw_state->cancel_pressed)
25177       menu_input->cancel_inhibit = false;
25178 
25179    if (!messagebox_active)
25180    {
25181       /* Up/Down
25182        * > Note 1: These always correspond to a mouse wheel, which
25183        *   handles differently from other inputs - i.e. we don't
25184        *   want a 'last pressed' check
25185        * > Note 2: If a message box is currently shown, must
25186        *   inhibit input */
25187 
25188       /* > Up */
25189       if (pointer_hw_state->up_pressed)
25190       {
25191          size_t selection = menu_st->selection_ptr;
25192          ret              = menu_entry_action(
25193                entry, selection, MENU_ACTION_UP);
25194       }
25195 
25196       /* > Down */
25197       if (pointer_hw_state->down_pressed)
25198       {
25199          size_t selection = menu_st->selection_ptr;
25200          ret              = menu_entry_action(
25201                entry, selection, MENU_ACTION_DOWN);
25202       }
25203 
25204       /* Left/Right
25205        * > Note 1: These also always correspond to a mouse wheel...
25206        *   In this case, it's a mouse wheel *tilt* operation, which
25207        *   is incredibly annoying because holding a tilt direction
25208        *   rapidly toggles the input state. The repeat speed is so
25209        *   high that any sort of useable control is impossible - so
25210        *   we have to apply a 'low pass' filter by ignoring inputs
25211        *   that occur below a certain frequency...
25212        * > Note 2: If a message box is currently shown, must
25213        *   inhibit input */
25214 
25215       /* > Left */
25216       if (      pointer_hw_state->left_pressed
25217             && !last_left_pressed)
25218       {
25219          if (current_time - last_left_action_time
25220                > MENU_INPUT_HORIZ_WHEEL_DELAY)
25221          {
25222             size_t selection      = menu_st->selection_ptr;
25223             last_left_action_time = current_time;
25224             ret                   = menu_entry_action(
25225                   entry, selection, MENU_ACTION_LEFT);
25226          }
25227       }
25228 
25229       /* > Right */
25230       if (
25231                 pointer_hw_state->right_pressed
25232             && !last_right_pressed)
25233       {
25234          if (current_time - last_right_action_time
25235                > MENU_INPUT_HORIZ_WHEEL_DELAY)
25236          {
25237             size_t selection       = menu_st->selection_ptr;
25238             last_right_action_time = current_time;
25239             ret                    = menu_entry_action(
25240                   entry, selection, MENU_ACTION_RIGHT);
25241          }
25242       }
25243    }
25244 
25245    last_select_pressed = pointer_hw_state->select_pressed;
25246    last_cancel_pressed = pointer_hw_state->cancel_pressed;
25247    last_left_pressed   = pointer_hw_state->left_pressed;
25248    last_right_pressed  = pointer_hw_state->right_pressed;
25249 
25250    return ret;
25251 }
25252 
menu_input_post_iterate(struct rarch_state * p_rarch,gfx_display_t * p_disp,struct menu_state * menu_st,unsigned action,retro_time_t current_time)25253 static int menu_input_post_iterate(
25254       struct rarch_state *p_rarch,
25255       gfx_display_t *p_disp,
25256       struct menu_state *menu_st,
25257       unsigned action,
25258       retro_time_t current_time)
25259 {
25260    menu_entry_t entry;
25261    menu_list_t *menu_list        = menu_st->entries.list;
25262    file_list_t *selection_buf    = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL;
25263    size_t selection              = menu_st->selection_ptr;
25264    menu_file_list_cbs_t *cbs     = selection_buf ?
25265       (menu_file_list_cbs_t*)selection_buf->list[selection].actiondata
25266       : NULL;
25267 
25268    MENU_ENTRY_INIT(entry);
25269    /* Note: If menu_input_pointer_post_iterate() is
25270     * modified, will have to verify that these
25271     * parameters remain unused... */
25272    entry.rich_label_enabled   = false;
25273    entry.value_enabled        = false;
25274    entry.sublabel_enabled     = false;
25275    menu_entry_get(&entry, 0, selection, NULL, false);
25276    return menu_input_pointer_post_iterate(p_rarch, p_disp,
25277          current_time, cbs, &entry, action);
25278 }
25279 #endif
25280 
input_keys_pressed_other_sources(struct rarch_state * p_rarch,unsigned i,input_bits_t * p_new_state)25281 static INLINE bool input_keys_pressed_other_sources(
25282       struct rarch_state *p_rarch,
25283       unsigned i,
25284       input_bits_t* p_new_state)
25285 {
25286 #ifdef HAVE_COMMAND
25287    int j;
25288    for (j = 0; j < ARRAY_SIZE(p_rarch->input_driver_command); j++)
25289       if ((i < RARCH_BIND_LIST_END) && p_rarch->input_driver_command[j]
25290          && p_rarch->input_driver_command[j]->state[i])
25291          return true;
25292 #endif
25293 
25294 #ifdef HAVE_OVERLAY
25295    if (p_rarch->overlay_ptr &&
25296          ((BIT256_GET(p_rarch->overlay_ptr->overlay_state.buttons, i))))
25297       return true;
25298 #endif
25299 
25300 #ifdef HAVE_NETWORKGAMEPAD
25301    /* Only process key presses related to game input if using Remote RetroPad */
25302    if (i < RARCH_CUSTOM_BIND_LIST_END
25303          && p_rarch->input_driver_remote
25304          && INPUT_REMOTE_KEY_PRESSED(p_rarch, i, 0))
25305       return true;
25306 #endif
25307 
25308    return false;
25309 }
25310 
25311 /**
25312  * input_keys_pressed:
25313  *
25314  * Grab an input sample for this frame.
25315  *
25316  * Returns: Input sample containing a mask of all pressed keys.
25317  */
input_keys_pressed(unsigned port,bool is_menu,int input_hotkey_block_delay,struct rarch_state * p_rarch,input_bits_t * p_new_state,const struct retro_keybind ** binds,const struct retro_keybind * binds_norm,const struct retro_keybind * binds_auto,rarch_joypad_info_t * joypad_info)25318 static void input_keys_pressed(
25319       unsigned port,
25320       bool is_menu,
25321       int input_hotkey_block_delay,
25322       struct rarch_state *p_rarch,
25323       input_bits_t *p_new_state,
25324       const struct retro_keybind **binds,
25325       const struct retro_keybind *binds_norm,
25326       const struct retro_keybind *binds_auto,
25327       rarch_joypad_info_t *joypad_info)
25328 {
25329    unsigned i;
25330 #ifdef HAVE_MFI
25331    const input_device_driver_t
25332       *sec_joypad                               = p_rarch->sec_joypad;
25333 #else
25334    const input_device_driver_t
25335       *sec_joypad                               = NULL;
25336 #endif
25337 
25338    if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY(binds_norm, binds_auto))
25339    {
25340       if (  input_state_wrap(
25341                p_rarch->current_input,
25342                p_rarch->current_input_data,
25343                p_rarch->joypad,
25344                sec_joypad,
25345                joypad_info,
25346                &binds[port],
25347                p_rarch->keyboard_mapping_blocked,
25348                port, RETRO_DEVICE_JOYPAD, 0,
25349                RARCH_ENABLE_HOTKEY))
25350       {
25351          if (p_rarch->input_hotkey_block_counter < input_hotkey_block_delay)
25352             p_rarch->input_hotkey_block_counter++;
25353          else
25354             p_rarch->input_driver_block_libretro_input = true;
25355       }
25356       else
25357       {
25358          p_rarch->input_hotkey_block_counter           = 0;
25359          p_rarch->input_driver_block_hotkey            = true;
25360       }
25361    }
25362 
25363    if (     !is_menu
25364          && binds[port][RARCH_GAME_FOCUS_TOGGLE].valid)
25365    {
25366       const struct retro_keybind *focus_binds_auto =
25367          &input_autoconf_binds[port][RARCH_GAME_FOCUS_TOGGLE];
25368       const struct retro_keybind *focus_normal     =
25369          &binds[port][RARCH_GAME_FOCUS_TOGGLE];
25370 
25371       /* Allows rarch_focus_toggle hotkey to still work
25372        * even though every hotkey is blocked */
25373       if (CHECK_INPUT_DRIVER_BLOCK_HOTKEY(
25374                focus_normal, focus_binds_auto))
25375       {
25376          if (input_state_wrap(
25377                   p_rarch->current_input,
25378                   p_rarch->current_input_data,
25379                   p_rarch->joypad,
25380                   sec_joypad,
25381                   joypad_info,
25382                   &binds[port],
25383                   p_rarch->keyboard_mapping_blocked,
25384                   port,
25385                   RETRO_DEVICE_JOYPAD, 0, RARCH_GAME_FOCUS_TOGGLE))
25386             p_rarch->input_driver_block_hotkey = false;
25387       }
25388    }
25389 
25390    {
25391       int16_t ret = 0;
25392 
25393       /* Check the libretro input first */
25394       if (!p_rarch->input_driver_block_libretro_input)
25395          ret = input_state_wrap(
25396                p_rarch->current_input,
25397                p_rarch->current_input_data,
25398                p_rarch->joypad,
25399                sec_joypad,
25400                joypad_info, &binds[port],
25401                p_rarch->keyboard_mapping_blocked,
25402                port, RETRO_DEVICE_JOYPAD, 0,
25403                RETRO_DEVICE_ID_JOYPAD_MASK);
25404 
25405       for (i = 0; i < RARCH_FIRST_META_KEY; i++)
25406       {
25407          if (
25408                (ret & (UINT64_C(1) <<  i)) ||
25409                input_keys_pressed_other_sources(p_rarch,
25410                   i, p_new_state))
25411          {
25412             BIT256_SET_PTR(p_new_state, i);
25413          }
25414       }
25415    }
25416 
25417    /* Check the hotkeys */
25418    if (p_rarch->input_driver_block_hotkey)
25419    {
25420       for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++)
25421       {
25422          if (
25423                   BIT64_GET(lifecycle_state, i)
25424                || input_keys_pressed_other_sources(p_rarch, i, p_new_state))
25425          {
25426             BIT256_SET_PTR(p_new_state, i);
25427          }
25428       }
25429    }
25430    else
25431    {
25432       for (i = RARCH_FIRST_META_KEY; i < RARCH_BIND_LIST_END; i++)
25433       {
25434          bool bit_pressed = binds[port][i].valid
25435             && input_state_wrap(
25436                   p_rarch->current_input,
25437                   p_rarch->current_input_data,
25438                   p_rarch->joypad,
25439                   sec_joypad,
25440                   joypad_info,
25441                   &binds[port],
25442                   p_rarch->keyboard_mapping_blocked,
25443                   port, RETRO_DEVICE_JOYPAD, 0, i);
25444          if (     bit_pressed
25445                || BIT64_GET(lifecycle_state, i)
25446                || input_keys_pressed_other_sources(p_rarch, i, p_new_state))
25447          {
25448             BIT256_SET_PTR(p_new_state, i);
25449          }
25450       }
25451    }
25452 }
25453 
input_driver_get_data(void)25454 void *input_driver_get_data(void)
25455 {
25456    struct rarch_state  *p_rarch   = &rarch_st;
25457    return p_rarch->current_input_data;
25458 }
25459 
input_driver_init_joypads(void)25460 void input_driver_init_joypads(void)
25461 {
25462    struct rarch_state *p_rarch = &rarch_st;
25463    settings_t *settings        = p_rarch->configuration_settings;
25464    p_rarch->joypad             = input_joypad_init_driver(
25465          settings->arrays.input_joypad_driver,
25466          p_rarch->current_input_data);
25467 #ifdef HAVE_MFI
25468    p_rarch->sec_joypad         = input_joypad_init_driver(
25469          "mfi",
25470          p_rarch->current_input_data);
25471 #endif
25472 }
25473 
input_driver_init_wrap(input_driver_t * input,const char * name)25474 void *input_driver_init_wrap(input_driver_t *input, const char *name)
25475 {
25476    void *ret                   = NULL;
25477    if (!input)
25478       return NULL;
25479    if ((ret = input->init(name)))
25480    {
25481       input_driver_init_joypads();
25482       return ret;
25483    }
25484    return NULL;
25485 }
25486 
input_driver_init(struct rarch_state * p_rarch,settings_t * settings)25487 static bool input_driver_init(struct rarch_state *p_rarch,
25488       settings_t *settings)
25489 {
25490    if (p_rarch->current_input)
25491       p_rarch->current_input_data = input_driver_init_wrap(
25492             p_rarch->current_input, settings->arrays.input_joypad_driver);
25493 
25494    return (p_rarch->current_input_data != NULL);
25495 }
25496 
input_driver_find_driver(struct rarch_state * p_rarch,settings_t * settings,const char * prefix,bool verbosity_enabled)25497 static bool input_driver_find_driver(
25498       struct rarch_state *p_rarch,
25499       settings_t *settings,
25500       const char *prefix,
25501       bool verbosity_enabled)
25502 {
25503    int i                = (int)driver_find_index(
25504          "input_driver",
25505          settings->arrays.input_driver);
25506 
25507    if (i >= 0)
25508    {
25509       p_rarch->current_input = (input_driver_t*)input_drivers[i];
25510       RARCH_LOG("[Input]: Found %s: \"%s\".\n", prefix,
25511             p_rarch->current_input->ident);
25512    }
25513    else
25514    {
25515       if (verbosity_enabled)
25516       {
25517          unsigned d;
25518          RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
25519                settings->arrays.input_driver);
25520          RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
25521          for (d = 0; input_drivers[d]; d++)
25522             RARCH_LOG_OUTPUT("\t%s\n", input_drivers[d]->ident);
25523          RARCH_WARN("Going to default to first %s...\n", prefix);
25524       }
25525 
25526       p_rarch->current_input = (input_driver_t*)input_drivers[0];
25527 
25528       if (!p_rarch->current_input)
25529       {
25530          retroarch_fail(p_rarch, 1, "find_input_driver()");
25531          return false;
25532       }
25533    }
25534 
25535    return true;
25536 }
25537 
input_driver_set_nonblock_state(void)25538 void input_driver_set_nonblock_state(void)
25539 {
25540    struct rarch_state *p_rarch = &rarch_st;
25541    p_rarch->input_driver_nonblock_state = true;
25542 }
25543 
input_driver_unset_nonblock_state(void)25544 void input_driver_unset_nonblock_state(void)
25545 {
25546    struct rarch_state *p_rarch = &rarch_st;
25547    p_rarch->input_driver_nonblock_state = false;
25548 }
25549 
25550 #ifdef HAVE_COMMAND
input_driver_init_command(struct rarch_state * p_rarch,settings_t * settings)25551 static void input_driver_init_command(struct rarch_state *p_rarch,
25552       settings_t *settings)
25553 {
25554    bool input_network_cmd_enable = settings->bools.network_cmd_enable;
25555    unsigned network_cmd_port     = settings->uints.network_cmd_port;
25556 #ifdef HAVE_STDIN_CMD
25557    bool input_stdin_cmd_enable   = settings->bools.stdin_cmd_enable;
25558 
25559    if (input_stdin_cmd_enable)
25560    {
25561       bool grab_stdin               = p_rarch->current_input->grab_stdin &&
25562          p_rarch->current_input->grab_stdin(p_rarch->current_input_data);
25563       if (grab_stdin)
25564       {
25565          RARCH_WARN("stdin command interface is desired, "
25566                "but input driver has already claimed stdin.\n"
25567                "Cannot use this command interface.\n");
25568       }
25569       else {
25570          p_rarch->input_driver_command[0] = command_stdin_new();
25571          if (!p_rarch->input_driver_command[1])
25572             RARCH_ERR("Failed to initialize the stdin command interface.\n");
25573       }
25574    }
25575 #endif
25576 
25577    /* Initialize the network command interface */
25578 #ifdef HAVE_NETWORK_CMD
25579    if (input_network_cmd_enable)
25580    {
25581       p_rarch->input_driver_command[1] = command_network_new(network_cmd_port);
25582       if (!p_rarch->input_driver_command[1])
25583          RARCH_ERR("Failed to initialize the network command interface.\n");
25584    }
25585 #endif
25586 
25587 #ifdef HAVE_LAKKA
25588    p_rarch->input_driver_command[2] = command_uds_new();
25589    if (!p_rarch->input_driver_command[2])
25590       RARCH_ERR("Failed to initialize the UDS command interface.\n");
25591 #endif
25592 }
25593 
input_driver_deinit_command(struct rarch_state * p_rarch)25594 static void input_driver_deinit_command(struct rarch_state *p_rarch)
25595 {
25596    int i;
25597    for (i = 0; i < ARRAY_SIZE(p_rarch->input_driver_command); i++)
25598    {
25599       if (p_rarch->input_driver_command[i])
25600          p_rarch->input_driver_command[i]->destroy(
25601             p_rarch->input_driver_command[i]);
25602 
25603       p_rarch->input_driver_command[i] = NULL;
25604     }
25605 }
25606 #endif
25607 
25608 #ifdef HAVE_NETWORKGAMEPAD
input_driver_init_remote(settings_t * settings,unsigned num_active_users)25609 static input_remote_t *input_driver_init_remote(
25610       settings_t *settings,
25611       unsigned num_active_users)
25612 {
25613    unsigned network_remote_base_port = settings->uints.network_remote_base_port;
25614    return input_remote_new(
25615          settings,
25616          network_remote_base_port,
25617          num_active_users);
25618 }
25619 #endif
25620 
input_driver_get_float(enum input_action action)25621 float *input_driver_get_float(enum input_action action)
25622 {
25623    struct rarch_state           *p_rarch = &rarch_st;
25624 
25625    switch (action)
25626    {
25627       case INPUT_ACTION_AXIS_THRESHOLD:
25628          return &p_rarch->input_driver_axis_threshold;
25629       default:
25630       case INPUT_ACTION_NONE:
25631          break;
25632    }
25633 
25634    return NULL;
25635 }
25636 
input_driver_get_uint(enum input_action action)25637 unsigned *input_driver_get_uint(enum input_action action)
25638 {
25639    struct rarch_state           *p_rarch = &rarch_st;
25640 
25641    switch (action)
25642    {
25643       case INPUT_ACTION_MAX_USERS:
25644          return &p_rarch->input_driver_max_users;
25645       default:
25646       case INPUT_ACTION_NONE:
25647          break;
25648    }
25649 
25650    return NULL;
25651 }
25652 
25653 /**
25654  * config_get_joypad_driver_options:
25655  *
25656  * Get an enumerated list of all joypad driver names, separated by '|'.
25657  *
25658  * Returns: string listing of all joypad driver names, separated by '|'.
25659  **/
config_get_joypad_driver_options(void)25660 const char* config_get_joypad_driver_options(void)
25661 {
25662    return char_list_new_special(STRING_LIST_INPUT_JOYPAD_DRIVERS, NULL);
25663 }
25664 
25665 /**
25666  * input_joypad_init_first:
25667  *
25668  * Finds first suitable joypad driver and initializes.
25669  *
25670  * Returns: joypad driver if found, otherwise NULL.
25671  **/
input_joypad_init_first(void * data)25672 static const input_device_driver_t *input_joypad_init_first(void *data)
25673 {
25674    unsigned i;
25675 
25676    for (i = 0; joypad_drivers[i]; i++)
25677    {
25678       if (     joypad_drivers[i]
25679             && joypad_drivers[i]->init)
25680       {
25681          void *ptr = joypad_drivers[i]->init(data);
25682          if (ptr)
25683          {
25684             RARCH_LOG("[Joypad]: Found joypad driver: \"%s\".\n",
25685                   joypad_drivers[i]->ident);
25686             return joypad_drivers[i];
25687          }
25688       }
25689    }
25690 
25691    return NULL;
25692 }
25693 
25694 /**
25695  * input_joypad_init_driver:
25696  * @ident                           : identifier of driver to initialize.
25697  *
25698  * Initialize a joypad driver of name @ident.
25699  *
25700  * If ident points to NULL or a zero-length string,
25701  * equivalent to calling input_joypad_init_first().
25702  *
25703  * Returns: joypad driver if found, otherwise NULL.
25704  **/
input_joypad_init_driver(const char * ident,void * data)25705 const input_device_driver_t *input_joypad_init_driver(
25706       const char *ident, void *data)
25707 {
25708    unsigned i;
25709    if (ident && *ident)
25710    {
25711       for (i = 0; joypad_drivers[i]; i++)
25712       {
25713          if (string_is_equal(ident, joypad_drivers[i]->ident)
25714                && joypad_drivers[i]->init)
25715          {
25716             void *ptr = joypad_drivers[i]->init(data);
25717             if (ptr)
25718             {
25719                RARCH_LOG("[Joypad]: Found joypad driver: \"%s\".\n",
25720                      joypad_drivers[i]->ident);
25721                return joypad_drivers[i];
25722             }
25723          }
25724       }
25725    }
25726 
25727    return input_joypad_init_first(data);
25728 }
25729 
input_key_pressed(int key,bool keyboard_pressed)25730 bool input_key_pressed(int key, bool keyboard_pressed)
25731 {
25732    /* If a keyboard key is pressed then immediately return
25733     * true, otherwise call button_is_pressed to determine
25734     * if the input comes from another input device */
25735    if (!(
25736             (key < RARCH_BIND_LIST_END)
25737             && keyboard_pressed
25738         )
25739       )
25740    {
25741       struct rarch_state *p_rarch    = &rarch_st;
25742       const input_device_driver_t
25743          *joypad                     = (const input_device_driver_t*)
25744          p_rarch->joypad;
25745       const uint64_t bind_joykey     = input_config_binds[0][key].joykey;
25746       const uint64_t bind_joyaxis    = input_config_binds[0][key].joyaxis;
25747       const uint64_t autobind_joykey = input_autoconf_binds[0][key].joykey;
25748       const uint64_t autobind_joyaxis= input_autoconf_binds[0][key].joyaxis;
25749       uint16_t port                  = 0;
25750       float axis_threshold           = p_rarch->input_driver_axis_threshold;
25751       const uint64_t joykey          = (bind_joykey != NO_BTN)
25752          ? bind_joykey  : autobind_joykey;
25753       const uint32_t joyaxis         = (bind_joyaxis != AXIS_NONE)
25754          ? bind_joyaxis : autobind_joyaxis;
25755 
25756       if ((uint16_t)joykey != NO_BTN && joypad->button(
25757                port, (uint16_t)joykey))
25758          return true;
25759       if (joyaxis != AXIS_NONE &&
25760             ((float)abs(joypad->axis(port, joyaxis))
25761              / 0x8000) > axis_threshold)
25762          return true;
25763       return false;
25764    }
25765    return true;
25766 }
25767 
input_mouse_grabbed(void)25768 bool input_mouse_grabbed(void)
25769 {
25770    struct rarch_state *p_rarch = &rarch_st;
25771    return p_rarch->input_driver_grab_mouse_state;
25772 }
25773 
25774 /**
25775  * input_joypad_analog:
25776  * @drv                     : Input device driver handle.
25777  * @port                    : User number.
25778  * @idx                     : Analog key index.
25779  *                            E.g.:
25780  *                            - RETRO_DEVICE_INDEX_ANALOG_LEFT
25781  *                            - RETRO_DEVICE_INDEX_ANALOG_RIGHT
25782  * @ident                   : Analog key identifier.
25783  *                            E.g.:
25784  *                            - RETRO_DEVICE_ID_ANALOG_X
25785  *                            - RETRO_DEVICE_ID_ANALOG_Y
25786  * @binds                   : Binds of user.
25787  *
25788  * Gets analog value of analog key identifiers @idx and @ident
25789  * from user with number @port with provided keybinds (@binds).
25790  *
25791  * Returns: analog value on success, otherwise 0.
25792  **/
input_joypad_analog_button(float input_analog_deadzone,float input_analog_sensitivity,const input_device_driver_t * drv,rarch_joypad_info_t * joypad_info,unsigned ident,const struct retro_keybind * bind)25793 static int16_t input_joypad_analog_button(
25794       float input_analog_deadzone,
25795       float input_analog_sensitivity,
25796       const input_device_driver_t *drv,
25797       rarch_joypad_info_t *joypad_info,
25798       unsigned ident,
25799       const struct retro_keybind *bind)
25800 {
25801    int16_t res                      = 0;
25802    float normal_mag                 = 0.0f;
25803    uint32_t axis                    = (bind->joyaxis == AXIS_NONE)
25804       ? joypad_info->auto_binds[ident].joyaxis
25805       : bind->joyaxis;
25806 
25807    /* Analog button. */
25808    if (input_analog_deadzone)
25809    {
25810       int16_t mult = 0;
25811       if (axis != AXIS_NONE)
25812          if ((mult = drv->axis(
25813                      joypad_info->joy_idx, axis)) != 0)
25814             normal_mag   = fabs((1.0f / 0x7fff) * mult);
25815    }
25816 
25817    /* If the result is zero, it's got a digital button
25818     * attached to it instead */
25819    if ((res = abs(input_joypad_axis(
25820             input_analog_deadzone,
25821             input_analog_sensitivity,
25822             drv,
25823             joypad_info->joy_idx, axis, normal_mag))) == 0)
25824    {
25825       uint16_t key = (bind->joykey == NO_BTN)
25826          ? joypad_info->auto_binds[ident].joykey
25827          : bind->joykey;
25828 
25829       if (drv->button(joypad_info->joy_idx, key))
25830          return 0x7fff;
25831       return 0;
25832    }
25833 
25834    return res;
25835 }
25836 
input_joypad_analog_axis(unsigned input_analog_dpad_mode,float input_analog_deadzone,float input_analog_sensitivity,const input_device_driver_t * drv,rarch_joypad_info_t * joypad_info,unsigned idx,unsigned ident,const struct retro_keybind * binds)25837 static int16_t input_joypad_analog_axis(
25838       unsigned input_analog_dpad_mode,
25839       float input_analog_deadzone,
25840       float input_analog_sensitivity,
25841       const input_device_driver_t *drv,
25842       rarch_joypad_info_t *joypad_info,
25843       unsigned idx,
25844       unsigned ident,
25845       const struct retro_keybind *binds)
25846 {
25847    int16_t res                              = 0;
25848    /* Analog sticks. Either RETRO_DEVICE_INDEX_ANALOG_LEFT
25849     * or RETRO_DEVICE_INDEX_ANALOG_RIGHT */
25850    unsigned ident_minus                     = 0;
25851    unsigned ident_plus                      = 0;
25852    unsigned ident_x_minus                   = 0;
25853    unsigned ident_x_plus                    = 0;
25854    unsigned ident_y_minus                   = 0;
25855    unsigned ident_y_plus                    = 0;
25856    const struct retro_keybind *bind_minus   = NULL;
25857    const struct retro_keybind *bind_plus    = NULL;
25858    const struct retro_keybind *bind_x_minus = NULL;
25859    const struct retro_keybind *bind_x_plus  = NULL;
25860    const struct retro_keybind *bind_y_minus = NULL;
25861    const struct retro_keybind *bind_y_plus  = NULL;
25862 
25863    /* Skip analog input with analog_dpad_mode */
25864    switch (input_analog_dpad_mode)
25865    {
25866       case ANALOG_DPAD_LSTICK:
25867          if (idx == RETRO_DEVICE_INDEX_ANALOG_LEFT)
25868             return 0;
25869          break;
25870       case ANALOG_DPAD_RSTICK:
25871          if (idx == RETRO_DEVICE_INDEX_ANALOG_RIGHT)
25872             return 0;
25873          break;
25874       default:
25875          break;
25876    }
25877 
25878    input_conv_analog_id_to_bind_id(idx, ident, ident_minus, ident_plus);
25879 
25880    bind_minus                             = &binds[ident_minus];
25881    bind_plus                              = &binds[ident_plus];
25882 
25883    if (!bind_minus->valid || !bind_plus->valid)
25884       return 0;
25885 
25886    input_conv_analog_id_to_bind_id(idx,
25887          RETRO_DEVICE_ID_ANALOG_X, ident_x_minus, ident_x_plus);
25888 
25889    bind_x_minus = &binds[ident_x_minus];
25890    bind_x_plus  = &binds[ident_x_plus];
25891 
25892    if (!bind_x_minus->valid || !bind_x_plus->valid)
25893       return 0;
25894 
25895    input_conv_analog_id_to_bind_id(idx,
25896          RETRO_DEVICE_ID_ANALOG_Y, ident_y_minus, ident_y_plus);
25897 
25898    bind_y_minus = &binds[ident_y_minus];
25899    bind_y_plus  = &binds[ident_y_plus];
25900 
25901    if (!bind_y_minus->valid || !bind_y_plus->valid)
25902       return 0;
25903 
25904    {
25905       uint32_t axis_minus            = (bind_minus->joyaxis   == AXIS_NONE)
25906          ? joypad_info->auto_binds[ident_minus].joyaxis
25907          : bind_minus->joyaxis;
25908       uint32_t axis_plus             = (bind_plus->joyaxis    == AXIS_NONE)
25909          ? joypad_info->auto_binds[ident_plus].joyaxis
25910          : bind_plus->joyaxis;
25911       float normal_mag               = 0.0f;
25912 
25913       /* normalized magnitude of stick actuation, needed for scaled
25914        * radial deadzone */
25915       if (input_analog_deadzone)
25916       {
25917          float x                  = 0.0f;
25918          float y                  = 0.0f;
25919          uint32_t x_axis_minus    = (bind_x_minus->joyaxis == AXIS_NONE)
25920             ? joypad_info->auto_binds[ident_x_minus].joyaxis
25921             : bind_x_minus->joyaxis;
25922          uint32_t x_axis_plus     = (bind_x_plus->joyaxis  == AXIS_NONE)
25923             ? joypad_info->auto_binds[ident_x_plus].joyaxis
25924             : bind_x_plus->joyaxis;
25925          uint32_t y_axis_minus    = (bind_y_minus->joyaxis == AXIS_NONE)
25926             ? joypad_info->auto_binds[ident_y_minus].joyaxis
25927             : bind_y_minus->joyaxis;
25928          uint32_t y_axis_plus     = (bind_y_plus->joyaxis  == AXIS_NONE)
25929             ? joypad_info->auto_binds[ident_y_plus].joyaxis
25930             : bind_y_plus->joyaxis;
25931          /* normalized magnitude for radial scaled analog deadzone */
25932          if (x_axis_plus != AXIS_NONE)
25933             x                     = drv->axis(
25934                   joypad_info->joy_idx, x_axis_plus);
25935          if (x_axis_minus != AXIS_NONE)
25936             x                    += drv->axis(joypad_info->joy_idx,
25937                   x_axis_minus);
25938          if (y_axis_plus != AXIS_NONE)
25939             y                     = drv->axis(
25940                joypad_info->joy_idx, y_axis_plus);
25941          if (y_axis_minus != AXIS_NONE)
25942             y                    += drv->axis(
25943                   joypad_info->joy_idx, y_axis_minus);
25944          normal_mag               = (1.0f / 0x7fff) * sqrt(x * x + y * y);
25945       }
25946 
25947       res           = abs(
25948             input_joypad_axis(
25949                input_analog_deadzone,
25950                input_analog_sensitivity,
25951                drv, joypad_info->joy_idx,
25952                axis_plus, normal_mag));
25953       res          -= abs(
25954             input_joypad_axis(
25955                input_analog_deadzone,
25956                input_analog_sensitivity,
25957                drv, joypad_info->joy_idx,
25958                axis_minus, normal_mag));
25959    }
25960 
25961    if (res == 0)
25962    {
25963       uint16_t key_minus    = (bind_minus->joykey == NO_BTN)
25964          ? joypad_info->auto_binds[ident_minus].joykey
25965          : bind_minus->joykey;
25966       uint16_t key_plus     = (bind_plus->joykey  == NO_BTN)
25967          ? joypad_info->auto_binds[ident_plus].joykey
25968          : bind_plus->joykey;
25969       if (drv->button(joypad_info->joy_idx, key_plus))
25970          res  = 0x7fff;
25971       if (drv->button(joypad_info->joy_idx, key_minus))
25972          res += -0x7fff;
25973    }
25974 
25975    return res;
25976 }
25977 
25978 #ifdef HAVE_MENU
25979 /**
25980  * input_mouse_button_raw:
25981  * @port                    : Mouse number.
25982  * @button                  : Identifier of key (libretro mouse constant).
25983  *
25984  * Checks if key (@button) was being pressed by user
25985  * with mouse number @port.
25986  *
25987  * Returns: true (1) if key was pressed, otherwise
25988  * false (0).
25989  **/
input_mouse_button_raw(struct rarch_state * p_rarch,input_driver_t * current_input,unsigned joy_idx,unsigned port,unsigned id)25990 static bool input_mouse_button_raw(
25991       struct rarch_state *p_rarch,
25992       input_driver_t *current_input,
25993       unsigned joy_idx,
25994       unsigned port, unsigned id)
25995 {
25996    rarch_joypad_info_t joypad_info;
25997 #ifdef HAVE_MFI
25998    const input_device_driver_t
25999       *sec_joypad                    = p_rarch->sec_joypad;
26000 #else
26001    const input_device_driver_t
26002       *sec_joypad                    = NULL;
26003 #endif
26004 
26005    /*ignore axes*/
26006    if (id == RETRO_DEVICE_ID_MOUSE_X || id == RETRO_DEVICE_ID_MOUSE_Y)
26007       return false;
26008 
26009    joypad_info.axis_threshold        = p_rarch->input_driver_axis_threshold;
26010    joypad_info.joy_idx               = joy_idx;
26011    joypad_info.auto_binds            = input_autoconf_binds[joy_idx];
26012 
26013    if (current_input->input_state)
26014       return current_input->input_state(
26015             p_rarch->current_input_data,
26016             p_rarch->joypad,
26017             sec_joypad,
26018             &joypad_info,
26019             p_rarch->libretro_input_binds,
26020             p_rarch->keyboard_mapping_blocked,
26021             port,
26022             RETRO_DEVICE_MOUSE, 0, id);
26023    return false;
26024 }
26025 #endif
26026 
input_pad_connect(unsigned port,input_device_driver_t * driver)26027 void input_pad_connect(unsigned port, input_device_driver_t *driver)
26028 {
26029    struct rarch_state *p_rarch = &rarch_st;
26030    if (port >= MAX_USERS || !driver)
26031    {
26032       RARCH_ERR("[Input]: input_pad_connect: bad parameters\n");
26033       return;
26034    }
26035 
26036    if (p_rarch->pad_connection_listener)
26037       p_rarch->pad_connection_listener->connected(port, driver);
26038 
26039    input_autoconfigure_connect(driver->name(port), NULL, driver->ident,
26040           port, 0, 0);
26041 }
26042 
26043 #ifdef HAVE_HID
hid_driver_get_data(void)26044 const void *hid_driver_get_data(void)
26045 {
26046    struct rarch_state *p_rarch = &rarch_st;
26047    return p_rarch->hid_data;
26048 }
26049 
26050 /* This is only to be called after we've invoked free() on the
26051  * HID driver; the memory will have already been freed, so we need to
26052  * reset the pointer.
26053  */
hid_driver_reset_data(void)26054 void hid_driver_reset_data(void)
26055 {
26056    struct rarch_state *p_rarch = &rarch_st;
26057    p_rarch->hid_data = NULL;
26058 }
26059 
26060 /**
26061  * config_get_hid_driver_options:
26062  *
26063  * Get an enumerated list of all HID driver names, separated by '|'.
26064  *
26065  * Returns: string listing of all HID driver names, separated by '|'.
26066  **/
config_get_hid_driver_options(void)26067 const char* config_get_hid_driver_options(void)
26068 {
26069    return char_list_new_special(STRING_LIST_INPUT_HID_DRIVERS, NULL);
26070 }
26071 
26072 /**
26073  * input_hid_init_first:
26074  *
26075  * Finds first suitable HID driver and initializes.
26076  *
26077  * Returns: HID driver if found, otherwise NULL.
26078  **/
input_hid_init_first(void)26079 const hid_driver_t *input_hid_init_first(void)
26080 {
26081    unsigned i;
26082    struct rarch_state *p_rarch = &rarch_st;
26083 
26084    for (i = 0; hid_drivers[i]; i++)
26085    {
26086       p_rarch->hid_data = hid_drivers[i]->init();
26087 
26088       if (p_rarch->hid_data)
26089       {
26090          RARCH_LOG("[Input]: Found HID driver: \"%s\".\n",
26091                hid_drivers[i]->ident);
26092          return hid_drivers[i];
26093       }
26094    }
26095 
26096    return NULL;
26097 }
26098 #endif
26099 
26100 /**
26101  * input_keyboard_line_event:
26102  * @state                    : Input keyboard line handle.
26103  * @character                : Inputted character.
26104  *
26105  * Called on every keyboard character event.
26106  *
26107  * Returns: true (1) on success, otherwise false (0).
26108  **/
input_keyboard_line_event(struct rarch_state * p_rarch,input_keyboard_line_t * state,uint32_t character)26109 static bool input_keyboard_line_event(
26110       struct rarch_state *p_rarch,
26111       input_keyboard_line_t *state, uint32_t character)
26112 {
26113    char array[2];
26114    bool            ret         = false;
26115    const char            *word = NULL;
26116    char            c           = (character >= 128) ? '?' : character;
26117 
26118    /* Treat extended chars as ? as we cannot support
26119     * printable characters for unicode stuff. */
26120 
26121    if (c == '\r' || c == '\n')
26122    {
26123       state->cb(state->userdata, state->buffer);
26124 
26125       array[0] = c;
26126       array[1] = 0;
26127 
26128       ret      = true;
26129       word     = array;
26130    }
26131    else if (c == '\b' || c == '\x7f') /* 0x7f is ASCII for del */
26132    {
26133       if (state->ptr)
26134       {
26135          unsigned i;
26136 
26137          for (i = 0; i < p_rarch->osk_last_codepoint_len; i++)
26138          {
26139             memmove(state->buffer + state->ptr - 1,
26140                   state->buffer + state->ptr,
26141                   state->size - state->ptr + 1);
26142             state->ptr--;
26143             state->size--;
26144          }
26145 
26146          word     = state->buffer;
26147       }
26148    }
26149    else if (ISPRINT(c))
26150    {
26151       /* Handle left/right here when suitable */
26152       char *newbuf = (char*)
26153          realloc(state->buffer, state->size + 2);
26154       if (!newbuf)
26155          return false;
26156 
26157       memmove(newbuf + state->ptr + 1,
26158             newbuf + state->ptr,
26159             state->size - state->ptr + 1);
26160       newbuf[state->ptr] = c;
26161       state->ptr++;
26162       state->size++;
26163       newbuf[state->size] = '\0';
26164 
26165       state->buffer = newbuf;
26166 
26167       array[0] = c;
26168       array[1] = 0;
26169 
26170       word     = array;
26171    }
26172 
26173    if (word)
26174    {
26175       /* OSK - update last character */
26176       if (word[0] == 0)
26177       {
26178          p_rarch->osk_last_codepoint     = 0;
26179          p_rarch->osk_last_codepoint_len = 0;
26180       }
26181       else
26182          osk_update_last_codepoint(
26183                &p_rarch->osk_last_codepoint,
26184                &p_rarch->osk_last_codepoint_len,
26185                word);
26186    }
26187 
26188    return ret;
26189 }
26190 
26191 #ifdef HAVE_MENU
input_keyboard_line_append(struct input_keyboard_line * keyboard_line,const char * word)26192 static bool input_keyboard_line_append(
26193       struct input_keyboard_line *keyboard_line,
26194       const char *word)
26195 {
26196    unsigned i                  = 0;
26197    unsigned len                = (unsigned)strlen(word);
26198    char *newbuf                = (char*)realloc(
26199          keyboard_line->buffer,
26200          keyboard_line->size + len * 2);
26201 
26202    if (!newbuf)
26203       return false;
26204 
26205    memmove(
26206          newbuf + keyboard_line->ptr + len,
26207          newbuf + keyboard_line->ptr,
26208          keyboard_line->size - keyboard_line->ptr + len);
26209 
26210    for (i = 0; i < len; i++)
26211    {
26212       newbuf[keyboard_line->ptr]= word[i];
26213       keyboard_line->ptr++;
26214       keyboard_line->size++;
26215    }
26216 
26217    newbuf[keyboard_line->size]  = '\0';
26218 
26219    keyboard_line->buffer        = newbuf;
26220    return true;
26221 }
26222 
26223 /**
26224  * input_keyboard_start_line:
26225  * @userdata                 : Userdata.
26226  * @cb                       : Line complete callback function.
26227  *
26228  * Sets function pointer for keyboard line handle.
26229  *
26230  * The underlying buffer can be reallocated at any time
26231  * (or be NULL), but the pointer to it remains constant
26232  * throughout the objects lifetime.
26233  *
26234  * Returns: underlying buffer of the keyboard line.
26235  **/
input_keyboard_start_line(void * userdata,struct input_keyboard_line * keyboard_line,input_keyboard_line_complete_t cb)26236 static const char **input_keyboard_start_line(
26237       void *userdata,
26238       struct input_keyboard_line *keyboard_line,
26239       input_keyboard_line_complete_t cb)
26240 {
26241    keyboard_line->buffer    = NULL;
26242    keyboard_line->ptr       = 0;
26243    keyboard_line->size      = 0;
26244    keyboard_line->cb        = cb;
26245    keyboard_line->userdata  = userdata;
26246    keyboard_line->enabled   = true;
26247 
26248    return (const char**)&keyboard_line->buffer;
26249 }
26250 
26251 #ifdef HAVE_ACCESSIBILITY
accessibility_lut_name(char key)26252 static const char *accessibility_lut_name(char key)
26253 {
26254    switch (key)
26255    {
26256 #if 0
26257       /* TODO/FIXME - overlaps with tilde */
26258       case '`':
26259          return "left quote";
26260 #endif
26261       case '`':
26262          return "tilde";
26263       case '!':
26264          return "exclamation point";
26265       case '@':
26266          return "at sign";
26267       case '#':
26268          return "hash sign";
26269       case '$':
26270          return "dollar sign";
26271       case '%':
26272          return "percent sign";
26273       case '^':
26274          return "carrot";
26275       case '&':
26276          return "ampersand";
26277       case '*':
26278          return "asterisk";
26279       case '(':
26280          return "left bracket";
26281       case ')':
26282          return "right bracket";
26283       case '-':
26284          return "minus";
26285       case '_':
26286          return "underscore";
26287       case '=':
26288          return "equals";
26289       case '+':
26290          return "plus";
26291       case '[':
26292          return "left square bracket";
26293       case '{':
26294          return "left curl bracket";
26295       case ']':
26296          return "right square bracket";
26297       case '}':
26298          return "right curl bracket";
26299       case '\\':
26300          return "back slash";
26301       case '|':
26302          return "pipe";
26303       case ';':
26304          return "semicolon";
26305       case ':':
26306          return "colon";
26307       case '\'':
26308          return "single quote";
26309       case '\"':
26310          return "double quote";
26311       case ',':
26312          return "comma";
26313       case '<':
26314          return "left angle bracket";
26315       case '.':
26316          return "period";
26317       case '>':
26318          return "right angle bracket";
26319       case '/':
26320          return "front slash";
26321       case '?':
26322          return "question mark";
26323       case ' ':
26324          return "space";
26325       default:
26326          break;
26327    }
26328    return NULL;
26329 }
26330 #endif
26331 #endif
26332 
26333 /**
26334  * input_keyboard_event:
26335  * @down                     : Keycode was pressed down?
26336  * @code                     : Keycode.
26337  * @character                : Character inputted.
26338  * @mod                      : TODO/FIXME: ???
26339  *
26340  * Keyboard event utils. Called by drivers when keyboard events are fired.
26341  * This interfaces with the global system driver struct and libretro callbacks.
26342  **/
input_keyboard_event(bool down,unsigned code,uint32_t character,uint16_t mod,unsigned device)26343 void input_keyboard_event(bool down, unsigned code,
26344       uint32_t character, uint16_t mod, unsigned device)
26345 {
26346    static bool deferred_wait_keys;
26347    struct rarch_state *p_rarch   = &rarch_st;
26348 #ifdef HAVE_ACCESSIBILITY
26349    settings_t *settings          = p_rarch->configuration_settings;
26350    bool accessibility_enable     = settings->bools.accessibility_enable;
26351    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
26352 #endif
26353 #ifdef HAVE_MENU
26354    struct menu_state *menu_st    = &p_rarch->menu_driver_state;
26355 
26356    /* If screensaver is active, then it should be
26357     * disabled if:
26358     * - Key is down AND
26359     * - OSK is active, OR:
26360     * - Key is *not* mapped to RetroPad input (these
26361     *   inputs are handled in menu_event() - if we
26362     *   allow mapped RetroPad keys to toggle off
26363     *   the screensaver, then we end up with a 'duplicate'
26364     *   input that will trigger unwanted menu action)
26365     * - For extra amusement, a number of keyboard keys
26366     *   are hard-coded to RetroPad inputs (while the menu
26367     *   is running) in such a way that they cannot be
26368     *   detected via the regular 'keyboard_mapping_bits'
26369     *   record. We therefore have to check each of these
26370     *   explicitly...
26371     * Otherwise, input is ignored whenever screensaver
26372     * is active */
26373    if (menu_st->screensaver_active)
26374    {
26375       if (down &&
26376           (code != RETROK_UNKNOWN) &&
26377           (menu_input_dialog_get_display_kb() ||
26378                !((code == RETROK_SPACE)     || /* RETRO_DEVICE_ID_JOYPAD_START */
26379                  (code == RETROK_SLASH)     || /* RETRO_DEVICE_ID_JOYPAD_X */
26380                  (code == RETROK_RSHIFT)    || /* RETRO_DEVICE_ID_JOYPAD_SELECT */
26381                  (code == RETROK_RIGHT)     || /* RETRO_DEVICE_ID_JOYPAD_RIGHT */
26382                  (code == RETROK_LEFT)      || /* RETRO_DEVICE_ID_JOYPAD_LEFT */
26383                  (code == RETROK_DOWN)      || /* RETRO_DEVICE_ID_JOYPAD_DOWN */
26384                  (code == RETROK_UP)        || /* RETRO_DEVICE_ID_JOYPAD_UP */
26385                  (code == RETROK_PAGEUP)    || /* RETRO_DEVICE_ID_JOYPAD_L */
26386                  (code == RETROK_PAGEDOWN)  || /* RETRO_DEVICE_ID_JOYPAD_R */
26387                  (code == RETROK_BACKSPACE) || /* RETRO_DEVICE_ID_JOYPAD_B */
26388                  (code == RETROK_RETURN)    || /* RETRO_DEVICE_ID_JOYPAD_A */
26389                  (code == RETROK_DELETE)    || /* RETRO_DEVICE_ID_JOYPAD_Y */
26390                  BIT512_GET(p_rarch->keyboard_mapping_bits, code))))
26391       {
26392          menu_ctx_environment_t menu_environ;
26393          menu_environ.type           = MENU_ENVIRON_DISABLE_SCREENSAVER;
26394          menu_environ.data           = NULL;
26395          menu_st->screensaver_active = false;
26396          menu_st->input_last_time_us = menu_st->current_time_us;
26397          menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
26398       }
26399       return;
26400    }
26401 
26402    if (down)
26403       menu_st->input_last_time_us = menu_st->current_time_us;
26404 
26405 #ifdef HAVE_ACCESSIBILITY
26406    if (menu_input_dialog_get_display_kb()
26407          && down && is_accessibility_enabled(
26408             accessibility_enable,
26409             p_rarch->accessibility_enabled))
26410    {
26411       if (code != 303 && code != 0)
26412       {
26413          char* say_char = (char*)malloc(sizeof(char)+1);
26414 
26415          if (say_char)
26416          {
26417             char c    = (char) character;
26418             *say_char = c;
26419             say_char[1] = '\0';
26420 
26421             if (character == 127 || character == 8)
26422                accessibility_speak_priority(p_rarch,
26423                      accessibility_enable,
26424                      accessibility_narrator_speech_speed,
26425                      "backspace", 10);
26426             else
26427             {
26428                const char *lut_name = accessibility_lut_name(c);
26429 
26430                if (lut_name)
26431                   accessibility_speak_priority(p_rarch,
26432                         accessibility_enable,
26433                         accessibility_narrator_speech_speed,
26434                         lut_name, 10);
26435                else if (character != 0)
26436                   accessibility_speak_priority(p_rarch,
26437                         accessibility_enable,
26438                         accessibility_narrator_speech_speed,
26439                         say_char, 10);
26440             }
26441             free(say_char);
26442          }
26443       }
26444    }
26445 #endif
26446 #endif
26447 
26448    if (deferred_wait_keys)
26449    {
26450       if (down)
26451          return;
26452 
26453       p_rarch->keyboard_press_cb                       = NULL;
26454       p_rarch->keyboard_press_data                     = NULL;
26455       p_rarch->keyboard_mapping_blocked                = false;
26456       deferred_wait_keys                               = false;
26457    }
26458    else if (p_rarch->keyboard_press_cb)
26459    {
26460       if (!down || code == RETROK_UNKNOWN)
26461          return;
26462       if (p_rarch->keyboard_press_cb(p_rarch->keyboard_press_data, code))
26463          return;
26464       deferred_wait_keys = true;
26465    }
26466    else if (p_rarch->keyboard_line.enabled)
26467    {
26468       if (!down)
26469          return;
26470 
26471       switch (device)
26472       {
26473          case RETRO_DEVICE_POINTER:
26474             if (code != 0x12d)
26475                character = (char)code;
26476             /* fall-through */
26477          default:
26478             if (!input_keyboard_line_event(p_rarch,
26479                      &p_rarch->keyboard_line, character))
26480                return;
26481             break;
26482       }
26483 
26484       /* Line is complete, can free it now. */
26485       if (p_rarch->keyboard_line.buffer)
26486          free(p_rarch->keyboard_line.buffer);
26487       p_rarch->keyboard_line.buffer                    = NULL;
26488       p_rarch->keyboard_line.ptr                       = 0;
26489       p_rarch->keyboard_line.size                      = 0;
26490       p_rarch->keyboard_line.cb                        = NULL;
26491       p_rarch->keyboard_line.userdata                  = NULL;
26492       p_rarch->keyboard_line.enabled                   = false;
26493 
26494       /* Unblock all hotkeys. */
26495       p_rarch->keyboard_mapping_blocked                = false;
26496    }
26497    else
26498    {
26499       if (code == RETROK_UNKNOWN)
26500          return;
26501 
26502       /* Block hotkey + RetroPad mapped keyboard key events,
26503        * but not with game focus, and from keyboard device type,
26504        * and with 'enable_hotkey' modifier set and unpressed */
26505       if (!p_rarch->game_focus_state.enabled &&
26506             BIT512_GET(p_rarch->keyboard_mapping_bits, code))
26507       {
26508          input_mapper_t *handle      = &p_rarch->input_driver_mapper;
26509          struct retro_keybind hotkey = input_config_binds[0][RARCH_ENABLE_HOTKEY];
26510          bool hotkey_pressed         =
26511                (p_rarch->input_hotkey_block_counter > 0) || (hotkey.key == code);
26512 
26513          if (!(MAPPER_GET_KEY(handle, code)) &&
26514                !(!hotkey_pressed && (
26515                   hotkey.key     != RETROK_UNKNOWN ||
26516                   hotkey.joykey  != NO_BTN ||
26517                   hotkey.joyaxis != AXIS_NONE
26518                )))
26519             return;
26520       }
26521 
26522       {
26523          retro_keyboard_event_t *key_event = &runloop_state.key_event;
26524          if (*key_event)
26525             (*key_event)(down, code, character, mod);
26526       }
26527    }
26528 }
26529 
input_config_bind_map_get_valid(unsigned bind_index)26530 static bool input_config_bind_map_get_valid(unsigned bind_index)
26531 {
26532    const struct input_bind_map *keybind =
26533       (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
26534    if (!keybind)
26535       return false;
26536    return keybind->valid;
26537 }
26538 
input_config_bind_map_get_meta(unsigned bind_index)26539 unsigned input_config_bind_map_get_meta(unsigned bind_index)
26540 {
26541    const struct input_bind_map *keybind =
26542       (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
26543    if (!keybind)
26544       return 0;
26545    return keybind->meta;
26546 }
26547 
input_config_bind_map_get_base(unsigned bind_index)26548 const char *input_config_bind_map_get_base(unsigned bind_index)
26549 {
26550    const struct input_bind_map *keybind =
26551       (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
26552    if (!keybind)
26553       return NULL;
26554    return keybind->base;
26555 }
26556 
input_config_bind_map_get_desc(unsigned bind_index)26557 const char *input_config_bind_map_get_desc(unsigned bind_index)
26558 {
26559    const struct input_bind_map *keybind =
26560       (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
26561    if (!keybind)
26562       return NULL;
26563    return msg_hash_to_str(keybind->desc);
26564 }
26565 
input_config_bind_map_get_retro_key(unsigned bind_index)26566 uint8_t input_config_bind_map_get_retro_key(unsigned bind_index)
26567 {
26568    const struct input_bind_map *keybind =
26569       (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
26570    if (!keybind)
26571       return 0;
26572    return keybind->retro_key;
26573 }
26574 
input_config_get_prefix(unsigned user,bool meta)26575 static const char *input_config_get_prefix(unsigned user, bool meta)
26576 {
26577    static const char *bind_user_prefix[MAX_USERS] = {
26578       "input_player1",
26579       "input_player2",
26580       "input_player3",
26581       "input_player4",
26582       "input_player5",
26583       "input_player6",
26584       "input_player7",
26585       "input_player8",
26586       "input_player9",
26587       "input_player10",
26588       "input_player11",
26589       "input_player12",
26590       "input_player13",
26591       "input_player14",
26592       "input_player15",
26593       "input_player16",
26594    };
26595    if (meta)
26596    {
26597       if (user == 0)
26598          return "input";
26599       /* Don't bother with meta bind for anyone else than first user. */
26600       return NULL;
26601    }
26602    return bind_user_prefix[user];
26603 }
26604 
26605 /**
26606  * input_config_translate_str_to_rk:
26607  * @str                            : String to translate to key ID.
26608  *
26609  * Translates tring representation to key identifier.
26610  *
26611  * Returns: key identifier.
26612  **/
input_config_translate_str_to_rk(const char * str)26613 enum retro_key input_config_translate_str_to_rk(const char *str)
26614 {
26615    size_t i;
26616    if (strlen(str) == 1 && ISALPHA((int)*str))
26617       return (enum retro_key)(RETROK_a + (TOLOWER((int)*str) - (int)'a'));
26618    for (i = 0; input_config_key_map[i].str; i++)
26619    {
26620       if (string_is_equal_noncase(input_config_key_map[i].str, str))
26621          return input_config_key_map[i].key;
26622    }
26623 
26624    RARCH_WARN("[Input]: Key name \"%s\" not found.\n", str);
26625    return RETROK_UNKNOWN;
26626 }
26627 
26628 /**
26629  * input_config_translate_str_to_bind_id:
26630  * @str                            : String to translate to bind ID.
26631  *
26632  * Translate string representation to bind ID.
26633  *
26634  * Returns: Bind ID value on success, otherwise
26635  * RARCH_BIND_LIST_END on not found.
26636  **/
input_config_translate_str_to_bind_id(const char * str)26637 unsigned input_config_translate_str_to_bind_id(const char *str)
26638 {
26639    unsigned i;
26640 
26641    for (i = 0; input_config_bind_map[i].valid; i++)
26642       if (string_is_equal(str, input_config_bind_map[i].base))
26643          return i;
26644 
26645    return RARCH_BIND_LIST_END;
26646 }
26647 
input_config_parse_hat(const char * dir)26648 static uint16_t input_config_parse_hat(const char *dir)
26649 {
26650    if (     dir[0] == 'u'
26651          && dir[1] == 'p'
26652          && dir[2] == '\0'
26653       )
26654       return HAT_UP_MASK;
26655    else if (
26656             dir[0] == 'd'
26657          && dir[1] == 'o'
26658          && dir[2] == 'w'
26659          && dir[3] == 'n'
26660          && dir[4] == '\0'
26661          )
26662       return HAT_DOWN_MASK;
26663    else if (
26664             dir[0] == 'l'
26665          && dir[1] == 'e'
26666          && dir[2] == 'f'
26667          && dir[3] == 't'
26668          && dir[4] == '\0'
26669          )
26670       return HAT_LEFT_MASK;
26671    else if (
26672             dir[0] == 'r'
26673          && dir[1] == 'i'
26674          && dir[2] == 'g'
26675          && dir[3] == 'h'
26676          && dir[4] == 't'
26677          && dir[5] == '\0'
26678          )
26679       return HAT_RIGHT_MASK;
26680 
26681    return 0;
26682 }
26683 
input_config_parse_joy_button(char * s,config_file_t * conf,const char * prefix,const char * btn,struct retro_keybind * bind)26684 static void input_config_parse_joy_button(
26685       char *s,
26686       config_file_t *conf, const char *prefix,
26687       const char *btn, struct retro_keybind *bind)
26688 {
26689    char tmp[64];
26690    char key[64];
26691    char key_label[64];
26692    struct config_entry_list *tmp_a         = NULL;
26693 
26694    tmp[0] = key[0] = key_label[0] = '\0';
26695 
26696    fill_pathname_join_delim(key, s,
26697          "btn", '_', sizeof(key));
26698    fill_pathname_join_delim(key_label, s,
26699          "btn_label", '_', sizeof(key_label));
26700 
26701    if (config_get_array(conf, key, tmp, sizeof(tmp)))
26702    {
26703       btn = tmp;
26704       if (     btn[0] == 'n'
26705             && btn[1] == 'u'
26706             && btn[2] == 'l'
26707             && btn[3] == '\0'
26708          )
26709          bind->joykey = NO_BTN;
26710       else
26711       {
26712          if (*btn == 'h')
26713          {
26714             const char *str = btn + 1;
26715             /* Parse hat? */
26716             if (str && ISDIGIT((int)*str))
26717             {
26718                char        *dir = NULL;
26719                uint16_t     hat = strtoul(str, &dir, 0);
26720                uint16_t hat_dir = dir ? input_config_parse_hat(dir) : 0;
26721                if (hat_dir)
26722                   bind->joykey = HAT_MAP(hat, hat_dir);
26723             }
26724          }
26725          else
26726             bind->joykey = strtoull(tmp, NULL, 0);
26727       }
26728    }
26729 
26730    tmp_a = config_get_entry(conf, key_label);
26731 
26732    if (tmp_a && !string_is_empty(tmp_a->value))
26733    {
26734       if (!string_is_empty(bind->joykey_label))
26735          free(bind->joykey_label);
26736 
26737       bind->joykey_label = strdup(tmp_a->value);
26738    }
26739 }
26740 
input_config_parse_joy_axis(char * s,config_file_t * conf,const char * prefix,const char * axis,struct retro_keybind * bind)26741 static void input_config_parse_joy_axis(
26742       char *s,
26743       config_file_t *conf, const char *prefix,
26744       const char *axis, struct retro_keybind *bind)
26745 {
26746    char       tmp[64];
26747    char       key[64];
26748    char key_label[64];
26749    struct config_entry_list *tmp_a         = NULL;
26750 
26751    tmp[0] = key[0] = key_label[0] = '\0';
26752 
26753    fill_pathname_join_delim(key, s,
26754          "axis", '_', sizeof(key));
26755    fill_pathname_join_delim(key_label, s,
26756          "axis_label", '_', sizeof(key_label));
26757 
26758    if (config_get_array(conf, key, tmp, sizeof(tmp)))
26759    {
26760       if (     tmp[0] == 'n'
26761             && tmp[1] == 'u'
26762             && tmp[2] == 'l'
26763             && tmp[3] == '\0'
26764          )
26765          bind->joyaxis = AXIS_NONE;
26766       else if (strlen(tmp) >= 2 && (*tmp == '+' || *tmp == '-'))
26767       {
26768          int i_axis = (int)strtol(tmp + 1, NULL, 0);
26769          if (*tmp == '+')
26770             bind->joyaxis = AXIS_POS(i_axis);
26771          else
26772             bind->joyaxis = AXIS_NEG(i_axis);
26773       }
26774 
26775       /* Ensure that D-pad emulation doesn't screw this over. */
26776       bind->orig_joyaxis = bind->joyaxis;
26777    }
26778 
26779    tmp_a = config_get_entry(conf, key_label);
26780 
26781    if (tmp_a && (!string_is_empty(tmp_a->value)))
26782    {
26783       if (bind->joyaxis_label &&
26784             !string_is_empty(bind->joyaxis_label))
26785          free(bind->joyaxis_label);
26786       bind->joyaxis_label = strdup(tmp_a->value);
26787    }
26788 }
26789 
input_config_parse_mouse_button(char * s,config_file_t * conf,const char * prefix,const char * btn,struct retro_keybind * bind)26790 static void input_config_parse_mouse_button(
26791       char *s,
26792       config_file_t *conf, const char *prefix,
26793       const char *btn, struct retro_keybind *bind)
26794 {
26795    int val;
26796    char tmp[64];
26797    char key[64];
26798 
26799    tmp[0] = key[0] = '\0';
26800 
26801    fill_pathname_join_delim(key, s, "mbtn", '_', sizeof(key));
26802 
26803    if (config_get_array(conf, key, tmp, sizeof(tmp)))
26804    {
26805       bind->mbutton = NO_BTN;
26806 
26807       if (tmp[0]=='w')
26808       {
26809          switch (tmp[1])
26810          {
26811             case 'u':
26812                bind->mbutton = RETRO_DEVICE_ID_MOUSE_WHEELUP;
26813                break;
26814             case 'd':
26815                bind->mbutton = RETRO_DEVICE_ID_MOUSE_WHEELDOWN;
26816                break;
26817             case 'h':
26818                switch (tmp[2])
26819                {
26820                   case 'u':
26821                      bind->mbutton = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP;
26822                      break;
26823                   case 'd':
26824                      bind->mbutton = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN;
26825                      break;
26826                }
26827                break;
26828          }
26829       }
26830       else
26831       {
26832          val = atoi(tmp);
26833          switch (val)
26834          {
26835             case 1:
26836                bind->mbutton = RETRO_DEVICE_ID_MOUSE_LEFT;
26837                break;
26838             case 2:
26839                bind->mbutton = RETRO_DEVICE_ID_MOUSE_RIGHT;
26840                break;
26841             case 3:
26842                bind->mbutton = RETRO_DEVICE_ID_MOUSE_MIDDLE;
26843                break;
26844             case 4:
26845                bind->mbutton = RETRO_DEVICE_ID_MOUSE_BUTTON_4;
26846                break;
26847             case 5:
26848                bind->mbutton = RETRO_DEVICE_ID_MOUSE_BUTTON_5;
26849                break;
26850          }
26851       }
26852    }
26853 }
26854 
input_config_get_bind_string_joykey(bool input_descriptor_label_show,char * buf,const char * prefix,const struct retro_keybind * bind,size_t size)26855 static void input_config_get_bind_string_joykey(
26856       bool input_descriptor_label_show,
26857       char *buf, const char *prefix,
26858       const struct retro_keybind *bind, size_t size)
26859 {
26860    if (GET_HAT_DIR(bind->joykey))
26861    {
26862       if (bind->joykey_label &&
26863             !string_is_empty(bind->joykey_label)
26864             && input_descriptor_label_show)
26865          fill_pathname_join_delim_concat(buf, prefix,
26866                bind->joykey_label, ' ', " (hat)", size);
26867       else
26868       {
26869          const char *dir = "?";
26870 
26871          switch (GET_HAT_DIR(bind->joykey))
26872          {
26873             case HAT_UP_MASK:
26874                dir = "up";
26875                break;
26876             case HAT_DOWN_MASK:
26877                dir = "down";
26878                break;
26879             case HAT_LEFT_MASK:
26880                dir = "left";
26881                break;
26882             case HAT_RIGHT_MASK:
26883                dir = "right";
26884                break;
26885             default:
26886                break;
26887          }
26888          snprintf(buf, size, "%sHat #%u %s (%s)", prefix,
26889                (unsigned)GET_HAT(bind->joykey), dir,
26890                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
26891       }
26892    }
26893    else
26894    {
26895       if (bind->joykey_label &&
26896             !string_is_empty(bind->joykey_label)
26897             && input_descriptor_label_show)
26898          fill_pathname_join_delim_concat(buf, prefix,
26899                bind->joykey_label, ' ', " (btn)", size);
26900       else
26901          snprintf(buf, size, "%s%u (%s)", prefix, (unsigned)bind->joykey,
26902                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
26903    }
26904 }
26905 
input_config_get_bind_string_joyaxis(bool input_descriptor_label_show,char * buf,const char * prefix,const struct retro_keybind * bind,size_t size)26906 static void input_config_get_bind_string_joyaxis(
26907       bool input_descriptor_label_show,
26908       char *buf, const char *prefix,
26909       const struct retro_keybind *bind, size_t size)
26910 {
26911    if (bind->joyaxis_label &&
26912          !string_is_empty(bind->joyaxis_label)
26913          && input_descriptor_label_show)
26914       fill_pathname_join_delim_concat(buf, prefix,
26915             bind->joyaxis_label, ' ', " (axis)", size);
26916    else
26917    {
26918       unsigned axis        = 0;
26919       char dir             = '\0';
26920       if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE)
26921       {
26922          dir = '-';
26923          axis = AXIS_NEG_GET(bind->joyaxis);
26924       }
26925       else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE)
26926       {
26927          dir = '+';
26928          axis = AXIS_POS_GET(bind->joyaxis);
26929       }
26930       snprintf(buf, size, "%s%c%u (%s)", prefix, dir, axis,
26931             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
26932    }
26933 }
26934 
input_config_get_bind_string(char * buf,const struct retro_keybind * bind,const struct retro_keybind * auto_bind,size_t size)26935 void input_config_get_bind_string(char *buf,
26936       const struct retro_keybind *bind,
26937       const struct retro_keybind *auto_bind,
26938       size_t size)
26939 {
26940    int delim                         = 0;
26941    struct rarch_state *p_rarch       = &rarch_st;
26942    settings_t *settings              = p_rarch->configuration_settings;
26943    bool  input_descriptor_label_show =
26944       settings->bools.input_descriptor_label_show;
26945 
26946    *buf = '\0';
26947 
26948    if      (bind      && bind->joykey  != NO_BTN)
26949       input_config_get_bind_string_joykey(
26950             input_descriptor_label_show, buf, "", bind, size);
26951    else if (bind      && bind->joyaxis != AXIS_NONE)
26952       input_config_get_bind_string_joyaxis(
26953             input_descriptor_label_show,
26954             buf, "", bind, size);
26955    else if (auto_bind && auto_bind->joykey != NO_BTN)
26956       input_config_get_bind_string_joykey(
26957             input_descriptor_label_show, buf, "Auto: ", auto_bind, size);
26958    else if (auto_bind && auto_bind->joyaxis != AXIS_NONE)
26959       input_config_get_bind_string_joyaxis(
26960             input_descriptor_label_show,
26961             buf, "Auto: ", auto_bind, size);
26962 
26963    if (*buf)
26964       delim = 1;
26965 
26966 #ifndef RARCH_CONSOLE
26967    {
26968       char key[64];
26969       key[0] = '\0';
26970 
26971       input_keymaps_translate_rk_to_str(bind->key, key, sizeof(key));
26972       if (     key[0] == 'n'
26973             && key[1] == 'u'
26974             && key[2] == 'l'
26975             && key[3] == '\0'
26976          )
26977          *key = '\0';
26978       /*empty?*/
26979       if (*key != '\0')
26980       {
26981          char keybuf[64];
26982 
26983          keybuf[0] = '\0';
26984 
26985          if (delim)
26986             strlcat(buf, ", ", size);
26987          snprintf(keybuf, sizeof(keybuf),
26988                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_KEY), key);
26989          strlcat(buf, keybuf, size);
26990          delim = 1;
26991       }
26992    }
26993 #endif
26994 
26995    if (bind->mbutton != NO_BTN)
26996    {
26997       int tag = 0;
26998       switch (bind->mbutton)
26999       {
27000          case RETRO_DEVICE_ID_MOUSE_LEFT:
27001             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_LEFT;
27002             break;
27003          case RETRO_DEVICE_ID_MOUSE_RIGHT:
27004             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_RIGHT;
27005             break;
27006          case RETRO_DEVICE_ID_MOUSE_MIDDLE:
27007             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_MIDDLE;
27008             break;
27009          case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
27010             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON4;
27011             break;
27012          case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
27013             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_BUTTON5;
27014             break;
27015          case RETRO_DEVICE_ID_MOUSE_WHEELUP:
27016             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_UP;
27017             break;
27018          case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
27019             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN;
27020             break;
27021          case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
27022             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP;
27023             break;
27024          case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
27025             tag = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN;
27026             break;
27027       }
27028 
27029       if (tag != 0)
27030       {
27031          if (delim)
27032             strlcat(buf, ", ", size);
27033          strlcat(buf, msg_hash_to_str((enum msg_hash_enums)tag), size);
27034       }
27035    }
27036 
27037    /*completely empty?*/
27038    if (*buf == '\0')
27039       strlcat(buf, "---", size);
27040 }
27041 
27042 /* input_device_info wrappers START */
27043 
input_config_get_device_count(void)27044 unsigned input_config_get_device_count(void)
27045 {
27046    unsigned num_devices;
27047    struct rarch_state *p_rarch = &rarch_st;
27048 
27049    for (num_devices = 0; num_devices < MAX_INPUT_DEVICES; ++num_devices)
27050    {
27051       if (string_is_empty(p_rarch->input_device_info[num_devices].name))
27052          break;
27053    }
27054    return num_devices;
27055 }
27056 
27057 /* Adds an index to devices with the same name,
27058  * so they can be uniquely identified in the
27059  * frontend */
input_config_reindex_device_names(struct rarch_state * p_rarch)27060 static void input_config_reindex_device_names(struct rarch_state *p_rarch)
27061 {
27062    unsigned i;
27063    unsigned j;
27064    unsigned name_index;
27065 
27066    /* Reset device name indices */
27067    for (i = 0; i < MAX_INPUT_DEVICES; i++)
27068       p_rarch->input_device_info[i].name_index       = 0;
27069 
27070    /* Scan device names */
27071    for (i = 0; i < MAX_INPUT_DEVICES; i++)
27072    {
27073       const char *device_name = input_config_get_device_name(i);
27074 
27075       /* If current device name is empty, or a non-zero
27076        * name index has already been assigned, continue
27077        * to the next device */
27078       if (
27079                string_is_empty(device_name)
27080             || p_rarch->input_device_info[i].name_index != 0)
27081          continue;
27082 
27083       /* > Uniquely named devices have a name index
27084        *   of 0
27085        * > Devices with the same name have a name
27086        *   index starting from 1 */
27087       name_index = 1;
27088 
27089       /* Loop over all devices following the current
27090        * selection */
27091       for (j = i + 1; j < MAX_INPUT_DEVICES; j++)
27092       {
27093          const char *next_device_name = input_config_get_device_name(j);
27094 
27095          if (string_is_empty(next_device_name))
27096             continue;
27097 
27098          /* Check if names match */
27099          if (string_is_equal(device_name, next_device_name))
27100          {
27101             /* If this is the first match, set a starting
27102              * index for the current device selection */
27103             if (p_rarch->input_device_info[i].name_index == 0)
27104                p_rarch->input_device_info[i].name_index       = name_index++;
27105 
27106             /* Set name index for the next device
27107              * (will keep incrementing as more matches
27108              *  are found) */
27109             p_rarch->input_device_info[j].name_index          = name_index++;
27110          }
27111       }
27112    }
27113 }
27114 
27115 /* > Get input_device_info */
27116 
input_config_get_device_name(unsigned port)27117 const char *input_config_get_device_name(unsigned port)
27118 {
27119    struct rarch_state *p_rarch = &rarch_st;
27120    if (string_is_empty(p_rarch->input_device_info[port].name))
27121       return NULL;
27122    return p_rarch->input_device_info[port].name;
27123 }
27124 
input_config_get_device_display_name(unsigned port)27125 const char *input_config_get_device_display_name(unsigned port)
27126 {
27127    struct rarch_state *p_rarch = &rarch_st;
27128    if (string_is_empty(p_rarch->input_device_info[port].display_name))
27129       return NULL;
27130    return p_rarch->input_device_info[port].display_name;
27131 }
27132 
input_config_get_device_config_path(unsigned port)27133 const char *input_config_get_device_config_path(unsigned port)
27134 {
27135    struct rarch_state *p_rarch = &rarch_st;
27136    if (string_is_empty(p_rarch->input_device_info[port].config_path))
27137       return NULL;
27138    return p_rarch->input_device_info[port].config_path;
27139 }
27140 
input_config_get_device_config_name(unsigned port)27141 const char *input_config_get_device_config_name(unsigned port)
27142 {
27143    struct rarch_state *p_rarch = &rarch_st;
27144    if (string_is_empty(p_rarch->input_device_info[port].config_name))
27145       return NULL;
27146    return p_rarch->input_device_info[port].config_name;
27147 }
27148 
input_config_get_device_joypad_driver(unsigned port)27149 const char *input_config_get_device_joypad_driver(unsigned port)
27150 {
27151    struct rarch_state *p_rarch = &rarch_st;
27152    if (string_is_empty(p_rarch->input_device_info[port].joypad_driver))
27153       return NULL;
27154    return p_rarch->input_device_info[port].joypad_driver;
27155 }
27156 
input_config_get_device_vid(unsigned port)27157 uint16_t input_config_get_device_vid(unsigned port)
27158 {
27159    struct rarch_state *p_rarch = &rarch_st;
27160    return p_rarch->input_device_info[port].vid;
27161 }
27162 
input_config_get_device_pid(unsigned port)27163 uint16_t input_config_get_device_pid(unsigned port)
27164 {
27165    struct rarch_state *p_rarch = &rarch_st;
27166    return p_rarch->input_device_info[port].pid;
27167 }
27168 
input_config_get_device_autoconfigured(unsigned port)27169 bool input_config_get_device_autoconfigured(unsigned port)
27170 {
27171    struct rarch_state *p_rarch = &rarch_st;
27172    return p_rarch->input_device_info[port].autoconfigured;
27173 }
27174 
input_config_get_device_name_index(unsigned port)27175 unsigned input_config_get_device_name_index(unsigned port)
27176 {
27177    struct rarch_state *p_rarch = &rarch_st;
27178    return p_rarch->input_device_info[port].name_index;
27179 }
27180 
27181 /* TODO/FIXME: This is required by linuxraw_joypad.c
27182  * and parport_joypad.c. These input drivers should
27183  * be refactored such that this dubious low-level
27184  * access is not required */
input_config_get_device_name_ptr(unsigned port)27185 char *input_config_get_device_name_ptr(unsigned port)
27186 {
27187    struct rarch_state *p_rarch = &rarch_st;
27188    return p_rarch->input_device_info[port].name;
27189 }
27190 
input_config_get_device_name_size(unsigned port)27191 size_t input_config_get_device_name_size(unsigned port)
27192 {
27193    struct rarch_state *p_rarch = &rarch_st;
27194    return sizeof(p_rarch->input_device_info[port].name);
27195 }
27196 
27197 /* > Set input_device_info */
27198 
input_config_set_device_name(unsigned port,const char * name)27199 void input_config_set_device_name(unsigned port, const char *name)
27200 {
27201    struct rarch_state *p_rarch = &rarch_st;
27202 
27203    if (string_is_empty(name))
27204       return;
27205 
27206    strlcpy(p_rarch->input_device_info[port].name, name,
27207          sizeof(p_rarch->input_device_info[port].name));
27208 
27209    input_config_reindex_device_names(p_rarch);
27210 }
27211 
input_config_set_device_display_name(unsigned port,const char * name)27212 void input_config_set_device_display_name(unsigned port, const char *name)
27213 {
27214    struct rarch_state *p_rarch = &rarch_st;
27215    if (!string_is_empty(name))
27216       strlcpy(p_rarch->input_device_info[port].display_name, name,
27217             sizeof(p_rarch->input_device_info[port].display_name));
27218 }
27219 
input_config_set_device_config_path(unsigned port,const char * path)27220 void input_config_set_device_config_path(unsigned port, const char *path)
27221 {
27222    if (!string_is_empty(path))
27223    {
27224       char parent_dir_name[128];
27225       struct rarch_state *p_rarch = &rarch_st;
27226 
27227       parent_dir_name[0] = '\0';
27228 
27229       if (fill_pathname_parent_dir_name(parent_dir_name,
27230                path, sizeof(parent_dir_name)))
27231          fill_pathname_join(p_rarch->input_device_info[port].config_path,
27232                parent_dir_name, path_basename(path),
27233                sizeof(p_rarch->input_device_info[port].config_path));
27234    }
27235 }
27236 
input_config_set_device_config_name(unsigned port,const char * name)27237 void input_config_set_device_config_name(unsigned port, const char *name)
27238 {
27239    struct rarch_state *p_rarch = &rarch_st;
27240    if (!string_is_empty(name))
27241       strlcpy(p_rarch->input_device_info[port].config_name, name,
27242             sizeof(p_rarch->input_device_info[port].config_name));
27243 }
27244 
input_config_set_device_joypad_driver(unsigned port,const char * driver)27245 void input_config_set_device_joypad_driver(unsigned port, const char *driver)
27246 {
27247    struct rarch_state *p_rarch = &rarch_st;
27248    if (!string_is_empty(driver))
27249       strlcpy(p_rarch->input_device_info[port].joypad_driver, driver,
27250             sizeof(p_rarch->input_device_info[port].joypad_driver));
27251 }
27252 
input_config_set_device_vid(unsigned port,uint16_t vid)27253 void input_config_set_device_vid(unsigned port, uint16_t vid)
27254 {
27255    struct rarch_state *p_rarch = &rarch_st;
27256    p_rarch->input_device_info[port].vid = vid;
27257 }
27258 
input_config_set_device_pid(unsigned port,uint16_t pid)27259 void input_config_set_device_pid(unsigned port, uint16_t pid)
27260 {
27261    struct rarch_state *p_rarch = &rarch_st;
27262    p_rarch->input_device_info[port].pid = pid;
27263 }
27264 
input_config_set_device_autoconfigured(unsigned port,bool autoconfigured)27265 void input_config_set_device_autoconfigured(unsigned port, bool autoconfigured)
27266 {
27267    struct rarch_state *p_rarch = &rarch_st;
27268    p_rarch->input_device_info[port].autoconfigured = autoconfigured;
27269 }
27270 
input_config_set_device_name_index(unsigned port,unsigned name_index)27271 void input_config_set_device_name_index(unsigned port, unsigned name_index)
27272 {
27273    struct rarch_state *p_rarch = &rarch_st;
27274    p_rarch->input_device_info[port].name_index = name_index;
27275 }
27276 
27277 /* > Clear input_device_info */
27278 
input_config_clear_device_name(unsigned port)27279 void input_config_clear_device_name(unsigned port)
27280 {
27281    struct rarch_state *p_rarch = &rarch_st;
27282    p_rarch->input_device_info[port].name[0] = '\0';
27283    input_config_reindex_device_names(p_rarch);
27284 }
27285 
input_config_clear_device_display_name(unsigned port)27286 void input_config_clear_device_display_name(unsigned port)
27287 {
27288    struct rarch_state *p_rarch = &rarch_st;
27289    p_rarch->input_device_info[port].display_name[0] = '\0';
27290 }
27291 
input_config_clear_device_config_path(unsigned port)27292 void input_config_clear_device_config_path(unsigned port)
27293 {
27294    struct rarch_state *p_rarch = &rarch_st;
27295    p_rarch->input_device_info[port].config_path[0] = '\0';
27296 }
27297 
input_config_clear_device_config_name(unsigned port)27298 void input_config_clear_device_config_name(unsigned port)
27299 {
27300    struct rarch_state *p_rarch = &rarch_st;
27301    p_rarch->input_device_info[port].config_name[0] = '\0';
27302 }
27303 
input_config_clear_device_joypad_driver(unsigned port)27304 void input_config_clear_device_joypad_driver(unsigned port)
27305 {
27306    struct rarch_state *p_rarch = &rarch_st;
27307    p_rarch->input_device_info[port].joypad_driver[0] = '\0';
27308 }
27309 
27310 /* input_device_info wrappers END */
27311 
input_config_get_device_ptr(unsigned port)27312 unsigned *input_config_get_device_ptr(unsigned port)
27313 {
27314    struct rarch_state      *p_rarch = &rarch_st;
27315    settings_t             *settings = p_rarch->configuration_settings;
27316    return &settings->uints.input_libretro_device[port];
27317 }
27318 
input_config_get_device(unsigned port)27319 unsigned input_config_get_device(unsigned port)
27320 {
27321    struct rarch_state      *p_rarch = &rarch_st;
27322    settings_t             *settings = p_rarch->configuration_settings;
27323    return settings->uints.input_libretro_device[port];
27324 }
27325 
input_config_set_device(unsigned port,unsigned id)27326 void input_config_set_device(unsigned port, unsigned id)
27327 {
27328    struct rarch_state *p_rarch = &rarch_st;
27329    settings_t        *settings = p_rarch->configuration_settings;
27330 
27331    if (settings)
27332       configuration_set_uint(settings,
27333       settings->uints.input_libretro_device[port], id);
27334 }
27335 
input_config_get_bind_auto(unsigned port,unsigned id)27336 const struct retro_keybind *input_config_get_bind_auto(
27337       unsigned port, unsigned id)
27338 {
27339    struct rarch_state *p_rarch = &rarch_st;
27340    settings_t        *settings = p_rarch->configuration_settings;
27341    unsigned        joy_idx     = settings->uints.input_joypad_index[port];
27342 
27343    if (joy_idx < MAX_USERS)
27344       return &input_autoconf_binds[joy_idx][id];
27345    return NULL;
27346 }
27347 
input_config_reset_autoconfig_binds(unsigned port)27348 void input_config_reset_autoconfig_binds(unsigned port)
27349 {
27350    unsigned i;
27351 
27352    if (port >= MAX_USERS)
27353       return;
27354 
27355    for (i = 0; i < RARCH_BIND_LIST_END; i++)
27356    {
27357       input_autoconf_binds[port][i].joykey  = NO_BTN;
27358       input_autoconf_binds[port][i].joyaxis = AXIS_NONE;
27359 
27360       if (input_autoconf_binds[port][i].joykey_label)
27361       {
27362          free(input_autoconf_binds[port][i].joykey_label);
27363          input_autoconf_binds[port][i].joykey_label = NULL;
27364       }
27365 
27366       if (input_autoconf_binds[port][i].joyaxis_label)
27367       {
27368          free(input_autoconf_binds[port][i].joyaxis_label);
27369          input_autoconf_binds[port][i].joyaxis_label = NULL;
27370       }
27371    }
27372 }
27373 
input_config_reset(void)27374 void input_config_reset(void)
27375 {
27376    unsigned i;
27377    struct rarch_state *p_rarch = &rarch_st;
27378 
27379    retro_assert(sizeof(input_config_binds[0]) >= sizeof(retro_keybinds_1));
27380    retro_assert(sizeof(input_config_binds[1]) >= sizeof(retro_keybinds_rest));
27381 
27382    memcpy(input_config_binds[0], retro_keybinds_1, sizeof(retro_keybinds_1));
27383 
27384    for (i = 1; i < MAX_USERS; i++)
27385       memcpy(input_config_binds[i], retro_keybinds_rest,
27386             sizeof(retro_keybinds_rest));
27387 
27388    for (i = 0; i < MAX_USERS; i++)
27389    {
27390       /* Note: Don't use input_config_clear_device_name()
27391        * here, since this will re-index devices each time
27392        * (not required - we are setting all 'name indices'
27393        * to zero manually) */
27394       p_rarch->input_device_info[i].name[0]          = '\0';
27395       p_rarch->input_device_info[i].display_name[0]  = '\0';
27396       p_rarch->input_device_info[i].config_path[0]   = '\0';
27397       p_rarch->input_device_info[i].config_name[0]   = '\0';
27398       p_rarch->input_device_info[i].joypad_driver[0] = '\0';
27399       p_rarch->input_device_info[i].vid              = 0;
27400       p_rarch->input_device_info[i].pid              = 0;
27401       p_rarch->input_device_info[i].autoconfigured   = false;
27402       p_rarch->input_device_info[i].name_index       = 0;
27403 
27404       input_config_reset_autoconfig_binds(i);
27405 
27406       p_rarch->libretro_input_binds[i] = input_config_binds[i];
27407    }
27408 }
27409 
config_read_keybinds_conf(void * data)27410 void config_read_keybinds_conf(void *data)
27411 {
27412    unsigned i;
27413    config_file_t         *conf = (config_file_t*)data;
27414    struct rarch_state *p_rarch = &rarch_st;
27415 
27416    if (!conf)
27417       return;
27418 
27419    for (i = 0; i < MAX_USERS; i++)
27420    {
27421       unsigned j;
27422 
27423       for (j = 0; input_config_bind_map_get_valid(j); j++)
27424       {
27425          char str[256];
27426          const struct input_bind_map *keybind =
27427             (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(j);
27428          struct retro_keybind *bind = &input_config_binds[i][j];
27429          bool meta                  = false;
27430          const char *prefix         = NULL;
27431          const char *btn            = NULL;
27432          struct config_entry_list
27433             *entry                  = NULL;
27434 
27435 
27436          if (!bind || !bind->valid || !keybind)
27437             continue;
27438          if (!keybind->valid)
27439             continue;
27440          meta                       = keybind->meta;
27441          btn                        = keybind->base;
27442          prefix                     = input_config_get_prefix(i, meta);
27443          if (!btn || !prefix)
27444             continue;
27445 
27446          str[0]                     = '\0';
27447 
27448          fill_pathname_join_delim(str, prefix, btn,  '_', sizeof(str));
27449 
27450          /* Clear old mapping bit */
27451          BIT512_CLEAR_PTR(&p_rarch->keyboard_mapping_bits, bind->key);
27452 
27453          entry                      = config_get_entry(conf, str);
27454          if (entry && !string_is_empty(entry->value))
27455             bind->key               = input_config_translate_str_to_rk(
27456                   entry->value);
27457          /* Store mapping bit */
27458          BIT512_SET_PTR(&p_rarch->keyboard_mapping_bits, bind->key);
27459 
27460          input_config_parse_joy_button  (str, conf, prefix, btn, bind);
27461          input_config_parse_joy_axis    (str, conf, prefix, btn, bind);
27462          input_config_parse_mouse_button(str, conf, prefix, btn, bind);
27463       }
27464    }
27465 }
27466 
input_config_set_autoconfig_binds(unsigned port,void * data)27467 void input_config_set_autoconfig_binds(unsigned port, void *data)
27468 {
27469    unsigned i;
27470    config_file_t *config       = (config_file_t*)data;
27471    struct retro_keybind *binds = NULL;
27472 
27473    if ((port >= MAX_USERS) || !config)
27474       return;
27475 
27476    binds = input_autoconf_binds[port];
27477 
27478    for (i = 0; i < RARCH_BIND_LIST_END; i++)
27479    {
27480       const struct input_bind_map *keybind =
27481          (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
27482       if (keybind)
27483       {
27484          char str[256];
27485          const char *base = keybind->base;
27486          str[0]                     = '\0';
27487 
27488          fill_pathname_join_delim(str, "input", base,  '_', sizeof(str));
27489 
27490          input_config_parse_joy_button(str, config, "input", base, &binds[i]);
27491          input_config_parse_joy_axis  (str, config, "input", base, &binds[i]);
27492       }
27493    }
27494 }
27495 
27496 /**
27497  * input_config_save_keybinds_user:
27498  * @conf               : pointer to config file object
27499  * @user               : user number
27500  *
27501  * Save the current keybinds of a user (@user) to the config file (@conf).
27502  */
input_config_save_keybinds_user(void * data,unsigned user)27503 void input_config_save_keybinds_user(void *data, unsigned user)
27504 {
27505    unsigned i = 0;
27506    config_file_t *conf = (config_file_t*)data;
27507 
27508    for (i = 0; input_config_bind_map_get_valid(i); i++)
27509    {
27510       char key[64];
27511       char btn[64];
27512       const struct input_bind_map *keybind =
27513          (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
27514       bool meta                            = keybind ? keybind->meta : false;
27515       const char *prefix                   = input_config_get_prefix(user, meta);
27516       const struct retro_keybind *bind     = &input_config_binds[user][i];
27517       const char                 *base     = NULL;
27518 
27519       if (!prefix || !bind->valid || !keybind)
27520          continue;
27521 
27522       base                                 = keybind->base;
27523       key[0] = btn[0]                      = '\0';
27524 
27525       fill_pathname_join_delim(key, prefix, base, '_', sizeof(key));
27526 
27527       input_keymaps_translate_rk_to_str(bind->key, btn, sizeof(btn));
27528       config_set_string(conf, key, btn);
27529 
27530       input_config_save_keybind(conf, prefix, base, bind, true);
27531    }
27532 }
27533 
save_keybind_hat(config_file_t * conf,const char * key,const struct retro_keybind * bind)27534 static void save_keybind_hat(config_file_t *conf, const char *key,
27535       const struct retro_keybind *bind)
27536 {
27537    char config[16];
27538    unsigned hat     = (unsigned)GET_HAT(bind->joykey);
27539    const char *dir  = NULL;
27540 
27541    config[0]        = '\0';
27542 
27543    switch (GET_HAT_DIR(bind->joykey))
27544    {
27545       case HAT_UP_MASK:
27546          dir = "up";
27547          break;
27548 
27549       case HAT_DOWN_MASK:
27550          dir = "down";
27551          break;
27552 
27553       case HAT_LEFT_MASK:
27554          dir = "left";
27555          break;
27556 
27557       case HAT_RIGHT_MASK:
27558          dir = "right";
27559          break;
27560 
27561       default:
27562          break;
27563    }
27564 
27565    snprintf(config, sizeof(config), "h%u%s", hat, dir);
27566    config_set_string(conf, key, config);
27567 }
27568 
save_keybind_joykey(config_file_t * conf,const char * prefix,const char * base,const struct retro_keybind * bind,bool save_empty)27569 static void save_keybind_joykey(config_file_t *conf,
27570       const char *prefix,
27571       const char *base,
27572       const struct retro_keybind *bind, bool save_empty)
27573 {
27574    char key[64];
27575 
27576    key[0] = '\0';
27577 
27578    fill_pathname_join_delim_concat(key, prefix,
27579          base, '_', "_btn", sizeof(key));
27580 
27581    if (bind->joykey == NO_BTN)
27582    {
27583        if (save_empty)
27584          config_set_string(conf, key, "nul");
27585    }
27586    else if (GET_HAT_DIR(bind->joykey))
27587       save_keybind_hat(conf, key, bind);
27588    else
27589       config_set_uint64(conf, key, bind->joykey);
27590 }
27591 
save_keybind_axis(config_file_t * conf,const char * prefix,const char * base,const struct retro_keybind * bind,bool save_empty)27592 static void save_keybind_axis(config_file_t *conf,
27593       const char *prefix,
27594       const char *base,
27595       const struct retro_keybind *bind, bool save_empty)
27596 {
27597    char key[64];
27598    unsigned axis   = 0;
27599    char dir        = '\0';
27600 
27601    key[0] = '\0';
27602 
27603    fill_pathname_join_delim_concat(key,
27604          prefix, base, '_',
27605          "_axis",
27606          sizeof(key));
27607 
27608    if (bind->joyaxis == AXIS_NONE)
27609    {
27610       if (save_empty)
27611          config_set_string(conf, key, "nul");
27612    }
27613    else if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE)
27614    {
27615       dir = '-';
27616       axis = AXIS_NEG_GET(bind->joyaxis);
27617    }
27618    else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE)
27619    {
27620       dir = '+';
27621       axis = AXIS_POS_GET(bind->joyaxis);
27622    }
27623 
27624    if (dir)
27625    {
27626       char config[16];
27627 
27628       config[0] = '\0';
27629 
27630       snprintf(config, sizeof(config), "%c%u", dir, axis);
27631       config_set_string(conf, key, config);
27632    }
27633 }
27634 
save_keybind_mbutton(config_file_t * conf,const char * prefix,const char * base,const struct retro_keybind * bind,bool save_empty)27635 static void save_keybind_mbutton(config_file_t *conf,
27636       const char *prefix,
27637       const char *base,
27638       const struct retro_keybind *bind, bool save_empty)
27639 {
27640    char key[64];
27641 
27642    key[0] = '\0';
27643 
27644    fill_pathname_join_delim_concat(key, prefix,
27645       base, '_', "_mbtn", sizeof(key));
27646 
27647    switch (bind->mbutton)
27648    {
27649       case RETRO_DEVICE_ID_MOUSE_LEFT:
27650          config_set_uint64(conf, key, 1);
27651          break;
27652       case RETRO_DEVICE_ID_MOUSE_RIGHT:
27653          config_set_uint64(conf, key, 2);
27654          break;
27655       case RETRO_DEVICE_ID_MOUSE_MIDDLE:
27656          config_set_uint64(conf, key, 3);
27657          break;
27658       case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
27659          config_set_uint64(conf, key, 4);
27660          break;
27661       case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
27662          config_set_uint64(conf, key, 5);
27663          break;
27664       case RETRO_DEVICE_ID_MOUSE_WHEELUP:
27665          config_set_string(conf, key, "wu");
27666          break;
27667       case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
27668          config_set_string(conf, key, "wd");
27669          break;
27670       case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
27671          config_set_string(conf, key, "whu");
27672          break;
27673       case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
27674          config_set_string(conf, key, "whd");
27675          break;
27676       default:
27677          if (save_empty)
27678             config_set_string(conf, key, "nul");
27679          break;
27680    }
27681 }
27682 
27683 /**
27684  * input_config_save_keybind:
27685  * @conf               : pointer to config file object
27686  * @prefix             : prefix name of keybind
27687  * @base               : base name   of keybind
27688  * @bind               : pointer to key binding object
27689  * @kb                 : save keyboard binds
27690  *
27691  * Save a key binding to the config file.
27692  */
input_config_save_keybind(void * data,const char * prefix,const char * base,const struct retro_keybind * bind,bool save_empty)27693 void input_config_save_keybind(void *data, const char *prefix,
27694       const char *base, const struct retro_keybind *bind,
27695       bool save_empty)
27696 {
27697    config_file_t *conf = (config_file_t*)data;
27698 
27699    save_keybind_joykey (conf, prefix, base, bind, save_empty);
27700    save_keybind_axis   (conf, prefix, base, bind, save_empty);
27701    save_keybind_mbutton(conf, prefix, base, bind, save_empty);
27702 }
27703 
27704 /* MIDI */
27705 
midi_driver_find_driver(const char * ident)27706 static midi_driver_t *midi_driver_find_driver(const char *ident)
27707 {
27708    unsigned i;
27709 
27710    for (i = 0; i < ARRAY_SIZE(midi_drivers); ++i)
27711    {
27712       if (string_is_equal(midi_drivers[i]->ident, ident))
27713          return midi_drivers[i];
27714    }
27715 
27716    RARCH_ERR("[MIDI]: Unknown driver \"%s\", falling back to \"null\" driver.\n", ident);
27717 
27718    return &midi_null;
27719 }
27720 
midi_driver_find_handle(int index)27721 static const void *midi_driver_find_handle(int index)
27722 {
27723    if (index < 0 || index >= ARRAY_SIZE(midi_drivers))
27724       return NULL;
27725 
27726    return midi_drivers[index];
27727 }
27728 
midi_driver_get_avail_inputs(void)27729 struct string_list *midi_driver_get_avail_inputs(void)
27730 {
27731    struct rarch_state *p_rarch = &rarch_st;
27732    return p_rarch->midi_drv_inputs;
27733 }
27734 
midi_driver_get_avail_outputs(void)27735 struct string_list *midi_driver_get_avail_outputs(void)
27736 {
27737    struct rarch_state *p_rarch = &rarch_st;
27738    return p_rarch->midi_drv_outputs;
27739 }
27740 
midi_driver_set_all_sounds_off(struct rarch_state * p_rarch)27741 static bool midi_driver_set_all_sounds_off(struct rarch_state *p_rarch)
27742 {
27743    midi_event_t event;
27744    uint8_t i;
27745    uint8_t data[3]     = { 0xB0, 120, 0 };
27746    bool result         = true;
27747 
27748    if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled)
27749       return false;
27750 
27751    event.data       = data;
27752    event.data_size  = sizeof(data);
27753    event.delta_time = 0;
27754 
27755    for (i = 0; i < 16; ++i)
27756    {
27757       data[0] = 0xB0 | i;
27758 
27759       if (!midi_drv->write(p_rarch->midi_drv_data, &event))
27760          result = false;
27761    }
27762 
27763    if (!midi_drv->flush(p_rarch->midi_drv_data))
27764       result = false;
27765 
27766    if (!result)
27767       RARCH_ERR("[MIDI]: All sounds off failed.\n");
27768 
27769    return result;
27770 }
27771 
midi_driver_set_volume(unsigned volume)27772 bool midi_driver_set_volume(unsigned volume)
27773 {
27774    midi_event_t event;
27775    struct rarch_state *p_rarch = &rarch_st;
27776    uint8_t         data[8]     = {
27777       0xF0, 0x7F, 0x7F, 0x04, 0x01, 0, 0, 0xF7};
27778 
27779    if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled)
27780       return false;
27781 
27782    volume           = (unsigned)(163.83 * volume + 0.5);
27783    if (volume > 16383)
27784       volume        = 16383;
27785 
27786    data[5]          = (uint8_t)(volume & 0x7F);
27787    data[6]          = (uint8_t)(volume >> 7);
27788 
27789    event.data       = data;
27790    event.data_size  = sizeof(data);
27791    event.delta_time = 0;
27792 
27793    if (!midi_drv->write(p_rarch->midi_drv_data, &event))
27794    {
27795       RARCH_ERR("[MIDI]: Volume change failed.\n");
27796       return false;
27797    }
27798 
27799    return true;
27800 }
27801 
midi_driver_init_io_buffers(struct rarch_state * p_rarch)27802 static bool midi_driver_init_io_buffers(struct rarch_state *p_rarch)
27803 {
27804    uint8_t *midi_drv_input_buffer  = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE);
27805    uint8_t *midi_drv_output_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE);
27806 
27807    if (!midi_drv_input_buffer || !midi_drv_output_buffer)
27808    {
27809       if (midi_drv_input_buffer)
27810          free(midi_drv_input_buffer);
27811       if (midi_drv_output_buffer)
27812          free(midi_drv_output_buffer);
27813       return false;
27814    }
27815 
27816    p_rarch->midi_drv_input_buffer           = midi_drv_input_buffer;
27817    p_rarch->midi_drv_output_buffer          = midi_drv_output_buffer;
27818 
27819    p_rarch->midi_drv_input_event.data       = midi_drv_input_buffer;
27820    p_rarch->midi_drv_input_event.data_size  = 0;
27821 
27822    p_rarch->midi_drv_output_event.data      = midi_drv_output_buffer;
27823    p_rarch->midi_drv_output_event.data_size = 0;
27824 
27825    return true;
27826 }
27827 
midi_driver_free(struct rarch_state * p_rarch)27828 static void midi_driver_free(struct rarch_state *p_rarch)
27829 {
27830    if (p_rarch->midi_drv_data)
27831    {
27832       midi_drv->free(p_rarch->midi_drv_data);
27833       p_rarch->midi_drv_data = NULL;
27834    }
27835 
27836    if (p_rarch->midi_drv_inputs)
27837    {
27838       string_list_free(p_rarch->midi_drv_inputs);
27839       p_rarch->midi_drv_inputs = NULL;
27840    }
27841 
27842    if (p_rarch->midi_drv_outputs)
27843    {
27844       string_list_free(p_rarch->midi_drv_outputs);
27845       p_rarch->midi_drv_outputs = NULL;
27846    }
27847 
27848    if (p_rarch->midi_drv_input_buffer)
27849    {
27850       free(p_rarch->midi_drv_input_buffer);
27851       p_rarch->midi_drv_input_buffer = NULL;
27852    }
27853 
27854    if (p_rarch->midi_drv_output_buffer)
27855    {
27856       free(p_rarch->midi_drv_output_buffer);
27857       p_rarch->midi_drv_output_buffer = NULL;
27858    }
27859 
27860    p_rarch->midi_drv_input_enabled  = false;
27861    p_rarch->midi_drv_output_enabled = false;
27862 }
27863 
midi_driver_init(struct rarch_state * p_rarch,settings_t * settings)27864 static bool midi_driver_init(struct rarch_state *p_rarch,
27865       settings_t *settings)
27866 {
27867    union string_list_elem_attr attr  = {0};
27868    bool ret                          = true;
27869 
27870    p_rarch->midi_drv_inputs          = string_list_new();
27871    p_rarch->midi_drv_outputs         = string_list_new();
27872 
27873    if (!p_rarch->midi_drv_inputs || !p_rarch->midi_drv_outputs)
27874       ret = false;
27875    else if (!string_list_append(p_rarch->midi_drv_inputs, "Off", attr) ||
27876             !string_list_append(p_rarch->midi_drv_outputs, "Off", attr))
27877       ret = false;
27878    else
27879    {
27880       char * input  = NULL;
27881       char * output = NULL;
27882 
27883       midi_drv      = midi_driver_find_driver(
27884             settings->arrays.midi_driver);
27885 
27886       if (strcmp(midi_drv->ident, settings->arrays.midi_driver))
27887       {
27888          configuration_set_string(settings,
27889                settings->arrays.midi_driver, midi_drv->ident);
27890       }
27891 
27892       if (!midi_drv->get_avail_inputs(p_rarch->midi_drv_inputs))
27893          ret = false;
27894       else if (!midi_drv->get_avail_outputs(p_rarch->midi_drv_outputs))
27895          ret = false;
27896       else
27897       {
27898          if (string_is_not_equal(settings->arrays.midi_input, "Off"))
27899          {
27900             if (string_list_find_elem(p_rarch->midi_drv_inputs, settings->arrays.midi_input))
27901                input = settings->arrays.midi_input;
27902             else
27903             {
27904                RARCH_WARN("[MIDI]: Input device \"%s\" unavailable.\n",
27905                      settings->arrays.midi_input);
27906                configuration_set_string(settings,
27907                      settings->arrays.midi_input, "Off");
27908             }
27909          }
27910 
27911          if (string_is_not_equal(settings->arrays.midi_output, "Off"))
27912          {
27913             if (string_list_find_elem(p_rarch->midi_drv_outputs, settings->arrays.midi_output))
27914                output = settings->arrays.midi_output;
27915             else
27916             {
27917                RARCH_WARN("[MIDI]: Output device \"%s\" unavailable.\n",
27918                      settings->arrays.midi_output);
27919                configuration_set_string(settings,
27920                      settings->arrays.midi_output, "Off");
27921             }
27922          }
27923 
27924          p_rarch->midi_drv_data = midi_drv->init(input, output);
27925          if (!p_rarch->midi_drv_data)
27926             ret = false;
27927          else
27928          {
27929             p_rarch->midi_drv_input_enabled  = (input  != NULL);
27930             p_rarch->midi_drv_output_enabled = (output != NULL);
27931 
27932             if (!midi_driver_init_io_buffers(p_rarch))
27933                ret = false;
27934             else
27935             {
27936                if (input)
27937                   RARCH_LOG("[MIDI]: Input device \"%s\".\n", input);
27938 
27939                if (output)
27940                {
27941                   RARCH_LOG("[MIDI]: Output device \"%s\".\n", output);
27942                   midi_driver_set_volume(settings->uints.midi_volume);
27943                }
27944             }
27945          }
27946       }
27947    }
27948 
27949    if (!ret)
27950    {
27951       midi_driver_free(p_rarch);
27952       RARCH_ERR("[MIDI]: Initialization failed.\n");
27953       return false;
27954    }
27955    return true;
27956 }
27957 
midi_driver_set_input(const char * input)27958 bool midi_driver_set_input(const char *input)
27959 {
27960    struct rarch_state *p_rarch = &rarch_st;
27961 
27962    if (!p_rarch->midi_drv_data)
27963    {
27964 #ifdef DEBUG
27965       RARCH_ERR("[MIDI]: midi_driver_set_input called on uninitialized driver.\n");
27966 #endif
27967       return false;
27968    }
27969 
27970    if (string_is_equal(input, "Off"))
27971       input = NULL;
27972 
27973    if (!midi_drv->set_input(p_rarch->midi_drv_data, input))
27974    {
27975       if (input)
27976          RARCH_ERR("[MIDI]: Failed to change input device to \"%s\".\n", input);
27977       else
27978          RARCH_ERR("[MIDI]: Failed to disable input.\n");
27979       return false;
27980    }
27981 
27982    if (input)
27983       RARCH_LOG("[MIDI]: Input device changed to \"%s\".\n", input);
27984    else
27985       RARCH_LOG("[MIDI]: Input disabled.\n");
27986 
27987    p_rarch->midi_drv_input_enabled = input != NULL;
27988 
27989    return true;
27990 }
27991 
midi_driver_set_output(const char * output)27992 bool midi_driver_set_output(const char *output)
27993 {
27994    struct rarch_state *p_rarch = &rarch_st;
27995 
27996    if (!p_rarch->midi_drv_data)
27997    {
27998 #ifdef DEBUG
27999       RARCH_ERR("[MIDI]: midi_driver_set_output called on uninitialized driver.\n");
28000 #endif
28001       return false;
28002    }
28003 
28004    if (string_is_equal(output, "Off"))
28005       output = NULL;
28006 
28007    if (!midi_drv->set_output(p_rarch->midi_drv_data, output))
28008    {
28009       if (output)
28010          RARCH_ERR("[MIDI]: Failed to change output device to \"%s\".\n", output);
28011       else
28012          RARCH_ERR("[MIDI]: Failed to disable output.\n");
28013       return false;
28014    }
28015 
28016    if (output)
28017    {
28018       settings_t *settings             = p_rarch->configuration_settings;
28019 
28020       p_rarch->midi_drv_output_enabled = true;
28021       RARCH_LOG("[MIDI]: Output device changed to \"%s\".\n", output);
28022 
28023       if (settings)
28024          midi_driver_set_volume(settings->uints.midi_volume);
28025       else
28026          RARCH_ERR("[MIDI]: Volume change failed (settings unavailable).\n");
28027    }
28028    else
28029    {
28030       p_rarch->midi_drv_output_enabled = false;
28031       RARCH_LOG("[MIDI]: Output disabled.\n");
28032    }
28033 
28034    return true;
28035 }
28036 
midi_driver_input_enabled(void)28037 static bool midi_driver_input_enabled(void)
28038 {
28039    struct rarch_state *p_rarch = &rarch_st;
28040    return p_rarch->midi_drv_input_enabled;
28041 }
28042 
midi_driver_output_enabled(void)28043 static bool midi_driver_output_enabled(void)
28044 {
28045    struct rarch_state *p_rarch = &rarch_st;
28046    return p_rarch->midi_drv_output_enabled;
28047 }
28048 
midi_driver_read(uint8_t * byte)28049 static bool midi_driver_read(uint8_t *byte)
28050 {
28051    static int i;
28052    struct rarch_state *p_rarch = &rarch_st;
28053 
28054    if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_input_enabled || !byte)
28055    {
28056 #ifdef DEBUG
28057       if (!p_rarch->midi_drv_data)
28058          RARCH_ERR("[MIDI]: midi_driver_read called on uninitialized driver.\n");
28059       else if (!p_rarch->midi_drv_input_enabled)
28060          RARCH_ERR("[MIDI]: midi_driver_read called when input is disabled.\n");
28061       else
28062          RARCH_ERR("[MIDI]: midi_driver_read called with null pointer.\n");
28063 #endif
28064       return false;
28065    }
28066 
28067    if (i == p_rarch->midi_drv_input_event.data_size)
28068    {
28069       p_rarch->midi_drv_input_event.data_size = MIDI_DRIVER_BUF_SIZE;
28070       if (!midi_drv->read(p_rarch->midi_drv_data,
28071                &p_rarch->midi_drv_input_event))
28072       {
28073          p_rarch->midi_drv_input_event.data_size = i;
28074          return false;
28075       }
28076 
28077       i = 0;
28078 
28079 #ifdef DEBUG
28080       if (p_rarch->midi_drv_input_event.data_size == 1)
28081          RARCH_LOG("[MIDI]: In [0x%02X].\n",
28082                p_rarch->midi_drv_input_event.data[0]);
28083       else if (p_rarch->midi_drv_input_event.data_size == 2)
28084          RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X].\n",
28085                p_rarch->midi_drv_input_event.data[0],
28086                p_rarch->midi_drv_input_event.data[1]);
28087       else if (p_rarch->midi_drv_input_event.data_size == 3)
28088          RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X, 0x%02X].\n",
28089                p_rarch->midi_drv_input_event.data[0],
28090                p_rarch->midi_drv_input_event.data[1],
28091                p_rarch->midi_drv_input_event.data[2]);
28092       else
28093          RARCH_LOG("[MIDI]: In [0x%02X, ...], size %u.\n",
28094                p_rarch->midi_drv_input_event.data[0],
28095                p_rarch->midi_drv_input_event.data_size);
28096 #endif
28097    }
28098 
28099    *byte = p_rarch->midi_drv_input_event.data[i++];
28100 
28101    return true;
28102 }
28103 
midi_driver_write(uint8_t byte,uint32_t delta_time)28104 static bool midi_driver_write(uint8_t byte, uint32_t delta_time)
28105 {
28106    static int event_size;
28107    struct rarch_state *p_rarch = &rarch_st;
28108 
28109    if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled)
28110    {
28111 #ifdef DEBUG
28112       if (!p_rarch->midi_drv_data)
28113          RARCH_ERR("[MIDI]: midi_driver_write called on uninitialized driver.\n");
28114       else
28115          RARCH_ERR("[MIDI]: midi_driver_write called when output is disabled.\n");
28116 #endif
28117       return false;
28118    }
28119 
28120    if (byte >= 0x80)
28121    {
28122       if (p_rarch->midi_drv_output_event.data_size &&
28123             p_rarch->midi_drv_output_event.data[0] == 0xF0)
28124       {
28125          if (byte == 0xF7)
28126             event_size = (int)p_rarch->midi_drv_output_event.data_size + 1;
28127          else
28128          {
28129             if (!midi_drv->write(p_rarch->midi_drv_data,
28130                      &p_rarch->midi_drv_output_event))
28131                return false;
28132 
28133 #ifdef DEBUG
28134             switch (p_rarch->midi_drv_output_event.data_size)
28135             {
28136                case 1:
28137                   RARCH_LOG("[MIDI]: Out [0x%02X].\n",
28138                         p_rarch->midi_drv_output_event.data[0]);
28139                   break;
28140                case 2:
28141                   RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n",
28142                         p_rarch->midi_drv_output_event.data[0],
28143                         p_rarch->midi_drv_output_event.data[1]);
28144                   break;
28145                case 3:
28146                   RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n",
28147                         p_rarch->midi_drv_output_event.data[0],
28148                         p_rarch->midi_drv_output_event.data[1],
28149                         p_rarch->midi_drv_output_event.data[2]);
28150                   break;
28151                default:
28152                   RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n",
28153                         p_rarch->midi_drv_output_event.data[0],
28154                         p_rarch->midi_drv_output_event.data_size);
28155                   break;
28156             }
28157 #endif
28158 
28159             p_rarch->midi_drv_output_pending          = true;
28160             event_size                                = (int)midi_driver_get_event_size(byte);
28161             p_rarch->midi_drv_output_event.data_size  = 0;
28162             p_rarch->midi_drv_output_event.delta_time = 0;
28163          }
28164       }
28165       else
28166       {
28167          event_size                                   = (int)midi_driver_get_event_size(byte);
28168          p_rarch->midi_drv_output_event.data_size     = 0;
28169          p_rarch->midi_drv_output_event.delta_time    = 0;
28170       }
28171    }
28172 
28173    if (p_rarch->midi_drv_output_event.data_size < MIDI_DRIVER_BUF_SIZE)
28174    {
28175       p_rarch->midi_drv_output_event.data[p_rarch->midi_drv_output_event.data_size] = byte;
28176       ++p_rarch->midi_drv_output_event.data_size;
28177       p_rarch->midi_drv_output_event.delta_time += delta_time;
28178    }
28179    else
28180    {
28181 #ifdef DEBUG
28182       RARCH_ERR("[MIDI]: Output event dropped.\n");
28183 #endif
28184       return false;
28185    }
28186 
28187    if (p_rarch->midi_drv_output_event.data_size == event_size)
28188    {
28189       if (!midi_drv->write(p_rarch->midi_drv_data,
28190                &p_rarch->midi_drv_output_event))
28191          return false;
28192 
28193 #ifdef DEBUG
28194       switch (p_rarch->midi_drv_output_event.data_size)
28195       {
28196          case 1:
28197             RARCH_LOG("[MIDI]: Out [0x%02X].\n",
28198                   p_rarch->midi_drv_output_event.data[0]);
28199             break;
28200          case 2:
28201             RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n",
28202                   p_rarch->midi_drv_output_event.data[0],
28203                   p_rarch->midi_drv_output_event.data[1]);
28204             break;
28205          case 3:
28206             RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n",
28207                   p_rarch->midi_drv_output_event.data[0],
28208                   p_rarch->midi_drv_output_event.data[1],
28209                   p_rarch->midi_drv_output_event.data[2]);
28210             break;
28211          default:
28212             RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n",
28213                   p_rarch->midi_drv_output_event.data[0],
28214                   p_rarch->midi_drv_output_event.data_size);
28215             break;
28216       }
28217 #endif
28218 
28219       p_rarch->midi_drv_output_pending             = true;
28220       p_rarch->midi_drv_output_event.data_size     = 0;
28221       p_rarch->midi_drv_output_event.delta_time    = 0;
28222    }
28223 
28224    return true;
28225 }
28226 
midi_driver_flush(void)28227 static bool midi_driver_flush(void)
28228 {
28229    struct rarch_state *p_rarch = &rarch_st;
28230    if (!p_rarch->midi_drv_data)
28231       return false;
28232 
28233    if (p_rarch->midi_drv_output_pending)
28234       p_rarch->midi_drv_output_pending =
28235          !midi_drv->flush(p_rarch->midi_drv_data);
28236 
28237    return !p_rarch->midi_drv_output_pending;
28238 }
28239 
midi_driver_get_event_size(uint8_t status)28240 size_t midi_driver_get_event_size(uint8_t status)
28241 {
28242    static const uint8_t midi_drv_ev_sizes[128]                     =
28243    {
28244       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
28245       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
28246       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
28247       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
28248       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
28249       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
28250       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
28251       0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
28252    };
28253 
28254    if (status < 0x80)
28255    {
28256 #ifdef DEBUG
28257       RARCH_ERR("[MIDI]: midi_driver_get_event_size called with invalid status.\n");
28258 #endif
28259       return 0;
28260    }
28261 
28262    return midi_drv_ev_sizes[status - 0x80];
28263 }
28264 
28265 /* AUDIO */
28266 
audio_driver_get_resampler_quality(settings_t * settings)28267 static enum resampler_quality audio_driver_get_resampler_quality(
28268       settings_t *settings)
28269 {
28270    if (settings)
28271       return (enum resampler_quality)settings->uints.audio_resampler_quality;
28272    return RESAMPLER_QUALITY_DONTCARE;
28273 }
28274 
28275 #ifdef HAVE_AUDIOMIXER
audio_driver_mixer_get_stream(unsigned i)28276 audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i)
28277 {
28278    struct rarch_state *p_rarch = &rarch_st;
28279    if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
28280       return NULL;
28281    return &p_rarch->audio_mixer_streams[i];
28282 }
28283 
audio_driver_mixer_get_stream_name(unsigned i)28284 const char *audio_driver_mixer_get_stream_name(unsigned i)
28285 {
28286    struct rarch_state *p_rarch = &rarch_st;
28287    if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
28288       return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
28289    if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
28290       return p_rarch->audio_mixer_streams[i].name;
28291    return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
28292 }
28293 
audio_driver_mixer_deinit(struct rarch_state * p_rarch)28294 static void audio_driver_mixer_deinit(struct rarch_state *p_rarch)
28295 {
28296    unsigned i;
28297 
28298    p_rarch->audio_mixer_active = false;
28299 
28300    for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
28301    {
28302       audio_driver_mixer_stop_stream(i);
28303       audio_driver_mixer_remove_stream(i);
28304    }
28305 
28306    audio_mixer_done();
28307 }
28308 #endif
28309 
28310 /**
28311  * audio_compute_buffer_statistics:
28312  *
28313  * Computes audio buffer statistics.
28314  *
28315  **/
audio_compute_buffer_statistics(struct rarch_state * p_rarch,audio_statistics_t * stats)28316 static bool audio_compute_buffer_statistics(
28317       struct rarch_state *p_rarch,
28318       audio_statistics_t *stats)
28319 {
28320    unsigned i, low_water_size, high_water_size, avg, stddev;
28321    uint64_t accum                = 0;
28322    uint64_t accum_var            = 0;
28323    unsigned low_water_count      = 0;
28324    unsigned high_water_count     = 0;
28325    unsigned samples              = MIN(
28326          (unsigned)p_rarch->audio_driver_free_samples_count,
28327          AUDIO_BUFFER_FREE_SAMPLES_COUNT);
28328 
28329    if (samples < 3)
28330       return false;
28331 
28332    stats->samples                = (unsigned)
28333       p_rarch->audio_driver_free_samples_count;
28334 
28335 #ifdef WARPUP
28336    /* uint64 to double not implemented, fair chance
28337     * signed int64 to double doesn't exist either */
28338    /* https://forums.libretro.com/t/unsupported-platform-help/13903/ */
28339    (void)stddev;
28340 #elif defined(_MSC_VER) && _MSC_VER <= 1200
28341    /* FIXME: error C2520: conversion from unsigned __int64
28342     * to double not implemented, use signed __int64 */
28343    (void)stddev;
28344 #else
28345    for (i = 1; i < samples; i++)
28346       accum += p_rarch->audio_driver_free_samples_buf[i];
28347 
28348    avg = (unsigned)accum / (samples - 1);
28349 
28350    for (i = 1; i < samples; i++)
28351    {
28352       int diff     = avg - p_rarch->audio_driver_free_samples_buf[i];
28353       accum_var   += diff * diff;
28354    }
28355 
28356    stddev                                = (unsigned)
28357       sqrt((double)accum_var / (samples - 2));
28358 
28359    stats->average_buffer_saturation      = (1.0f - (float)avg
28360          / p_rarch->audio_driver_buffer_size) * 100.0;
28361    stats->std_deviation_percentage       = ((float)stddev
28362          / p_rarch->audio_driver_buffer_size)  * 100.0;
28363 #endif
28364 
28365    low_water_size  = (unsigned)(p_rarch->audio_driver_buffer_size * 3 / 4);
28366    high_water_size = (unsigned)(p_rarch->audio_driver_buffer_size     / 4);
28367 
28368    for (i = 1; i < samples; i++)
28369    {
28370       if (p_rarch->audio_driver_free_samples_buf[i] >= low_water_size)
28371          low_water_count++;
28372       else if (p_rarch->audio_driver_free_samples_buf[i] <= high_water_size)
28373          high_water_count++;
28374    }
28375 
28376    stats->close_to_underrun      = (100.0f * low_water_count)  / (samples - 1);
28377    stats->close_to_blocking      = (100.0f * high_water_count) / (samples - 1);
28378 
28379    return true;
28380 }
28381 
28382 #ifdef DEBUG
report_audio_buffer_statistics(struct rarch_state * p_rarch)28383 static void report_audio_buffer_statistics(struct rarch_state *p_rarch)
28384 {
28385    audio_statistics_t audio_stats;
28386    audio_stats.samples                   = 0;
28387    audio_stats.average_buffer_saturation = 0.0f;
28388    audio_stats.std_deviation_percentage  = 0.0f;
28389    audio_stats.close_to_underrun         = 0.0f;
28390    audio_stats.close_to_blocking         = 0.0f;
28391 
28392    if (!audio_compute_buffer_statistics(p_rarch, &audio_stats))
28393       return;
28394 
28395    RARCH_LOG("[Audio]: Average audio buffer saturation: %.2f %%,"
28396          " standard deviation (percentage points): %.2f %%.\n"
28397          "[Audio]: Amount of time spent close to underrun: %.2f %%."
28398          " Close to blocking: %.2f %%.\n",
28399          audio_stats.average_buffer_saturation,
28400          audio_stats.std_deviation_percentage,
28401          audio_stats.close_to_underrun,
28402          audio_stats.close_to_blocking);
28403 }
28404 #endif
28405 
28406 /**
28407  * config_get_audio_driver_options:
28408  *
28409  * Get an enumerated list of all audio driver names, separated by '|'.
28410  *
28411  * Returns: string listing of all audio driver names, separated by '|'.
28412  **/
config_get_audio_driver_options(void)28413 const char *config_get_audio_driver_options(void)
28414 {
28415    return char_list_new_special(STRING_LIST_AUDIO_DRIVERS, NULL);
28416 }
28417 
audio_driver_deinit_resampler(struct rarch_state * p_rarch)28418 static void audio_driver_deinit_resampler(struct rarch_state *p_rarch)
28419 {
28420    if (p_rarch->audio_driver_resampler && p_rarch->audio_driver_resampler_data)
28421       p_rarch->audio_driver_resampler->free(p_rarch->audio_driver_resampler_data);
28422    p_rarch->audio_driver_resampler      = NULL;
28423    p_rarch->audio_driver_resampler_data = NULL;
28424 }
28425 
28426 
audio_driver_deinit_internal(struct rarch_state * p_rarch,bool audio_enable)28427 static bool audio_driver_deinit_internal(struct rarch_state *p_rarch,
28428       bool audio_enable)
28429 {
28430    if (p_rarch->current_audio && p_rarch->current_audio->free)
28431    {
28432       if (p_rarch->audio_driver_context_audio_data)
28433          p_rarch->current_audio->free(
28434                p_rarch->audio_driver_context_audio_data);
28435       p_rarch->audio_driver_context_audio_data = NULL;
28436    }
28437 
28438    if (p_rarch->audio_driver_output_samples_conv_buf)
28439       memalign_free(p_rarch->audio_driver_output_samples_conv_buf);
28440    p_rarch->audio_driver_output_samples_conv_buf     = NULL;
28441 
28442    if (p_rarch->audio_driver_input_data)
28443       memalign_free(p_rarch->audio_driver_input_data);
28444    p_rarch->audio_driver_input_data = NULL;
28445 
28446    p_rarch->audio_driver_data_ptr           = 0;
28447 
28448 #ifdef HAVE_REWIND
28449    if (p_rarch->audio_driver_rewind_buf)
28450       memalign_free(p_rarch->audio_driver_rewind_buf);
28451    p_rarch->audio_driver_rewind_buf         = NULL;
28452 
28453    p_rarch->audio_driver_rewind_size        = 0;
28454 #endif
28455 
28456    if (!audio_enable)
28457    {
28458       p_rarch->audio_driver_active          = false;
28459       return false;
28460    }
28461 
28462    audio_driver_deinit_resampler(p_rarch);
28463 
28464    if (p_rarch->audio_driver_output_samples_buf)
28465       memalign_free(p_rarch->audio_driver_output_samples_buf);
28466    p_rarch->audio_driver_output_samples_buf = NULL;
28467 
28468 #ifdef HAVE_DSP_FILTER
28469    audio_driver_dsp_filter_free();
28470 #endif
28471 #ifdef DEBUG
28472    report_audio_buffer_statistics(p_rarch);
28473 #endif
28474 
28475    return true;
28476 }
28477 
audio_driver_free_devices_list(struct rarch_state * p_rarch)28478 static bool audio_driver_free_devices_list(struct rarch_state *p_rarch)
28479 {
28480    if (!p_rarch->current_audio || !p_rarch->current_audio->device_list_free
28481          || !p_rarch->audio_driver_context_audio_data)
28482       return false;
28483    p_rarch->current_audio->device_list_free(
28484          p_rarch->audio_driver_context_audio_data,
28485          p_rarch->audio_driver_devices_list);
28486    p_rarch->audio_driver_devices_list = NULL;
28487    return true;
28488 }
28489 
audio_driver_deinit(struct rarch_state * p_rarch,settings_t * settings)28490 static bool audio_driver_deinit(struct rarch_state *p_rarch,
28491       settings_t *settings)
28492 {
28493 #ifdef HAVE_AUDIOMIXER
28494    audio_driver_mixer_deinit(p_rarch);
28495 #endif
28496    audio_driver_free_devices_list(p_rarch);
28497 
28498    return audio_driver_deinit_internal(p_rarch,
28499          settings->bools.audio_enable);
28500 }
28501 
audio_driver_find_driver(struct rarch_state * p_rarch,settings_t * settings,const char * prefix,bool verbosity_enabled)28502 static bool audio_driver_find_driver(struct rarch_state *p_rarch,
28503       settings_t *settings,
28504       const char *prefix,
28505       bool verbosity_enabled)
28506 {
28507    int i                   = (int)driver_find_index(
28508          "audio_driver",
28509          settings->arrays.audio_driver);
28510 
28511    if (i >= 0)
28512       p_rarch->current_audio = (const audio_driver_t*)
28513          audio_drivers[i];
28514    else
28515    {
28516       if (verbosity_enabled)
28517       {
28518          unsigned d;
28519          RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
28520                settings->arrays.audio_driver);
28521          RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
28522          for (d = 0; audio_drivers[d]; d++)
28523          {
28524             if (audio_drivers[d])
28525                RARCH_LOG_OUTPUT("\t%s\n", audio_drivers[d]->ident);
28526          }
28527          RARCH_WARN("Going to default to first %s...\n", prefix);
28528       }
28529 
28530       p_rarch->current_audio = (const audio_driver_t*)
28531          audio_drivers[0];
28532 
28533       if (!p_rarch->current_audio)
28534          retroarch_fail(p_rarch, 1, "audio_driver_find()");
28535    }
28536 
28537    return true;
28538 }
28539 
audio_driver_init_internal(struct rarch_state * p_rarch,settings_t * settings,bool audio_cb_inited)28540 static bool audio_driver_init_internal(
28541       struct rarch_state *p_rarch,
28542       settings_t *settings,
28543       bool audio_cb_inited)
28544 {
28545    unsigned new_rate       = 0;
28546    float  *samples_buf     = NULL;
28547    size_t max_bufsamples   = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
28548    bool audio_enable       = settings->bools.audio_enable;
28549    bool audio_sync         = settings->bools.audio_sync;
28550    bool audio_rate_control = settings->bools.audio_rate_control;
28551    float slowmotion_ratio  = settings->floats.slowmotion_ratio;
28552    unsigned audio_latency  = (runloop_state.audio_latency > settings->uints.audio_latency) ?
28553          runloop_state.audio_latency : settings->uints.audio_latency;
28554 #ifdef HAVE_REWIND
28555    int16_t *rewind_buf     = NULL;
28556 #endif
28557    /* Accomodate rewind since at some point we might have two full buffers. */
28558    size_t outsamples_max   = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO * slowmotion_ratio;
28559    int16_t *conv_buf       = (int16_t*)memalign_alloc(64, outsamples_max * sizeof(int16_t));
28560    float *audio_buf        = (float*)memalign_alloc(64, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
28561    bool verbosity_enabled  = verbosity_is_enabled();
28562 
28563    convert_s16_to_float_init_simd();
28564    convert_float_to_s16_init_simd();
28565 
28566    /* Used for recording even if audio isn't enabled. */
28567    retro_assert(conv_buf != NULL);
28568    retro_assert(audio_buf != NULL);
28569 
28570    if (!conv_buf || !audio_buf)
28571       goto error;
28572 
28573    memset(audio_buf, 0, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
28574 
28575    p_rarch->audio_driver_input_data              = audio_buf;
28576    p_rarch->audio_driver_output_samples_conv_buf = conv_buf;
28577    p_rarch->audio_driver_chunk_block_size        = AUDIO_CHUNK_SIZE_BLOCKING;
28578    p_rarch->audio_driver_chunk_nonblock_size     = AUDIO_CHUNK_SIZE_NONBLOCKING;
28579    p_rarch->audio_driver_chunk_size              = p_rarch->audio_driver_chunk_block_size;
28580 
28581 #ifdef HAVE_REWIND
28582    /* Needs to be able to hold full content of a full max_bufsamples
28583     * in addition to its own. */
28584    rewind_buf = (int16_t*)memalign_alloc(64, max_bufsamples * sizeof(int16_t));
28585    retro_assert(rewind_buf != NULL);
28586 
28587    if (!rewind_buf)
28588       goto error;
28589 
28590    p_rarch->audio_driver_rewind_buf              = rewind_buf;
28591    p_rarch->audio_driver_rewind_size             = max_bufsamples;
28592 #endif
28593 
28594    if (!audio_enable)
28595    {
28596       p_rarch->audio_driver_active = false;
28597       return false;
28598    }
28599 
28600    audio_driver_find_driver(p_rarch, settings,
28601          "audio driver", verbosity_enabled);
28602 
28603    if (!p_rarch->current_audio || !p_rarch->current_audio->init)
28604    {
28605       RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
28606       p_rarch->audio_driver_active = false;
28607       return false;
28608    }
28609 
28610 #ifdef HAVE_THREADS
28611    if (audio_cb_inited)
28612    {
28613       RARCH_LOG("[Audio]: Starting threaded audio driver ...\n");
28614       if (!audio_init_thread(
28615                &p_rarch->current_audio,
28616                &p_rarch->audio_driver_context_audio_data,
28617                *settings->arrays.audio_device
28618                ? settings->arrays.audio_device : NULL,
28619                settings->uints.audio_output_sample_rate, &new_rate,
28620                audio_latency,
28621                settings->uints.audio_block_frames,
28622                p_rarch->current_audio))
28623       {
28624          RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
28625          retroarch_fail(p_rarch, 1, "audio_driver_init_internal()");
28626       }
28627    }
28628    else
28629 #endif
28630    {
28631       p_rarch->audio_driver_context_audio_data =
28632          p_rarch->current_audio->init(*settings->arrays.audio_device ?
28633                settings->arrays.audio_device : NULL,
28634                settings->uints.audio_output_sample_rate,
28635                audio_latency,
28636                settings->uints.audio_block_frames,
28637                &new_rate);
28638    }
28639 
28640    if (new_rate != 0)
28641       configuration_set_int(settings, settings->uints.audio_output_sample_rate, new_rate);
28642 
28643    if (!p_rarch->audio_driver_context_audio_data)
28644    {
28645       RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
28646       p_rarch->audio_driver_active    = false;
28647    }
28648 
28649    p_rarch->audio_driver_use_float    = false;
28650    if (     p_rarch->audio_driver_active
28651          && p_rarch->current_audio->use_float(
28652             p_rarch->audio_driver_context_audio_data))
28653       p_rarch->audio_driver_use_float = true;
28654 
28655    if (!audio_sync && p_rarch->audio_driver_active)
28656    {
28657       if (p_rarch->audio_driver_active &&
28658             p_rarch->audio_driver_context_audio_data)
28659          p_rarch->current_audio->set_nonblock_state(
28660                p_rarch->audio_driver_context_audio_data, true);
28661 
28662       p_rarch->audio_driver_chunk_size =
28663          p_rarch->audio_driver_chunk_nonblock_size;
28664    }
28665 
28666    if (p_rarch->audio_driver_input <= 0.0f)
28667    {
28668       /* Should never happen. */
28669       RARCH_WARN("[Audio]: Input rate is invalid (%.3f Hz)."
28670             " Using output rate (%u Hz).\n",
28671             p_rarch->audio_driver_input, settings->uints.audio_output_sample_rate);
28672 
28673       p_rarch->audio_driver_input = settings->uints.audio_output_sample_rate;
28674    }
28675 
28676    p_rarch->audio_source_ratio_original   =
28677       p_rarch->audio_source_ratio_current =
28678       (double)settings->uints.audio_output_sample_rate / p_rarch->audio_driver_input;
28679 
28680    if (!retro_resampler_realloc(
28681             &p_rarch->audio_driver_resampler_data,
28682             &p_rarch->audio_driver_resampler,
28683             settings->arrays.audio_resampler,
28684             audio_driver_get_resampler_quality(settings),
28685             p_rarch->audio_source_ratio_original))
28686    {
28687       RARCH_ERR("Failed to initialize resampler \"%s\".\n",
28688             settings->arrays.audio_resampler);
28689       p_rarch->audio_driver_active = false;
28690    }
28691 
28692    p_rarch->audio_driver_data_ptr   = 0;
28693 
28694    retro_assert(settings->uints.audio_output_sample_rate <
28695          p_rarch->audio_driver_input * AUDIO_MAX_RATIO);
28696 
28697    samples_buf = (float*)memalign_alloc(64, outsamples_max * sizeof(float));
28698 
28699    retro_assert(samples_buf != NULL);
28700 
28701    if (!samples_buf)
28702       goto error;
28703 
28704    p_rarch->audio_driver_output_samples_buf = (float*)samples_buf;
28705    p_rarch->audio_driver_control            = false;
28706 
28707    if (
28708          !audio_cb_inited
28709          && p_rarch->audio_driver_active
28710          && audio_rate_control
28711          )
28712    {
28713       /* Audio rate control requires write_avail
28714        * and buffer_size to be implemented. */
28715       if (p_rarch->current_audio->buffer_size)
28716       {
28717          p_rarch->audio_driver_buffer_size =
28718             p_rarch->current_audio->buffer_size(
28719                   p_rarch->audio_driver_context_audio_data);
28720          p_rarch->audio_driver_control     = true;
28721       }
28722       else
28723          RARCH_WARN("[Audio]: Rate control was desired, but driver does not support needed features.\n");
28724    }
28725 
28726    command_event(CMD_EVENT_DSP_FILTER_INIT, NULL);
28727 
28728    p_rarch->audio_driver_free_samples_count = 0;
28729 
28730 #ifdef HAVE_AUDIOMIXER
28731    audio_mixer_init(settings->uints.audio_output_sample_rate);
28732 #endif
28733 
28734    /* Threaded driver is initially stopped. */
28735    if (
28736          p_rarch->audio_driver_active
28737          && audio_cb_inited
28738          )
28739       audio_driver_start(p_rarch,
28740             false);
28741 
28742    return true;
28743 
28744 error:
28745    return audio_driver_deinit(p_rarch, settings);
28746 }
28747 
28748 /**
28749  * audio_driver_flush:
28750  * @data                 : pointer to audio buffer.
28751  * @right                : amount of samples to write.
28752  *
28753  * Writes audio samples to audio driver. Will first
28754  * perform DSP processing (if enabled) and resampling.
28755  **/
audio_driver_flush(struct rarch_state * p_rarch,float slowmotion_ratio,bool audio_fastforward_mute,const int16_t * data,size_t samples,bool is_slowmotion,bool is_fastmotion)28756 static void audio_driver_flush(
28757       struct rarch_state *p_rarch,
28758       float slowmotion_ratio,
28759       bool audio_fastforward_mute,
28760       const int16_t *data, size_t samples,
28761       bool is_slowmotion, bool is_fastmotion)
28762 {
28763    struct resampler_data src_data;
28764    float audio_volume_gain           = (p_rarch->audio_driver_mute_enable ||
28765          (audio_fastforward_mute && is_fastmotion)) ?
28766                0.0f : p_rarch->audio_driver_volume_gain;
28767 
28768    src_data.data_out                 = NULL;
28769    src_data.output_frames            = 0;
28770 
28771    convert_s16_to_float(p_rarch->audio_driver_input_data, data, samples,
28772          audio_volume_gain);
28773 
28774    src_data.data_in                  = p_rarch->audio_driver_input_data;
28775    src_data.input_frames             = samples >> 1;
28776 
28777 #ifdef HAVE_DSP_FILTER
28778    if (p_rarch->audio_driver_dsp)
28779    {
28780       struct retro_dsp_data dsp_data;
28781 
28782       dsp_data.input                 = NULL;
28783       dsp_data.input_frames          = 0;
28784       dsp_data.output                = NULL;
28785       dsp_data.output_frames         = 0;
28786 
28787       dsp_data.input                 = p_rarch->audio_driver_input_data;
28788       dsp_data.input_frames          = (unsigned)(samples >> 1);
28789 
28790       retro_dsp_filter_process(p_rarch->audio_driver_dsp, &dsp_data);
28791 
28792       if (dsp_data.output)
28793       {
28794          src_data.data_in            = dsp_data.output;
28795          src_data.input_frames       = dsp_data.output_frames;
28796       }
28797    }
28798 #endif
28799 
28800    src_data.data_out                 = p_rarch->audio_driver_output_samples_buf;
28801 
28802    if (p_rarch->audio_driver_control)
28803    {
28804       /* Readjust the audio input rate. */
28805       int      half_size           =
28806          (int)(p_rarch->audio_driver_buffer_size / 2);
28807       int      avail               =
28808          (int)p_rarch->current_audio->write_avail(
28809                p_rarch->audio_driver_context_audio_data);
28810       int      delta_mid           = avail - half_size;
28811       double   direction           = (double)delta_mid / half_size;
28812       double   adjust              = 1.0 +
28813          p_rarch->audio_driver_rate_control_delta * direction;
28814       unsigned write_idx           =
28815          p_rarch->audio_driver_free_samples_count++ &
28816          (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
28817 
28818       p_rarch->audio_driver_free_samples_buf
28819          [write_idx]                        = avail;
28820       p_rarch->audio_source_ratio_current   =
28821          p_rarch->audio_source_ratio_original * adjust;
28822 
28823 #if 0
28824       if (verbosity_is_enabled())
28825       {
28826          RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n",
28827                (unsigned)(100 - (avail * 100) /
28828                   p_rarch->audio_driver_buffer_size));
28829          RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
28830                p_rarch->audio_source_ratio_current,
28831                p_rarch->audio_source_ratio_original);
28832       }
28833 #endif
28834    }
28835 
28836    src_data.ratio           = p_rarch->audio_source_ratio_current;
28837 
28838    if (is_slowmotion)
28839       src_data.ratio       *= slowmotion_ratio;
28840 
28841    /* Note: Ideally we would divide by the user-configured
28842     * 'fastforward_ratio' when fast forward is enabled,
28843     * but in practice this doesn't work:
28844     * - 'fastforward_ratio' is only a limit. If the host
28845     *   cannot push frames fast enough, the actual ratio
28846     *   will be lower - and crackling will ensue
28847     * - Most of the time 'fastforward_ratio' will be
28848     *   zero (unlimited)
28849     * So what we would need to do is measure the time since
28850     * the last audio flush operation, and calculate a 'real'
28851     * fast-forward ratio - but this doesn't work either.
28852     * The measurement is inaccurate and the frame-by-frame
28853     * fluctuations are too large, so crackling is unavoidable.
28854     * Since it's going to crackle anyway, there's no point
28855     * trying to do anything. Just leave the ratio as-is,
28856     * and hope for the best... */
28857 
28858    p_rarch->audio_driver_resampler->process(
28859          p_rarch->audio_driver_resampler_data, &src_data);
28860 
28861 #ifdef HAVE_AUDIOMIXER
28862    if (p_rarch->audio_mixer_active)
28863    {
28864       bool override                       = true;
28865       float mixer_gain                    = 0.0f;
28866       bool audio_driver_mixer_mute_enable =
28867          p_rarch->audio_driver_mixer_mute_enable;
28868 
28869       if (!audio_driver_mixer_mute_enable)
28870       {
28871          if (p_rarch->audio_driver_mixer_volume_gain == 1.0f)
28872             override                      = false;
28873          mixer_gain                       =
28874             p_rarch->audio_driver_mixer_volume_gain;
28875       }
28876       audio_mixer_mix(
28877             p_rarch->audio_driver_output_samples_buf,
28878             src_data.output_frames, mixer_gain, override);
28879    }
28880 #endif
28881 
28882    {
28883       const void *output_data = p_rarch->audio_driver_output_samples_buf;
28884       unsigned output_frames  = (unsigned)src_data.output_frames;
28885 
28886       if (p_rarch->audio_driver_use_float)
28887          output_frames       *= sizeof(float);
28888       else
28889       {
28890          convert_float_to_s16(p_rarch->audio_driver_output_samples_conv_buf,
28891                (const float*)output_data, output_frames * 2);
28892 
28893          output_data          = p_rarch->audio_driver_output_samples_conv_buf;
28894          output_frames       *= sizeof(int16_t);
28895       }
28896 
28897       if (p_rarch->current_audio->write(
28898                p_rarch->audio_driver_context_audio_data,
28899                output_data, output_frames * 2) < 0)
28900          p_rarch->audio_driver_active = false;
28901    }
28902 }
28903 
28904 /**
28905  * audio_driver_sample:
28906  * @left                 : value of the left audio channel.
28907  * @right                : value of the right audio channel.
28908  *
28909  * Audio sample render callback function.
28910  **/
audio_driver_sample(int16_t left,int16_t right)28911 static void audio_driver_sample(int16_t left, int16_t right)
28912 {
28913    struct rarch_state *p_rarch = &rarch_st;
28914    if (p_rarch->audio_suspended)
28915       return;
28916 
28917    p_rarch->audio_driver_output_samples_conv_buf[p_rarch->audio_driver_data_ptr++] = left;
28918    p_rarch->audio_driver_output_samples_conv_buf[p_rarch->audio_driver_data_ptr++] = right;
28919 
28920    if (p_rarch->audio_driver_data_ptr < p_rarch->audio_driver_chunk_size)
28921       return;
28922 
28923    if (  p_rarch->recording_data     &&
28924          p_rarch->recording_driver   &&
28925          p_rarch->recording_driver->push_audio)
28926    {
28927       struct record_audio_data ffemu_data;
28928 
28929       ffemu_data.data                    = p_rarch->audio_driver_output_samples_conv_buf;
28930       ffemu_data.frames                  = p_rarch->audio_driver_data_ptr / 2;
28931 
28932       p_rarch->recording_driver->push_audio(p_rarch->recording_data, &ffemu_data);
28933    }
28934 
28935    if (!(runloop_state.paused           ||
28936 		   !p_rarch->audio_driver_active     ||
28937 		   !p_rarch->audio_driver_output_samples_buf))
28938       audio_driver_flush(
28939             p_rarch,
28940             p_rarch->configuration_settings->floats.slowmotion_ratio,
28941             p_rarch->configuration_settings->bools.audio_fastforward_mute,
28942             p_rarch->audio_driver_output_samples_conv_buf,
28943             p_rarch->audio_driver_data_ptr,
28944             runloop_state.slowmotion,
28945             runloop_state.fastmotion);
28946 
28947    p_rarch->audio_driver_data_ptr = 0;
28948 }
28949 
28950 #ifdef HAVE_MENU
audio_driver_menu_sample(void)28951 static void audio_driver_menu_sample(void)
28952 {
28953    static int16_t samples_buf[1024]       = {0};
28954    struct rarch_state          *p_rarch   = &rarch_st;
28955    struct retro_system_av_info *av_info   = &p_rarch->video_driver_av_info;
28956    const struct retro_system_timing *info =
28957       (const struct retro_system_timing*)&av_info->timing;
28958    unsigned sample_count                  = (info->sample_rate / info->fps) * 2;
28959    bool check_flush                       = !(
28960          runloop_state.paused           ||
28961          !p_rarch->audio_driver_active     ||
28962          !p_rarch->audio_driver_output_samples_buf);
28963 
28964    while (sample_count > 1024)
28965    {
28966       if (  p_rarch->recording_data   &&
28967             p_rarch->recording_driver &&
28968             p_rarch->recording_driver->push_audio)
28969       {
28970          struct record_audio_data ffemu_data;
28971 
28972          ffemu_data.data                    = samples_buf;
28973          ffemu_data.frames                  = 1024 / 2;
28974 
28975          p_rarch->recording_driver->push_audio(
28976                p_rarch->recording_data, &ffemu_data);
28977       }
28978       if (check_flush)
28979          audio_driver_flush(
28980                p_rarch,
28981                p_rarch->configuration_settings->floats.slowmotion_ratio,
28982                p_rarch->configuration_settings->bools.audio_fastforward_mute,
28983                samples_buf,
28984                1024,
28985                runloop_state.slowmotion,
28986                runloop_state.fastmotion);
28987       sample_count -= 1024;
28988    }
28989    if (  p_rarch->recording_data   &&
28990          p_rarch->recording_driver &&
28991          p_rarch->recording_driver->push_audio)
28992    {
28993       struct record_audio_data ffemu_data;
28994 
28995       ffemu_data.data                    = samples_buf;
28996       ffemu_data.frames                  = sample_count / 2;
28997 
28998       p_rarch->recording_driver->push_audio(
28999             p_rarch->recording_data, &ffemu_data);
29000    }
29001    if (check_flush)
29002       audio_driver_flush(
29003             p_rarch,
29004             p_rarch->configuration_settings->floats.slowmotion_ratio,
29005             p_rarch->configuration_settings->bools.audio_fastforward_mute,
29006             samples_buf,
29007             sample_count,
29008             runloop_state.slowmotion,
29009             runloop_state.fastmotion);
29010 }
29011 #endif
29012 
29013 /**
29014  * audio_driver_sample_batch:
29015  * @data                 : pointer to audio buffer.
29016  * @frames               : amount of audio frames to push.
29017  *
29018  * Batched audio sample render callback function.
29019  *
29020  * Returns: amount of frames sampled. Will be equal to @frames
29021  * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2).
29022  **/
audio_driver_sample_batch(const int16_t * data,size_t frames)29023 static size_t audio_driver_sample_batch(const int16_t *data, size_t frames)
29024 {
29025    struct rarch_state            *p_rarch = &rarch_st;
29026    if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
29027       frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
29028 
29029    if (p_rarch->audio_suspended)
29030       return frames;
29031 
29032    if (  p_rarch->recording_data   &&
29033          p_rarch->recording_driver &&
29034          p_rarch->recording_driver->push_audio)
29035    {
29036       struct record_audio_data ffemu_data;
29037 
29038       ffemu_data.data                    = data;
29039       ffemu_data.frames                  = (frames << 1) / 2;
29040 
29041       p_rarch->recording_driver->push_audio(
29042             p_rarch->recording_data, &ffemu_data);
29043    }
29044 
29045    if (!(
29046          runloop_state.paused           ||
29047          !p_rarch->audio_driver_active     ||
29048          !p_rarch->audio_driver_output_samples_buf))
29049       audio_driver_flush(
29050             p_rarch,
29051             p_rarch->configuration_settings->floats.slowmotion_ratio,
29052             p_rarch->configuration_settings->bools.audio_fastforward_mute,
29053             data,
29054             frames << 1,
29055             runloop_state.slowmotion,
29056             runloop_state.fastmotion);
29057 
29058    return frames;
29059 }
29060 
29061 #ifdef HAVE_REWIND
29062 /**
29063  * audio_driver_sample_rewind:
29064  * @left                 : value of the left audio channel.
29065  * @right                : value of the right audio channel.
29066  *
29067  * Audio sample render callback function (rewind version).
29068  * This callback function will be used instead of
29069  * audio_driver_sample when rewinding is activated.
29070  **/
audio_driver_sample_rewind(int16_t left,int16_t right)29071 static void audio_driver_sample_rewind(int16_t left, int16_t right)
29072 {
29073    struct rarch_state *p_rarch   = &rarch_st;
29074    if (p_rarch->audio_driver_rewind_ptr == 0)
29075       return;
29076 
29077    p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = right;
29078    p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = left;
29079 }
29080 
29081 /**
29082  * audio_driver_sample_batch_rewind:
29083  * @data                 : pointer to audio buffer.
29084  * @frames               : amount of audio frames to push.
29085  *
29086  * Batched audio sample render callback function (rewind version).
29087  *
29088  * This callback function will be used instead of
29089  * audio_driver_sample_batch when rewinding is activated.
29090  *
29091  * Returns: amount of frames sampled. Will be equal to @frames
29092  * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2).
29093  **/
audio_driver_sample_batch_rewind(const int16_t * data,size_t frames)29094 static size_t audio_driver_sample_batch_rewind(
29095       const int16_t *data, size_t frames)
29096 {
29097    size_t i;
29098    struct rarch_state *p_rarch   = &rarch_st;
29099    size_t              samples   = frames << 1;
29100 
29101    for (i = 0; i < samples; i++)
29102    {
29103       if (p_rarch->audio_driver_rewind_ptr > 0)
29104          p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = data[i];
29105    }
29106 
29107    return frames;
29108 }
29109 #endif
29110 
29111 #ifdef HAVE_DSP_FILTER
audio_driver_dsp_filter_free(void)29112 void audio_driver_dsp_filter_free(void)
29113 {
29114    struct rarch_state *p_rarch = &rarch_st;
29115    if (p_rarch->audio_driver_dsp)
29116       retro_dsp_filter_free(p_rarch->audio_driver_dsp);
29117    p_rarch->audio_driver_dsp = NULL;
29118 }
29119 
audio_driver_dsp_filter_init(const char * device)29120 bool audio_driver_dsp_filter_init(const char *device)
29121 {
29122    retro_dsp_filter_t *audio_driver_dsp = NULL;
29123    struct rarch_state *p_rarch          = &rarch_st;
29124    struct string_list *plugs            = NULL;
29125 #if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
29126    char basedir[PATH_MAX_LENGTH];
29127    char ext_name[PATH_MAX_LENGTH];
29128 
29129    basedir[0] = ext_name[0]             = '\0';
29130 
29131    fill_pathname_basedir(basedir, device, sizeof(basedir));
29132 
29133    if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
29134       return false;
29135 
29136    plugs = dir_list_new(basedir, ext_name, false, true, false, false);
29137    if (!plugs)
29138       return false;
29139 #endif
29140    audio_driver_dsp = retro_dsp_filter_new(
29141          device, plugs, p_rarch->audio_driver_input);
29142    if (!audio_driver_dsp)
29143       return false;
29144 
29145    p_rarch->audio_driver_dsp = audio_driver_dsp;
29146 
29147    return true;
29148 }
29149 #endif
29150 
audio_driver_set_buffer_size(size_t bufsize)29151 void audio_driver_set_buffer_size(size_t bufsize)
29152 {
29153    struct rarch_state *p_rarch       = &rarch_st;
29154    p_rarch->audio_driver_buffer_size = bufsize;
29155 }
29156 
audio_driver_monitor_adjust_system_rates(double input_sample_rate,double input_fps,float video_refresh_rate,unsigned video_swap_interval,float audio_max_timing_skew)29157 static float audio_driver_monitor_adjust_system_rates(
29158       double input_sample_rate,
29159       double input_fps,
29160       float video_refresh_rate,
29161       unsigned video_swap_interval,
29162       float audio_max_timing_skew)
29163 {
29164    float inp_sample_rate                  = input_sample_rate;
29165    const float target_video_sync_rate     = video_refresh_rate
29166    / video_swap_interval;
29167    float timing_skew                      =
29168       fabs(1.0f - input_fps / target_video_sync_rate);
29169    if (timing_skew <= audio_max_timing_skew)
29170       return (inp_sample_rate * target_video_sync_rate / input_fps);
29171    return inp_sample_rate;
29172 }
29173 
29174 #ifdef HAVE_REWIND
audio_driver_setup_rewind(void)29175 void audio_driver_setup_rewind(void)
29176 {
29177    unsigned i;
29178    struct rarch_state *p_rarch      = &rarch_st;
29179 
29180    /* Push audio ready to be played. */
29181    p_rarch->audio_driver_rewind_ptr = p_rarch->audio_driver_rewind_size;
29182 
29183    for (i = 0; i < p_rarch->audio_driver_data_ptr; i += 2)
29184    {
29185       if (p_rarch->audio_driver_rewind_ptr > 0)
29186          p_rarch->audio_driver_rewind_buf[
29187             --p_rarch->audio_driver_rewind_ptr] =
29188             p_rarch->audio_driver_output_samples_conv_buf[i + 1];
29189 
29190       if (p_rarch->audio_driver_rewind_ptr > 0)
29191          p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] =
29192             p_rarch->audio_driver_output_samples_conv_buf[i + 0];
29193    }
29194 
29195    p_rarch->audio_driver_data_ptr = 0;
29196 }
29197 #endif
29198 
29199 
audio_driver_get_devices_list(void ** data)29200 bool audio_driver_get_devices_list(void **data)
29201 {
29202    struct rarch_state *p_rarch = &rarch_st;
29203    struct string_list**ptr     = (struct string_list**)data;
29204    if (!ptr)
29205       return false;
29206    *ptr = p_rarch->audio_driver_devices_list;
29207    return true;
29208 }
29209 
29210 #ifdef HAVE_AUDIOMIXER
audio_driver_mixer_extension_supported(const char * ext)29211 bool audio_driver_mixer_extension_supported(const char *ext)
29212 {
29213    unsigned i;
29214    struct string_list str_list;
29215    union string_list_elem_attr attr;
29216    bool ret                      = false;
29217 
29218    attr.i = 0;
29219    if (!string_list_initialize(&str_list))
29220       return false;
29221 
29222 #ifdef HAVE_STB_VORBIS
29223    string_list_append(&str_list, "ogg", attr);
29224 #endif
29225 #ifdef HAVE_IBXM
29226    string_list_append(&str_list, "mod", attr);
29227    string_list_append(&str_list, "s3m", attr);
29228    string_list_append(&str_list, "xm", attr);
29229 #endif
29230 #ifdef HAVE_DR_FLAC
29231    string_list_append(&str_list, "flac", attr);
29232 #endif
29233 #ifdef HAVE_DR_MP3
29234    string_list_append(&str_list, "mp3", attr);
29235 #endif
29236    string_list_append(&str_list, "wav", attr);
29237 
29238    for (i = 0; i < str_list.size; i++)
29239    {
29240       const char *str_ext = str_list.elems[i].data;
29241       if (string_is_equal_noncase(str_ext, ext))
29242       {
29243          ret = true;
29244          break;
29245       }
29246    }
29247 
29248    string_list_deinitialize(&str_list);
29249 
29250    return ret;
29251 }
29252 
audio_mixer_find_index(struct rarch_state * p_rarch,audio_mixer_sound_t * sound)29253 static int audio_mixer_find_index(
29254       struct rarch_state *p_rarch,
29255       audio_mixer_sound_t *sound)
29256 {
29257    unsigned i;
29258 
29259    for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
29260    {
29261       audio_mixer_sound_t *handle = p_rarch->audio_mixer_streams[i].handle;
29262       if (handle == sound)
29263          return i;
29264    }
29265    return -1;
29266 }
29267 
audio_mixer_play_stop_cb(audio_mixer_sound_t * sound,unsigned reason)29268 static void audio_mixer_play_stop_cb(
29269       audio_mixer_sound_t *sound, unsigned reason)
29270 {
29271    struct rarch_state *p_rarch = &rarch_st;
29272    int                     idx = audio_mixer_find_index(p_rarch, sound);
29273 
29274    switch (reason)
29275    {
29276       case AUDIO_MIXER_SOUND_FINISHED:
29277          audio_mixer_destroy(sound);
29278 
29279          if (idx >= 0)
29280          {
29281             unsigned i = (unsigned)idx;
29282 
29283             if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
29284                free(p_rarch->audio_mixer_streams[i].name);
29285 
29286             p_rarch->audio_mixer_streams[i].name    = NULL;
29287             p_rarch->audio_mixer_streams[i].state   = AUDIO_STREAM_STATE_NONE;
29288             p_rarch->audio_mixer_streams[i].volume  = 0.0f;
29289             p_rarch->audio_mixer_streams[i].buf     = NULL;
29290             p_rarch->audio_mixer_streams[i].stop_cb = NULL;
29291             p_rarch->audio_mixer_streams[i].handle  = NULL;
29292             p_rarch->audio_mixer_streams[i].voice   = NULL;
29293          }
29294          break;
29295       case AUDIO_MIXER_SOUND_STOPPED:
29296          break;
29297       case AUDIO_MIXER_SOUND_REPEATED:
29298          break;
29299    }
29300 }
29301 
audio_mixer_menu_stop_cb(audio_mixer_sound_t * sound,unsigned reason)29302 static void audio_mixer_menu_stop_cb(
29303       audio_mixer_sound_t *sound, unsigned reason)
29304 {
29305    struct rarch_state *p_rarch = &rarch_st;
29306    int                     idx = audio_mixer_find_index(p_rarch, sound);
29307 
29308    switch (reason)
29309    {
29310       case AUDIO_MIXER_SOUND_FINISHED:
29311          if (idx >= 0)
29312          {
29313             unsigned i                              = (unsigned)idx;
29314             p_rarch->audio_mixer_streams[i].state   = AUDIO_STREAM_STATE_STOPPED;
29315             p_rarch->audio_mixer_streams[i].volume  = 0.0f;
29316          }
29317          break;
29318       case AUDIO_MIXER_SOUND_STOPPED:
29319          break;
29320       case AUDIO_MIXER_SOUND_REPEATED:
29321          break;
29322    }
29323 }
29324 
audio_mixer_play_stop_sequential_cb(audio_mixer_sound_t * sound,unsigned reason)29325 static void audio_mixer_play_stop_sequential_cb(
29326       audio_mixer_sound_t *sound, unsigned reason)
29327 {
29328    struct rarch_state *p_rarch = &rarch_st;
29329    int                     idx = audio_mixer_find_index(p_rarch, sound);
29330 
29331    switch (reason)
29332    {
29333       case AUDIO_MIXER_SOUND_FINISHED:
29334          audio_mixer_destroy(sound);
29335 
29336          if (idx >= 0)
29337          {
29338             unsigned i = (unsigned)idx;
29339 
29340             if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
29341                free(p_rarch->audio_mixer_streams[i].name);
29342 
29343             if (i < AUDIO_MIXER_MAX_STREAMS)
29344                p_rarch->audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER;
29345             else
29346                p_rarch->audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_SYSTEM;
29347 
29348             p_rarch->audio_mixer_streams[i].name           = NULL;
29349             p_rarch->audio_mixer_streams[i].state          = AUDIO_STREAM_STATE_NONE;
29350             p_rarch->audio_mixer_streams[i].volume         = 0.0f;
29351             p_rarch->audio_mixer_streams[i].buf            = NULL;
29352             p_rarch->audio_mixer_streams[i].stop_cb        = NULL;
29353             p_rarch->audio_mixer_streams[i].handle         = NULL;
29354             p_rarch->audio_mixer_streams[i].voice          = NULL;
29355 
29356             i++;
29357 
29358             for (; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
29359             {
29360                if (p_rarch->audio_mixer_streams[i].state
29361                      == AUDIO_STREAM_STATE_STOPPED)
29362                {
29363                   audio_driver_mixer_play_stream_sequential(i);
29364                   break;
29365                }
29366             }
29367          }
29368          break;
29369       case AUDIO_MIXER_SOUND_STOPPED:
29370          break;
29371       case AUDIO_MIXER_SOUND_REPEATED:
29372          break;
29373    }
29374 }
29375 
audio_driver_mixer_get_free_stream_slot(unsigned * id,enum audio_mixer_stream_type type)29376 static bool audio_driver_mixer_get_free_stream_slot(
29377       unsigned *id, enum audio_mixer_stream_type type)
29378 {
29379    unsigned                  i = AUDIO_MIXER_MAX_STREAMS;
29380    unsigned              count = AUDIO_MIXER_MAX_SYSTEM_STREAMS;
29381    struct rarch_state *p_rarch = &rarch_st;
29382 
29383    if (type == AUDIO_STREAM_TYPE_USER)
29384    {
29385       i     = 0;
29386       count = AUDIO_MIXER_MAX_STREAMS;
29387    }
29388 
29389    for (; i < count; i++)
29390    {
29391       if (p_rarch->audio_mixer_streams[i].state == AUDIO_STREAM_STATE_NONE)
29392       {
29393          *id = i;
29394          return true;
29395       }
29396    }
29397 
29398    return false;
29399 }
29400 
audio_driver_mixer_add_stream(audio_mixer_stream_params_t * params)29401 bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params)
29402 {
29403    struct rarch_state *p_rarch   = &rarch_st;
29404    unsigned free_slot            = 0;
29405    audio_mixer_voice_t *voice    = NULL;
29406    audio_mixer_sound_t *handle   = NULL;
29407    audio_mixer_stop_cb_t stop_cb = audio_mixer_play_stop_cb;
29408    bool looped                   = false;
29409    void *buf                     = NULL;
29410 
29411    if (params->stream_type == AUDIO_STREAM_TYPE_NONE)
29412       return false;
29413 
29414    switch (params->slot_selection_type)
29415    {
29416       case AUDIO_MIXER_SLOT_SELECTION_MANUAL:
29417          free_slot = params->slot_selection_idx;
29418          break;
29419       case AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC:
29420       default:
29421          if (!audio_driver_mixer_get_free_stream_slot(
29422                   &free_slot, params->stream_type))
29423             return false;
29424          break;
29425    }
29426 
29427    if (params->state == AUDIO_STREAM_STATE_NONE)
29428       return false;
29429 
29430    buf = malloc(params->bufsize);
29431 
29432    if (!buf)
29433       return false;
29434 
29435    memcpy(buf, params->buf, params->bufsize);
29436 
29437    switch (params->type)
29438    {
29439       case AUDIO_MIXER_TYPE_WAV:
29440          handle = audio_mixer_load_wav(buf, (int32_t)params->bufsize);
29441          /* WAV is a special case - input buffer is not
29442           * free()'d when sound playback is complete (it is
29443           * converted to a PCM buffer, which is free()'d instead),
29444           * so have to do it here */
29445          free(buf);
29446          buf = NULL;
29447          break;
29448       case AUDIO_MIXER_TYPE_OGG:
29449          handle = audio_mixer_load_ogg(buf, (int32_t)params->bufsize);
29450          break;
29451       case AUDIO_MIXER_TYPE_MOD:
29452          handle = audio_mixer_load_mod(buf, (int32_t)params->bufsize);
29453          break;
29454       case AUDIO_MIXER_TYPE_FLAC:
29455 #ifdef HAVE_DR_FLAC
29456          handle = audio_mixer_load_flac(buf, (int32_t)params->bufsize);
29457 #endif
29458          break;
29459       case AUDIO_MIXER_TYPE_MP3:
29460 #ifdef HAVE_DR_MP3
29461          handle = audio_mixer_load_mp3(buf, (int32_t)params->bufsize);
29462 #endif
29463          break;
29464       case AUDIO_MIXER_TYPE_NONE:
29465          break;
29466    }
29467 
29468    if (!handle)
29469    {
29470       free(buf);
29471       return false;
29472    }
29473 
29474    switch (params->state)
29475    {
29476       case AUDIO_STREAM_STATE_PLAYING_LOOPED:
29477          looped = true;
29478          voice = audio_mixer_play(handle, looped, params->volume, stop_cb);
29479          break;
29480       case AUDIO_STREAM_STATE_PLAYING:
29481          voice = audio_mixer_play(handle, looped, params->volume, stop_cb);
29482          break;
29483       case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
29484          stop_cb = audio_mixer_play_stop_sequential_cb;
29485          voice = audio_mixer_play(handle, looped, params->volume, stop_cb);
29486          break;
29487       default:
29488          break;
29489    }
29490 
29491    p_rarch->audio_mixer_active                         = true;
29492 
29493    p_rarch->audio_mixer_streams[free_slot].name        =
29494       !string_is_empty(params->basename) ? strdup(params->basename) : NULL;
29495    p_rarch->audio_mixer_streams[free_slot].buf         = buf;
29496    p_rarch->audio_mixer_streams[free_slot].handle      = handle;
29497    p_rarch->audio_mixer_streams[free_slot].voice       = voice;
29498    p_rarch->audio_mixer_streams[free_slot].stream_type = params->stream_type;
29499    p_rarch->audio_mixer_streams[free_slot].type        = params->type;
29500    p_rarch->audio_mixer_streams[free_slot].state       = params->state;
29501    p_rarch->audio_mixer_streams[free_slot].volume      = params->volume;
29502    p_rarch->audio_mixer_streams[free_slot].stop_cb     = stop_cb;
29503 
29504    return true;
29505 }
29506 
audio_driver_mixer_get_stream_state(unsigned i)29507 enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i)
29508 {
29509    struct rarch_state *p_rarch = &rarch_st;
29510    if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
29511       return AUDIO_STREAM_STATE_NONE;
29512 
29513    return p_rarch->audio_mixer_streams[i].state;
29514 }
29515 
audio_driver_mixer_play_stream_internal(struct rarch_state * p_rarch,unsigned i,unsigned type)29516 static void audio_driver_mixer_play_stream_internal(
29517       struct rarch_state *p_rarch,
29518       unsigned i, unsigned type)
29519 {
29520    if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
29521       return;
29522 
29523    switch (p_rarch->audio_mixer_streams[i].state)
29524    {
29525       case AUDIO_STREAM_STATE_STOPPED:
29526          p_rarch->audio_mixer_streams[i].voice =
29527             audio_mixer_play(p_rarch->audio_mixer_streams[i].handle,
29528                (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false,
29529                1.0f, p_rarch->audio_mixer_streams[i].stop_cb);
29530          p_rarch->audio_mixer_streams[i].state = (enum audio_mixer_state)type;
29531          break;
29532       case AUDIO_STREAM_STATE_PLAYING:
29533       case AUDIO_STREAM_STATE_PLAYING_LOOPED:
29534       case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
29535       case AUDIO_STREAM_STATE_NONE:
29536          break;
29537    }
29538 }
29539 
audio_driver_load_menu_bgm_callback(retro_task_t * task,void * task_data,void * user_data,const char * error)29540 static void audio_driver_load_menu_bgm_callback(retro_task_t *task,
29541       void *task_data, void *user_data, const char *error)
29542 {
29543    bool contentless = false;
29544    bool is_inited   = false;
29545 
29546    content_get_status(&contentless, &is_inited);
29547 
29548    if (!is_inited)
29549       audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
29550 }
29551 
audio_driver_load_system_sounds(void)29552 void audio_driver_load_system_sounds(void)
29553 {
29554    char sounds_path[PATH_MAX_LENGTH];
29555    char sounds_fallback_path[PATH_MAX_LENGTH];
29556    char basename_noext[PATH_MAX_LENGTH];
29557    struct rarch_state *p_rarch           = &rarch_st;
29558    settings_t *settings                  = p_rarch->configuration_settings;
29559    const char *dir_assets                = settings->paths.directory_assets;
29560    const bool audio_enable_menu          = settings->bools.audio_enable_menu;
29561    const bool audio_enable_menu_ok       = audio_enable_menu && settings->bools.audio_enable_menu_ok;
29562    const bool audio_enable_menu_cancel   = audio_enable_menu && settings->bools.audio_enable_menu_cancel;
29563    const bool audio_enable_menu_notice   = audio_enable_menu && settings->bools.audio_enable_menu_notice;
29564    const bool audio_enable_menu_bgm      = audio_enable_menu && settings->bools.audio_enable_menu_bgm;
29565    const bool audio_enable_cheevo_unlock = settings->bools.cheevos_unlock_sound_enable;
29566    const char *path_ok                   = NULL;
29567    const char *path_cancel               = NULL;
29568    const char *path_notice               = NULL;
29569    const char *path_bgm                  = NULL;
29570    const char *path_cheevo_unlock        = NULL;
29571    struct string_list *list              = NULL;
29572    struct string_list *list_fallback     = NULL;
29573    unsigned i                            = 0;
29574 
29575    if (!audio_enable_menu && !audio_enable_cheevo_unlock)
29576       goto end;
29577 
29578    sounds_path[0] = sounds_fallback_path[0] =
29579                           basename_noext[0] ='\0';
29580 
29581    fill_pathname_join(
29582          sounds_fallback_path,
29583          dir_assets,
29584          "sounds",
29585          sizeof(sounds_fallback_path));
29586 
29587    fill_pathname_application_special(
29588          sounds_path,
29589          sizeof(sounds_path),
29590          APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS);
29591 
29592    list          = dir_list_new(sounds_path, MENU_SOUND_FORMATS, false, false, false, false);
29593    list_fallback = dir_list_new(sounds_fallback_path, MENU_SOUND_FORMATS, false, false, false, false);
29594 
29595    if (!list)
29596    {
29597       list          = list_fallback;
29598       list_fallback = NULL;
29599    }
29600 
29601    if (!list || list->size == 0)
29602       goto end;
29603 
29604    if (list_fallback && list_fallback->size > 0)
29605    {
29606       for (i = 0; i < list_fallback->size; i++)
29607       {
29608          if (list->size == 0 || !string_list_find_elem(list, list_fallback->elems[i].data))
29609          {
29610             union string_list_elem_attr attr = {0};
29611             string_list_append(list, list_fallback->elems[i].data, attr);
29612          }
29613       }
29614    }
29615 
29616    for (i = 0; i < list->size; i++)
29617    {
29618       const char *path = list->elems[i].data;
29619       const char *ext  = path_get_extension(path);
29620 
29621       if (audio_driver_mixer_extension_supported(ext))
29622       {
29623          basename_noext[0] = '\0';
29624          fill_pathname_base_noext(basename_noext, path, sizeof(basename_noext));
29625 
29626          if (string_is_equal_noncase(basename_noext, "ok"))
29627             path_ok = path;
29628          else if (string_is_equal_noncase(basename_noext, "cancel"))
29629             path_cancel = path;
29630          else if (string_is_equal_noncase(basename_noext, "notice"))
29631             path_notice = path;
29632          else if (string_is_equal_noncase(basename_noext, "bgm"))
29633             path_bgm = path;
29634          else if (string_is_equal_noncase(basename_noext, "unlock"))
29635             path_cheevo_unlock = path;
29636       }
29637    }
29638 
29639    if (path_ok && audio_enable_menu_ok)
29640       task_push_audio_mixer_load(path_ok, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_OK);
29641    if (path_cancel && audio_enable_menu_cancel)
29642       task_push_audio_mixer_load(path_cancel, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_CANCEL);
29643    if (path_notice && audio_enable_menu_notice)
29644       task_push_audio_mixer_load(path_notice, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_NOTICE);
29645    if (path_bgm && audio_enable_menu_bgm)
29646       task_push_audio_mixer_load(path_bgm, audio_driver_load_menu_bgm_callback, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_BGM);
29647    if (path_cheevo_unlock && audio_enable_cheevo_unlock)
29648       task_push_audio_mixer_load(path_cheevo_unlock, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_ACHIEVEMENT_UNLOCK);
29649 
29650 end:
29651    if (list)
29652       string_list_free(list);
29653    if (list_fallback)
29654       string_list_free(list_fallback);
29655 }
29656 
audio_driver_mixer_play_stream(unsigned i)29657 void audio_driver_mixer_play_stream(unsigned i)
29658 {
29659    struct rarch_state *p_rarch = &rarch_st;
29660    p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
29661    audio_driver_mixer_play_stream_internal(p_rarch,
29662          i, AUDIO_STREAM_STATE_PLAYING);
29663 }
29664 
audio_driver_mixer_play_menu_sound_looped(unsigned i)29665 void audio_driver_mixer_play_menu_sound_looped(unsigned i)
29666 {
29667    struct rarch_state *p_rarch = &rarch_st;
29668    p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
29669    audio_driver_mixer_play_stream_internal(p_rarch,
29670          i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
29671 }
29672 
audio_driver_mixer_play_menu_sound(unsigned i)29673 void audio_driver_mixer_play_menu_sound(unsigned i)
29674 {
29675    struct rarch_state *p_rarch = &rarch_st;
29676    p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
29677    audio_driver_mixer_play_stream_internal(p_rarch,
29678          i, AUDIO_STREAM_STATE_PLAYING);
29679 }
29680 
audio_driver_mixer_play_stream_looped(unsigned i)29681 void audio_driver_mixer_play_stream_looped(unsigned i)
29682 {
29683    struct rarch_state *p_rarch = &rarch_st;
29684    p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
29685    audio_driver_mixer_play_stream_internal(p_rarch,
29686          i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
29687 }
29688 
audio_driver_mixer_play_stream_sequential(unsigned i)29689 void audio_driver_mixer_play_stream_sequential(unsigned i)
29690 {
29691    struct rarch_state *p_rarch = &rarch_st;
29692    p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_sequential_cb;
29693    audio_driver_mixer_play_stream_internal(p_rarch,
29694          i, AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL);
29695 }
29696 
audio_driver_mixer_get_stream_volume(unsigned i)29697 float audio_driver_mixer_get_stream_volume(unsigned i)
29698 {
29699    struct rarch_state *p_rarch = &rarch_st;
29700    if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
29701       return 0.0f;
29702 
29703    return p_rarch->audio_mixer_streams[i].volume;
29704 }
29705 
audio_driver_mixer_set_stream_volume(unsigned i,float vol)29706 void audio_driver_mixer_set_stream_volume(unsigned i, float vol)
29707 {
29708    audio_mixer_voice_t *voice             = NULL;
29709    struct rarch_state *p_rarch            = &rarch_st;
29710 
29711    if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
29712       return;
29713 
29714    p_rarch->audio_mixer_streams[i].volume = vol;
29715 
29716    voice                                  =
29717       p_rarch->audio_mixer_streams[i].voice;
29718 
29719    if (voice)
29720       audio_mixer_voice_set_volume(voice, DB_TO_GAIN(vol));
29721 }
29722 
audio_driver_mixer_stop_stream(unsigned i)29723 void audio_driver_mixer_stop_stream(unsigned i)
29724 {
29725    bool set_state                         = false;
29726    struct rarch_state *p_rarch            = &rarch_st;
29727 
29728    if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
29729       return;
29730 
29731    switch (p_rarch->audio_mixer_streams[i].state)
29732    {
29733       case AUDIO_STREAM_STATE_PLAYING:
29734       case AUDIO_STREAM_STATE_PLAYING_LOOPED:
29735       case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
29736          set_state = true;
29737          break;
29738       case AUDIO_STREAM_STATE_STOPPED:
29739       case AUDIO_STREAM_STATE_NONE:
29740          break;
29741    }
29742 
29743    if (set_state)
29744    {
29745       audio_mixer_voice_t *voice     = p_rarch->audio_mixer_streams[i].voice;
29746 
29747       if (voice)
29748          audio_mixer_stop(voice);
29749       p_rarch->audio_mixer_streams[i].state   = AUDIO_STREAM_STATE_STOPPED;
29750       p_rarch->audio_mixer_streams[i].volume  = 1.0f;
29751    }
29752 }
29753 
audio_driver_mixer_remove_stream(unsigned i)29754 void audio_driver_mixer_remove_stream(unsigned i)
29755 {
29756    bool destroy                = false;
29757    struct rarch_state *p_rarch = &rarch_st;
29758 
29759    if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
29760       return;
29761 
29762    switch (p_rarch->audio_mixer_streams[i].state)
29763    {
29764       case AUDIO_STREAM_STATE_PLAYING:
29765       case AUDIO_STREAM_STATE_PLAYING_LOOPED:
29766       case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
29767          audio_driver_mixer_stop_stream(i);
29768          destroy = true;
29769          break;
29770       case AUDIO_STREAM_STATE_STOPPED:
29771          destroy = true;
29772          break;
29773       case AUDIO_STREAM_STATE_NONE:
29774          break;
29775    }
29776 
29777    if (destroy)
29778    {
29779       audio_mixer_sound_t *handle = p_rarch->audio_mixer_streams[i].handle;
29780       if (handle)
29781          audio_mixer_destroy(handle);
29782 
29783       if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
29784          free(p_rarch->audio_mixer_streams[i].name);
29785 
29786       p_rarch->audio_mixer_streams[i].state   = AUDIO_STREAM_STATE_NONE;
29787       p_rarch->audio_mixer_streams[i].stop_cb = NULL;
29788       p_rarch->audio_mixer_streams[i].volume  = 0.0f;
29789       p_rarch->audio_mixer_streams[i].handle  = NULL;
29790       p_rarch->audio_mixer_streams[i].voice   = NULL;
29791       p_rarch->audio_mixer_streams[i].name    = NULL;
29792    }
29793 }
29794 #endif
29795 
audio_driver_enable_callback(void)29796 bool audio_driver_enable_callback(void)
29797 {
29798    struct rarch_state *p_rarch = &rarch_st;
29799    if (!p_rarch->audio_callback.callback)
29800       return false;
29801    if (p_rarch->audio_callback.set_state)
29802       p_rarch->audio_callback.set_state(true);
29803    return true;
29804 }
29805 
audio_driver_disable_callback(void)29806 bool audio_driver_disable_callback(void)
29807 {
29808    struct rarch_state *p_rarch = &rarch_st;
29809    if (!p_rarch->audio_callback.callback)
29810       return false;
29811 
29812    if (p_rarch->audio_callback.set_state)
29813       p_rarch->audio_callback.set_state(false);
29814    return true;
29815 }
29816 
audio_driver_callback(void)29817 bool audio_driver_callback(void)
29818 {
29819    struct rarch_state *p_rarch = &rarch_st;
29820    settings_t *settings        = p_rarch->configuration_settings;
29821 #ifdef HAVE_MENU
29822    bool core_paused            = runloop_state.paused || (settings->bools.menu_pause_libretro && p_rarch->menu_driver_alive);
29823 #else
29824    bool core_paused            = runloop_state.paused;
29825 #endif
29826 
29827    if (!p_rarch->audio_callback.callback)
29828       return false;
29829 
29830    if (!core_paused && p_rarch->audio_callback.callback)
29831       p_rarch->audio_callback.callback();
29832 
29833    return true;
29834 }
29835 
audio_driver_has_callback(void)29836 bool audio_driver_has_callback(void)
29837 {
29838    struct rarch_state *p_rarch = &rarch_st;
29839    if (p_rarch->audio_callback.callback)
29840 	   return true;
29841    return false;
29842 }
29843 
29844 #ifdef HAVE_AUDIOMIXER
audio_driver_mixer_toggle_mute(void)29845 bool audio_driver_mixer_toggle_mute(void)
29846 {
29847    struct rarch_state *p_rarch = &rarch_st;
29848    p_rarch->audio_driver_mixer_mute_enable  =
29849       !p_rarch->audio_driver_mixer_mute_enable;
29850    return true;
29851 }
29852 #endif
29853 
audio_driver_alive(struct rarch_state * p_rarch)29854 static INLINE bool audio_driver_alive(struct rarch_state *p_rarch)
29855 {
29856    if (     p_rarch->current_audio
29857          && p_rarch->current_audio->alive
29858          && p_rarch->audio_driver_context_audio_data)
29859       return p_rarch->current_audio->alive(p_rarch->audio_driver_context_audio_data);
29860    return false;
29861 }
29862 
audio_driver_start(struct rarch_state * p_rarch,bool is_shutdown)29863 static bool audio_driver_start(struct rarch_state *p_rarch,
29864       bool is_shutdown)
29865 {
29866    if (!p_rarch->current_audio || !p_rarch->current_audio->start
29867          || !p_rarch->audio_driver_context_audio_data)
29868       goto error;
29869    if (!p_rarch->current_audio->start(
29870             p_rarch->audio_driver_context_audio_data, is_shutdown))
29871       goto error;
29872 
29873    return true;
29874 
29875 error:
29876    RARCH_ERR("%s\n",
29877          msg_hash_to_str(MSG_FAILED_TO_START_AUDIO_DRIVER));
29878    p_rarch->audio_driver_active = false;
29879    return false;
29880 }
29881 
audio_driver_stop(struct rarch_state * p_rarch)29882 static bool audio_driver_stop(struct rarch_state *p_rarch)
29883 {
29884    if (     !p_rarch->current_audio
29885          || !p_rarch->current_audio->stop
29886          || !p_rarch->audio_driver_context_audio_data
29887          || !audio_driver_alive(p_rarch)
29888       )
29889       return false;
29890    return p_rarch->current_audio->stop(
29891          p_rarch->audio_driver_context_audio_data);
29892 }
29893 
29894 #ifdef HAVE_REWIND
audio_driver_frame_is_reverse(void)29895 void audio_driver_frame_is_reverse(void)
29896 {
29897    struct rarch_state            *p_rarch = &rarch_st;
29898    /* We just rewound. Flush rewind audio buffer. */
29899    if (  p_rarch->recording_data   &&
29900          p_rarch->recording_driver &&
29901          p_rarch->recording_driver->push_audio)
29902    {
29903       struct record_audio_data ffemu_data;
29904 
29905       ffemu_data.data                    = p_rarch->audio_driver_rewind_buf +
29906          p_rarch->audio_driver_rewind_ptr;
29907       ffemu_data.frames                  = (p_rarch->audio_driver_rewind_size -
29908             p_rarch->audio_driver_rewind_ptr) / 2;
29909 
29910       p_rarch->recording_driver->push_audio(p_rarch->recording_data, &ffemu_data);
29911    }
29912 
29913    if (!(
29914           runloop_state.paused          ||
29915          !p_rarch->audio_driver_active     ||
29916          !p_rarch->audio_driver_output_samples_buf))
29917       audio_driver_flush(
29918             p_rarch,
29919             p_rarch->configuration_settings->floats.slowmotion_ratio,
29920             p_rarch->configuration_settings->bools.audio_fastforward_mute,
29921             p_rarch->audio_driver_rewind_buf  +
29922             p_rarch->audio_driver_rewind_ptr,
29923             p_rarch->audio_driver_rewind_size -
29924             p_rarch->audio_driver_rewind_ptr,
29925             runloop_state.slowmotion,
29926             runloop_state.fastmotion);
29927 }
29928 #endif
29929 
audio_set_float(enum audio_action action,float val)29930 void audio_set_float(enum audio_action action, float val)
29931 {
29932    struct rarch_state *p_rarch                    = &rarch_st;
29933 
29934    switch (action)
29935    {
29936       case AUDIO_ACTION_VOLUME_GAIN:
29937          p_rarch->audio_driver_volume_gain        = DB_TO_GAIN(val);
29938          break;
29939       case AUDIO_ACTION_MIXER_VOLUME_GAIN:
29940 #ifdef HAVE_AUDIOMIXER
29941          p_rarch->audio_driver_mixer_volume_gain  = DB_TO_GAIN(val);
29942 #endif
29943          break;
29944       case AUDIO_ACTION_RATE_CONTROL_DELTA:
29945          p_rarch->audio_driver_rate_control_delta = val;
29946          break;
29947       case AUDIO_ACTION_NONE:
29948       default:
29949          break;
29950    }
29951 }
29952 
audio_get_float_ptr(enum audio_action action)29953 float *audio_get_float_ptr(enum audio_action action)
29954 {
29955    struct rarch_state *p_rarch     = &rarch_st;
29956 
29957    switch (action)
29958    {
29959       case AUDIO_ACTION_RATE_CONTROL_DELTA:
29960          return &p_rarch->audio_driver_rate_control_delta;
29961       case AUDIO_ACTION_NONE:
29962       default:
29963          break;
29964    }
29965 
29966    return NULL;
29967 }
29968 
audio_get_bool_ptr(enum audio_action action)29969 bool *audio_get_bool_ptr(enum audio_action action)
29970 {
29971    struct rarch_state *p_rarch = &rarch_st;
29972 
29973    switch (action)
29974    {
29975       case AUDIO_ACTION_MIXER_MUTE_ENABLE:
29976 #ifdef HAVE_AUDIOMIXER
29977          return &p_rarch->audio_driver_mixer_mute_enable;
29978 #else
29979          break;
29980 #endif
29981       case AUDIO_ACTION_MUTE_ENABLE:
29982          return &p_rarch->audio_driver_mute_enable;
29983       case AUDIO_ACTION_NONE:
29984       default:
29985          break;
29986    }
29987 
29988    return NULL;
29989 }
29990 
29991 /* VIDEO */
video_display_server_get_ident(void)29992 const char *video_display_server_get_ident(void)
29993 {
29994    if (!current_display_server)
29995       return FILE_PATH_UNKNOWN;
29996    return current_display_server->ident;
29997 }
29998 
video_display_server_init(enum rarch_display_type type)29999 void* video_display_server_init(enum rarch_display_type type)
30000 {
30001    struct rarch_state            *p_rarch = &rarch_st;
30002 
30003    video_display_server_destroy();
30004 
30005    switch (type)
30006    {
30007       case RARCH_DISPLAY_WIN32:
30008 #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
30009          current_display_server = &dispserv_win32;
30010 #endif
30011          break;
30012       case RARCH_DISPLAY_X11:
30013 #if defined(HAVE_X11)
30014          current_display_server = &dispserv_x11;
30015 #endif
30016          break;
30017       default:
30018 #if defined(ANDROID)
30019          current_display_server = &dispserv_android;
30020 #else
30021          current_display_server = &dispserv_null;
30022 #endif
30023          break;
30024    }
30025 
30026    if (current_display_server)
30027    {
30028       if (current_display_server->init)
30029          p_rarch->current_display_server_data = current_display_server->init();
30030 
30031       if (!string_is_empty(current_display_server->ident))
30032       {
30033          RARCH_LOG("[Video]: Found display server: %s\n",
30034                current_display_server->ident);
30035       }
30036    }
30037 
30038    p_rarch->initial_screen_orientation =
30039       video_display_server_get_screen_orientation();
30040    p_rarch->current_screen_orientation =
30041       p_rarch->initial_screen_orientation;
30042 
30043    return p_rarch->current_display_server_data;
30044 }
30045 
video_display_server_destroy(void)30046 void video_display_server_destroy(void)
30047 {
30048    struct rarch_state                    *p_rarch = &rarch_st;
30049    const enum rotation initial_screen_orientation = p_rarch->initial_screen_orientation;
30050    const enum rotation current_screen_orientation = p_rarch->current_screen_orientation;
30051 
30052    if (initial_screen_orientation != current_screen_orientation)
30053       video_display_server_set_screen_orientation(initial_screen_orientation);
30054 
30055    if (current_display_server)
30056       if (p_rarch->current_display_server_data)
30057          current_display_server->destroy(p_rarch->current_display_server_data);
30058 }
30059 
video_display_server_set_window_opacity(unsigned opacity)30060 bool video_display_server_set_window_opacity(unsigned opacity)
30061 {
30062    struct rarch_state *p_rarch = &rarch_st;
30063    if (current_display_server && current_display_server->set_window_opacity)
30064       return current_display_server->set_window_opacity(
30065             p_rarch->current_display_server_data, opacity);
30066    return false;
30067 }
30068 
video_display_server_set_window_progress(int progress,bool finished)30069 bool video_display_server_set_window_progress(int progress, bool finished)
30070 {
30071    struct rarch_state *p_rarch = &rarch_st;
30072    if (current_display_server && current_display_server->set_window_progress)
30073       return current_display_server->set_window_progress(
30074             p_rarch->current_display_server_data, progress, finished);
30075    return false;
30076 }
30077 
video_display_server_set_window_decorations(bool on)30078 bool video_display_server_set_window_decorations(bool on)
30079 {
30080    struct rarch_state *p_rarch = &rarch_st;
30081    if (current_display_server && current_display_server->set_window_decorations)
30082       return current_display_server->set_window_decorations(
30083             p_rarch->current_display_server_data, on);
30084    return false;
30085 }
30086 
video_display_server_set_resolution(unsigned width,unsigned height,int int_hz,float hz,int center,int monitor_index,int xoffset,int padjust)30087 bool video_display_server_set_resolution(unsigned width, unsigned height,
30088       int int_hz, float hz, int center, int monitor_index, int xoffset, int padjust)
30089 {
30090    struct rarch_state *p_rarch = &rarch_st;
30091    if (current_display_server && current_display_server->set_resolution)
30092       return current_display_server->set_resolution(
30093             p_rarch->current_display_server_data, width, height, int_hz,
30094             hz, center, monitor_index, xoffset, padjust);
30095    return false;
30096 }
30097 
video_display_server_has_resolution_list(void)30098 bool video_display_server_has_resolution_list(void)
30099 {
30100    return (current_display_server
30101          && current_display_server->get_resolution_list);
30102 }
30103 
video_display_server_get_resolution_list(unsigned * size)30104 void *video_display_server_get_resolution_list(unsigned *size)
30105 {
30106    struct rarch_state *p_rarch = &rarch_st;
30107    if (video_display_server_has_resolution_list())
30108       return current_display_server->get_resolution_list(
30109             p_rarch->current_display_server_data, size);
30110    return NULL;
30111 }
30112 
video_display_server_get_output_options(void)30113 const char *video_display_server_get_output_options(void)
30114 {
30115    struct rarch_state *p_rarch = &rarch_st;
30116    if (current_display_server && current_display_server->get_output_options)
30117       return current_display_server->get_output_options(p_rarch->current_display_server_data);
30118    return NULL;
30119 }
30120 
video_display_server_set_screen_orientation(enum rotation rotation)30121 void video_display_server_set_screen_orientation(enum rotation rotation)
30122 {
30123    if (current_display_server && current_display_server->set_screen_orientation)
30124    {
30125       struct rarch_state            *p_rarch = &rarch_st;
30126 
30127       RARCH_LOG("[Video]: Setting screen orientation to %d.\n", rotation);
30128       p_rarch->current_screen_orientation    = rotation;
30129       current_display_server->set_screen_orientation(p_rarch->current_display_server_data, rotation);
30130    }
30131 }
30132 
video_display_server_can_set_screen_orientation(void)30133 bool video_display_server_can_set_screen_orientation(void)
30134 {
30135    return (current_display_server && current_display_server->set_screen_orientation);
30136 }
30137 
video_display_server_get_screen_orientation(void)30138 enum rotation video_display_server_get_screen_orientation(void)
30139 {
30140    struct rarch_state *p_rarch = &rarch_st;
30141    if (current_display_server && current_display_server->get_screen_orientation)
30142       return current_display_server->get_screen_orientation(p_rarch->current_display_server_data);
30143    return ORIENTATION_NORMAL;
30144 }
30145 
video_display_server_get_flags(gfx_ctx_flags_t * flags)30146 bool video_display_server_get_flags(gfx_ctx_flags_t *flags)
30147 {
30148    struct rarch_state *p_rarch = &rarch_st;
30149    if (!flags || !current_display_server || !current_display_server->get_flags)
30150       return false;
30151    flags->flags = current_display_server->get_flags(
30152          p_rarch->current_display_server_data);
30153    return true;
30154 }
30155 
video_driver_started_fullscreen(void)30156 bool video_driver_started_fullscreen(void)
30157 {
30158    struct rarch_state *p_rarch = &rarch_st;
30159    return p_rarch->video_started_fullscreen;
30160 }
30161 
30162 /* Stub functions */
30163 
get_metrics_null(void * data,enum display_metric_types type,float * value)30164 static bool get_metrics_null(void *data, enum display_metric_types type,
30165       float *value) { return false; }
30166 
30167 /**
30168  * config_get_video_driver_options:
30169  *
30170  * Get an enumerated list of all video driver names, separated by '|'.
30171  *
30172  * Returns: string listing of all video driver names, separated by '|'.
30173  **/
config_get_video_driver_options(void)30174 const char* config_get_video_driver_options(void)
30175 {
30176    return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL);
30177 }
30178 
video_driver_is_threaded(void)30179 bool video_driver_is_threaded(void)
30180 {
30181 #ifdef HAVE_THREADS
30182    struct rarch_state *p_rarch = &rarch_st;
30183 #endif
30184    return VIDEO_DRIVER_IS_THREADED_INTERNAL();
30185 }
30186 
video_driver_get_threaded(void)30187 bool *video_driver_get_threaded(void)
30188 {
30189    struct rarch_state *p_rarch = &rarch_st;
30190 #if defined(__MACH__) && defined(__APPLE__)
30191    /* TODO/FIXME - force threaded video to disabled on Apple for now
30192     * until NSWindow/UIWindow concurrency issues are taken care of */
30193    p_rarch->video_driver_threaded = false;
30194 #endif
30195    return &p_rarch->video_driver_threaded;
30196 }
30197 
video_driver_set_threaded(bool val)30198 void video_driver_set_threaded(bool val)
30199 {
30200    struct rarch_state *p_rarch = &rarch_st;
30201 #if defined(__MACH__) && defined(__APPLE__)
30202    /* TODO/FIXME - force threaded video to disabled on Apple for now
30203     * until NSWindow/UIWindow concurrency issues are taken care of */
30204    p_rarch->video_driver_threaded = false;
30205 #else
30206    p_rarch->video_driver_threaded = val;
30207 #endif
30208 }
30209 
video_driver_get_ident(void)30210 const char *video_driver_get_ident(void)
30211 {
30212    struct rarch_state *p_rarch = &rarch_st;
30213    if (!p_rarch->current_video)
30214       return NULL;
30215 #ifdef HAVE_THREADS
30216    if (VIDEO_DRIVER_IS_THREADED_INTERNAL())
30217    {
30218       const thread_video_t *thr   = (const thread_video_t*)p_rarch->video_driver_data;
30219       if (!thr || !thr->driver)
30220          return NULL;
30221       return thr->driver->ident;
30222    }
30223 #endif
30224 
30225    return p_rarch->current_video->ident;
30226 }
30227 
video_context_driver_reset(void)30228 static void video_context_driver_reset(void)
30229 {
30230    struct rarch_state  *p_rarch   = &rarch_st;
30231 
30232    if (!p_rarch->current_video_context.get_metrics)
30233       p_rarch->current_video_context.get_metrics         = get_metrics_null;
30234 }
30235 
video_context_driver_set(const gfx_ctx_driver_t * data)30236 bool video_context_driver_set(const gfx_ctx_driver_t *data)
30237 {
30238    struct rarch_state     *p_rarch = &rarch_st;
30239 
30240    if (!data)
30241       return false;
30242    p_rarch->current_video_context = *data;
30243    video_context_driver_reset();
30244    return true;
30245 }
30246 
video_context_driver_destroy_internal(gfx_ctx_driver_t * ctx_driver)30247 static void video_context_driver_destroy_internal(
30248       gfx_ctx_driver_t *ctx_driver)
30249 {
30250    if (!ctx_driver)
30251       return;
30252 
30253    ctx_driver->init                       = NULL;
30254    ctx_driver->bind_api                   = NULL;
30255    ctx_driver->swap_interval              = NULL;
30256    ctx_driver->set_video_mode             = NULL;
30257    ctx_driver->get_video_size             = NULL;
30258    ctx_driver->get_video_output_size      = NULL;
30259    ctx_driver->get_video_output_prev      = NULL;
30260    ctx_driver->get_video_output_next      = NULL;
30261    ctx_driver->get_metrics                = get_metrics_null;
30262    ctx_driver->translate_aspect           = NULL;
30263    ctx_driver->update_window_title        = NULL;
30264    ctx_driver->check_window               = NULL;
30265    ctx_driver->set_resize                 = NULL;
30266    ctx_driver->suppress_screensaver       = NULL;
30267    ctx_driver->swap_buffers               = NULL;
30268    ctx_driver->input_driver               = NULL;
30269    ctx_driver->get_proc_address           = NULL;
30270    ctx_driver->image_buffer_init          = NULL;
30271    ctx_driver->image_buffer_write         = NULL;
30272    ctx_driver->show_mouse                 = NULL;
30273    ctx_driver->ident                      = NULL;
30274    ctx_driver->get_flags                  = NULL;
30275    ctx_driver->set_flags                  = NULL;
30276    ctx_driver->bind_hw_render             = NULL;
30277    ctx_driver->get_context_data           = NULL;
30278    ctx_driver->make_current               = NULL;
30279 }
30280 
video_context_driver_destroy(void)30281 void video_context_driver_destroy(void)
30282 {
30283    struct rarch_state     *p_rarch                           = &rarch_st;
30284    video_context_driver_destroy_internal(&p_rarch->current_video_context);
30285 }
30286 
30287 /**
30288  * video_driver_get_current_framebuffer:
30289  *
30290  * Gets pointer to current hardware renderer framebuffer object.
30291  * Used by RETRO_ENVIRONMENT_SET_HW_RENDER.
30292  *
30293  * Returns: pointer to hardware framebuffer object, otherwise 0.
30294  **/
video_driver_get_current_framebuffer(void)30295 static uintptr_t video_driver_get_current_framebuffer(void)
30296 {
30297    struct rarch_state          *p_rarch = &rarch_st;
30298    if (     p_rarch->video_driver_poke
30299          && p_rarch->video_driver_poke->get_current_framebuffer)
30300       return p_rarch->video_driver_poke->get_current_framebuffer(
30301             p_rarch->video_driver_data);
30302    return 0;
30303 }
30304 
video_driver_get_proc_address(const char * sym)30305 static retro_proc_address_t video_driver_get_proc_address(const char *sym)
30306 {
30307    struct rarch_state          *p_rarch = &rarch_st;
30308    if (     p_rarch->video_driver_poke
30309          && p_rarch->video_driver_poke->get_proc_address)
30310       return p_rarch->video_driver_poke->get_proc_address(
30311             p_rarch->video_driver_data, sym);
30312    return NULL;
30313 }
30314 
30315 #ifdef HAVE_VIDEO_FILTER
video_driver_filter_free(void)30316 static void video_driver_filter_free(void)
30317 {
30318    struct rarch_state          *p_rarch = &rarch_st;
30319 
30320    if (p_rarch->video_driver_state_filter)
30321       rarch_softfilter_free(p_rarch->video_driver_state_filter);
30322    p_rarch->video_driver_state_filter   = NULL;
30323 
30324    if (p_rarch->video_driver_state_buffer)
30325    {
30326 #ifdef _3DS
30327       linearFree(p_rarch->video_driver_state_buffer);
30328 #else
30329       free(p_rarch->video_driver_state_buffer);
30330 #endif
30331    }
30332    p_rarch->video_driver_state_buffer    = NULL;
30333 
30334    p_rarch->video_driver_state_scale     = 0;
30335    p_rarch->video_driver_state_out_bpp   = 0;
30336    p_rarch->video_driver_state_out_rgb32 = false;
30337 }
30338 #endif
30339 
30340 #ifdef HAVE_VIDEO_FILTER
video_driver_init_filter(enum retro_pixel_format colfmt_int,settings_t * settings)30341 static void video_driver_init_filter(enum retro_pixel_format colfmt_int,
30342       settings_t *settings)
30343 {
30344    unsigned pow2_x, pow2_y, maxsize;
30345    void *buf                            = NULL;
30346    struct rarch_state          *p_rarch = &rarch_st;
30347    struct retro_game_geometry *geom     = &p_rarch->video_driver_av_info.geometry;
30348    unsigned width                       = geom->max_width;
30349    unsigned height                      = geom->max_height;
30350    /* Deprecated format. Gets pre-converted. */
30351    enum retro_pixel_format colfmt       =
30352       (colfmt_int == RETRO_PIXEL_FORMAT_0RGB1555) ?
30353       RETRO_PIXEL_FORMAT_RGB565 : colfmt_int;
30354 
30355    if (video_driver_is_hw_context())
30356    {
30357       RARCH_WARN("[Video]: Cannot use CPU filters when hardware rendering is used.\n");
30358       return;
30359    }
30360 
30361    p_rarch->video_driver_state_filter   = rarch_softfilter_new(
30362          settings->paths.path_softfilter_plugin,
30363          RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height);
30364 
30365    if (!p_rarch->video_driver_state_filter)
30366    {
30367       RARCH_ERR("[Video]: Failed to load filter.\n");
30368       return;
30369    }
30370 
30371    rarch_softfilter_get_max_output_size(
30372          p_rarch->video_driver_state_filter,
30373          &width, &height);
30374 
30375    pow2_x                              = next_pow2(width);
30376    pow2_y                              = next_pow2(height);
30377    maxsize                             = MAX(pow2_x, pow2_y);
30378 
30379 #ifdef _3DS
30380    /* On 3DS, video is disabled if the output resolution
30381     * exceeds 2048x2048. To avoid the user being presented
30382     * with a black screen, we therefore have to check that
30383     * the filter upscaling buffer fits within this limit. */
30384    if (maxsize >= 2048)
30385    {
30386       RARCH_ERR("[Video]: Softfilter initialization failed."
30387             " Upscaling buffer exceeds hardware limitations.\n");
30388       video_driver_filter_free();
30389       return;
30390    }
30391 #endif
30392 
30393    p_rarch->video_driver_state_scale     = maxsize / RARCH_SCALE_BASE;
30394    p_rarch->video_driver_state_out_rgb32 = rarch_softfilter_get_output_format(
30395          p_rarch->video_driver_state_filter) == RETRO_PIXEL_FORMAT_XRGB8888;
30396 
30397    p_rarch->video_driver_state_out_bpp   =
30398       p_rarch->video_driver_state_out_rgb32 ?
30399       sizeof(uint32_t)             :
30400       sizeof(uint16_t);
30401 
30402    /* TODO: Aligned output. */
30403 #ifdef _3DS
30404    buf = linearMemAlign(
30405          width * height * p_rarch->video_driver_state_out_bpp, 0x80);
30406 #else
30407    buf = malloc(
30408          width * height * p_rarch->video_driver_state_out_bpp);
30409 #endif
30410    if (!buf)
30411    {
30412       RARCH_ERR("[Video]: Softfilter initialization failed.\n");
30413       video_driver_filter_free();
30414       return;
30415    }
30416 
30417    p_rarch->video_driver_state_buffer    = buf;
30418 }
30419 #endif
30420 
video_driver_init_input(input_driver_t * tmp,settings_t * settings,bool verbosity_enabled)30421 static void video_driver_init_input(
30422       input_driver_t *tmp,
30423       settings_t *settings,
30424       bool verbosity_enabled)
30425 {
30426    struct rarch_state *p_rarch = &rarch_st;
30427    input_driver_t      **input = &p_rarch->current_input;
30428    if (*input)
30429       return;
30430 
30431    /* Video driver didn't provide an input driver,
30432     * so we use configured one. */
30433    RARCH_LOG("[Video]: Graphics driver did not initialize an input driver."
30434          " Attempting to pick a suitable driver.\n");
30435 
30436    if (tmp)
30437       *input = tmp;
30438    else
30439       input_driver_find_driver(p_rarch, settings, "input driver",
30440             verbosity_enabled);
30441 
30442    /* This should never really happen as tmp (driver.input) is always
30443     * found before this in find_driver_input(), or we have aborted
30444     * in a similar fashion anyways. */
30445    if (!p_rarch->current_input || !input_driver_init(p_rarch, settings))
30446    {
30447       RARCH_ERR("[Video]: Cannot initialize input driver. Exiting ...\n");
30448       retroarch_fail(p_rarch, 1, "video_driver_init_input()");
30449    }
30450 }
30451 
30452 /**
30453  * video_driver_monitor_compute_fps_statistics:
30454  *
30455  * Computes monitor FPS statistics.
30456  **/
video_driver_monitor_compute_fps_statistics(struct rarch_state * p_rarch)30457 static void video_driver_monitor_compute_fps_statistics(struct rarch_state *p_rarch)
30458 {
30459    double        avg_fps       = 0.0;
30460    double        stddev        = 0.0;
30461    unsigned        samples     = 0;
30462 
30463    if (p_rarch->video_driver_frame_time_count <
30464          (2 * MEASURE_FRAME_TIME_SAMPLES_COUNT))
30465    {
30466       RARCH_LOG(
30467             "[Video]: Does not have enough samples for monitor refresh rate"
30468             " estimation. Requires to run for at least %u frames.\n",
30469             2 * MEASURE_FRAME_TIME_SAMPLES_COUNT);
30470       return;
30471    }
30472 
30473    if (video_monitor_fps_statistics(&avg_fps, &stddev, &samples))
30474    {
30475       RARCH_LOG("[Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time"
30476             " deviation, based on %u last samples).\n",
30477             avg_fps, 100.0f * stddev, samples);
30478    }
30479 }
30480 
video_driver_pixel_converter_free(video_pixel_scaler_t * scalr)30481 static void video_driver_pixel_converter_free(
30482       video_pixel_scaler_t *scalr)
30483 {
30484    if (!scalr)
30485       return;
30486 
30487    if (scalr->scaler)
30488    {
30489       scaler_ctx_gen_reset(scalr->scaler);
30490       free(scalr->scaler);
30491    }
30492    if (scalr->scaler_out)
30493       free(scalr->scaler_out);
30494 
30495    scalr->scaler     = NULL;
30496    scalr->scaler_out = NULL;
30497 
30498    free(scalr);
30499 }
30500 
video_driver_free_hw_context(struct rarch_state * p_rarch)30501 static void video_driver_free_hw_context(struct rarch_state *p_rarch)
30502 {
30503    VIDEO_DRIVER_CONTEXT_LOCK();
30504 
30505    if (p_rarch->hw_render.context_destroy)
30506       p_rarch->hw_render.context_destroy();
30507 
30508    memset(&p_rarch->hw_render, 0, sizeof(p_rarch->hw_render));
30509 
30510    VIDEO_DRIVER_CONTEXT_UNLOCK();
30511 
30512    p_rarch->hw_render_context_negotiation = NULL;
30513 }
30514 
video_driver_free_internal(struct rarch_state * p_rarch)30515 static void video_driver_free_internal(struct rarch_state *p_rarch)
30516 {
30517 #ifdef HAVE_THREADS
30518    bool        is_threaded     = VIDEO_DRIVER_IS_THREADED_INTERNAL();
30519 #endif
30520 
30521 #ifdef HAVE_VIDEO_LAYOUT
30522    video_layout_deinit();
30523 #endif
30524 
30525    command_event(CMD_EVENT_OVERLAY_DEINIT, NULL);
30526 
30527    if (!video_driver_is_video_cache_context())
30528       video_driver_free_hw_context(p_rarch);
30529 
30530    if (!(p_rarch->current_input_data == p_rarch->video_driver_data))
30531    {
30532       if (p_rarch->current_input)
30533          if (p_rarch->current_input->free)
30534             p_rarch->current_input->free(p_rarch->current_input_data);
30535       if (p_rarch->joypad)
30536          p_rarch->joypad->destroy();
30537       p_rarch->joypad                                     = NULL;
30538 #ifdef HAVE_MFI
30539       if (p_rarch->sec_joypad)
30540          p_rarch->sec_joypad->destroy();
30541       p_rarch->sec_joypad                                 = NULL;
30542 #endif
30543       p_rarch->keyboard_mapping_blocked                   = false;
30544       p_rarch->current_input_data                         = NULL;
30545    }
30546 
30547    if (p_rarch->video_driver_data
30548          && p_rarch->current_video
30549          && p_rarch->current_video->free)
30550       p_rarch->current_video->free(p_rarch->video_driver_data);
30551 
30552    if (p_rarch->video_driver_scaler_ptr)
30553       video_driver_pixel_converter_free(p_rarch->video_driver_scaler_ptr);
30554    p_rarch->video_driver_scaler_ptr = NULL;
30555 #ifdef HAVE_VIDEO_FILTER
30556    video_driver_filter_free();
30557 #endif
30558    dir_free_shader(
30559          (struct rarch_dir_shader_list*)&p_rarch->dir_shader_list,
30560          p_rarch->configuration_settings->bools.video_shader_remember_last_dir);
30561 
30562 #ifdef HAVE_THREADS
30563    if (is_threaded)
30564       return;
30565 #endif
30566 
30567    video_driver_monitor_compute_fps_statistics(p_rarch);
30568 }
30569 
video_driver_pixel_converter_init(const enum retro_pixel_format video_driver_pix_fmt,struct retro_hw_render_callback * hwr,unsigned size)30570 static video_pixel_scaler_t *video_driver_pixel_converter_init(
30571       const enum retro_pixel_format video_driver_pix_fmt,
30572       struct retro_hw_render_callback *hwr,
30573       unsigned size)
30574 {
30575    void *scalr_out                      = NULL;
30576    video_pixel_scaler_t          *scalr = NULL;
30577    struct scaler_ctx        *scalr_ctx  = NULL;
30578 
30579    /* If pixel format is not 0RGB1555, we don't need to do
30580     * any internal pixel conversion. */
30581    if (video_driver_pix_fmt != RETRO_PIXEL_FORMAT_0RGB1555)
30582       return NULL;
30583 
30584    /* No need to perform pixel conversion for HW rendering contexts. */
30585    if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE)
30586       return NULL;
30587 
30588    RARCH_WARN("[Video]: 0RGB1555 pixel format is deprecated,"
30589          " and will be slower. For 15/16-bit, RGB565"
30590          " format is preferred.\n");
30591 
30592    if (!(scalr = (video_pixel_scaler_t*)malloc(sizeof(*scalr))))
30593       goto error;
30594 
30595    scalr->scaler                            = NULL;
30596    scalr->scaler_out                        = NULL;
30597 
30598    if (!(scalr_ctx = (struct scaler_ctx*)calloc(1, sizeof(*scalr_ctx))))
30599       goto error;
30600 
30601    scalr->scaler                            = scalr_ctx;
30602    scalr->scaler->scaler_type               = SCALER_TYPE_POINT;
30603    scalr->scaler->in_fmt                    = SCALER_FMT_0RGB1555;
30604    /* TODO/FIXME: Pick either ARGB8888 or RGB565 depending on driver. */
30605    scalr->scaler->out_fmt                   = SCALER_FMT_RGB565;
30606 
30607    if (!scaler_ctx_gen_filter(scalr_ctx))
30608       goto error;
30609 
30610    if (!(scalr_out = calloc(sizeof(uint16_t), size * size)))
30611       goto error;
30612 
30613    scalr->scaler_out                        = scalr_out;
30614 
30615    return scalr;
30616 
30617 error:
30618    video_driver_pixel_converter_free(scalr);
30619 #ifdef HAVE_VIDEO_FILTER
30620    video_driver_filter_free();
30621 #endif
30622    return NULL;
30623 }
30624 
video_driver_set_viewport_config(struct retro_game_geometry * geom,float video_aspect_ratio,bool video_aspect_ratio_auto)30625 static void video_driver_set_viewport_config(
30626       struct retro_game_geometry *geom,
30627       float video_aspect_ratio,
30628       bool video_aspect_ratio_auto)
30629 {
30630    if (video_aspect_ratio < 0.0f)
30631    {
30632       if (geom->aspect_ratio > 0.0f && video_aspect_ratio_auto)
30633          aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio;
30634       else
30635       {
30636          unsigned base_width  = geom->base_width;
30637          unsigned base_height = geom->base_height;
30638 
30639          /* Get around division by zero errors */
30640          if (base_width == 0)
30641             base_width = 1;
30642          if (base_height == 0)
30643             base_height = 1;
30644          aspectratio_lut[ASPECT_RATIO_CONFIG].value =
30645             (float)base_width / base_height; /* 1:1 PAR. */
30646       }
30647    }
30648    else
30649       aspectratio_lut[ASPECT_RATIO_CONFIG].value = video_aspect_ratio;
30650 }
30651 
video_driver_set_viewport_square_pixel(struct retro_game_geometry * geom)30652 static void video_driver_set_viewport_square_pixel(struct retro_game_geometry *geom)
30653 {
30654    unsigned len, highest, i, aspect_x, aspect_y;
30655    unsigned width                    = geom->base_width;
30656    unsigned height                   = geom->base_height;
30657    unsigned int rotation             = retroarch_get_rotation();
30658 
30659    if (width == 0 || height == 0)
30660       return;
30661 
30662    len      = MIN(width, height);
30663    highest  = 1;
30664 
30665    for (i = 1; i < len; i++)
30666    {
30667       if ((width % i) == 0 && (height % i) == 0)
30668          highest = i;
30669    }
30670 
30671    if (rotation % 2)
30672    {
30673       aspect_x = height / highest;
30674       aspect_y = width / highest;
30675    }
30676    else
30677    {
30678       aspect_x = width / highest;
30679       aspect_y = height / highest;
30680    }
30681 
30682    snprintf(aspectratio_lut[ASPECT_RATIO_SQUARE].name,
30683          sizeof(aspectratio_lut[ASPECT_RATIO_SQUARE].name),
30684          "1:1 PAR (%u:%u DAR)", aspect_x, aspect_y);
30685 
30686    aspectratio_lut[ASPECT_RATIO_SQUARE].value = (float)aspect_x / aspect_y;
30687 }
30688 
video_driver_init_internal(struct rarch_state * p_rarch,settings_t * settings,bool * video_is_threaded,bool verbosity_enabled)30689 static bool video_driver_init_internal(
30690       struct rarch_state *p_rarch,
30691       settings_t *settings,
30692       bool *video_is_threaded,
30693       bool verbosity_enabled
30694      )
30695 {
30696    video_info_t video;
30697    unsigned max_dim, scale, width, height;
30698    video_viewport_t *custom_vp            = NULL;
30699    input_driver_t *tmp                    = NULL;
30700    static uint16_t dummy_pixels[32]       = {0};
30701    struct retro_game_geometry *geom       = &p_rarch->video_driver_av_info.geometry;
30702    const enum retro_pixel_format
30703       video_driver_pix_fmt                = p_rarch->video_driver_pix_fmt;
30704 #ifdef HAVE_VIDEO_FILTER
30705    const char *path_softfilter_plugin     = settings->paths.path_softfilter_plugin;
30706 
30707    if (!string_is_empty(path_softfilter_plugin))
30708       video_driver_init_filter(video_driver_pix_fmt, settings);
30709 #endif
30710 
30711    max_dim   = MAX(geom->max_width, geom->max_height);
30712    scale     = next_pow2(max_dim) / RARCH_SCALE_BASE;
30713    scale     = MAX(scale, 1);
30714 
30715 #ifdef HAVE_VIDEO_FILTER
30716    if (p_rarch->video_driver_state_filter)
30717       scale  = p_rarch->video_driver_state_scale;
30718 #endif
30719 
30720    /* Update core-dependent aspect ratio values. */
30721    video_driver_set_viewport_square_pixel(geom);
30722    video_driver_set_viewport_core();
30723    video_driver_set_viewport_config(geom,
30724          settings->floats.video_aspect_ratio,
30725          settings->bools.video_aspect_ratio_auto);
30726 
30727    /* Update CUSTOM viewport. */
30728    custom_vp = &settings->video_viewport_custom;
30729 
30730    if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
30731    {
30732       float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value;
30733       aspectratio_lut[ASPECT_RATIO_CUSTOM].value =
30734          (custom_vp->width && custom_vp->height) ?
30735          (float)custom_vp->width / custom_vp->height : default_aspect;
30736    }
30737 
30738    {
30739       /* Guard against aspect ratio index possibly being out of bounds */
30740       unsigned new_aspect_idx = settings->uints.video_aspect_ratio_idx;
30741       if (new_aspect_idx > ASPECT_RATIO_END)
30742          new_aspect_idx = settings->uints.video_aspect_ratio_idx = 0;
30743 
30744       video_driver_set_aspect_ratio_value(
30745             aspectratio_lut[new_aspect_idx].value);
30746    }
30747 
30748    if (settings->bools.video_fullscreen|| p_rarch->rarch_force_fullscreen)
30749    {
30750       width  = settings->uints.video_fullscreen_x;
30751       height = settings->uints.video_fullscreen_y;
30752    }
30753    else
30754    {
30755       /* TODO: remove when the new window resizing core is hooked */
30756       if (settings->bools.video_window_save_positions &&
30757          (settings->uints.window_position_width ||
30758           settings->uints.window_position_height))
30759       {
30760          width  = settings->uints.window_position_width;
30761          height = settings->uints.window_position_height;
30762       }
30763       else
30764       {
30765          float video_scale = settings->floats.video_scale;
30766          if (settings->bools.video_force_aspect)
30767          {
30768             /* Do rounding here to simplify integer scale correctness. */
30769             unsigned base_width =
30770                roundf(geom->base_height * p_rarch->video_driver_aspect_ratio);
30771             width  = roundf(base_width * video_scale);
30772          }
30773          else
30774             width  = roundf(geom->base_width   * video_scale);
30775          height    = roundf(geom->base_height  * video_scale);
30776       }
30777    }
30778 
30779 #ifdef __WINRT__
30780    if (settings->bools.video_force_resolution)
30781    {
30782       width = settings->uints.video_fullscreen_x != 0 ? settings->uints.video_fullscreen_x : 3840;
30783       height = settings->uints.video_fullscreen_y != 0 ? settings->uints.video_fullscreen_y : 2160;
30784    }
30785 #endif
30786 
30787    if (width && height)
30788       RARCH_LOG("[Video]: Video @ %ux%u\n", width, height);
30789    else
30790       RARCH_LOG("[Video]: Video @ fullscreen\n");
30791 
30792    p_rarch->video_driver_display_type     = RARCH_DISPLAY_NONE;
30793    p_rarch->video_driver_display          = 0;
30794    p_rarch->video_driver_display_userdata = 0;
30795    p_rarch->video_driver_window           = 0;
30796 
30797    p_rarch->video_driver_scaler_ptr       = video_driver_pixel_converter_init(
30798          p_rarch->video_driver_pix_fmt,
30799          VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch),
30800          RARCH_SCALE_BASE * scale);
30801 
30802    video.width                       = width;
30803    video.height                      = height;
30804    video.fullscreen                  = settings->bools.video_fullscreen ||
30805                                        p_rarch->rarch_force_fullscreen;
30806    video.vsync                       = settings->bools.video_vsync &&
30807       !runloop_state.force_nonblock;
30808    video.force_aspect                = settings->bools.video_force_aspect;
30809    video.font_enable                 = settings->bools.video_font_enable;
30810    video.swap_interval               = settings->uints.video_swap_interval;
30811    video.adaptive_vsync              = settings->bools.video_adaptive_vsync;
30812 #ifdef GEKKO
30813    video.viwidth                     = settings->uints.video_viwidth;
30814    video.vfilter                     = settings->bools.video_vfilter;
30815 #endif
30816    video.smooth                      = settings->bools.video_smooth;
30817    video.ctx_scaling                 = settings->bools.video_ctx_scaling;
30818    video.input_scale                 = scale;
30819    video.font_size                   = settings->floats.video_font_size;
30820    video.path_font                   = settings->paths.path_font;
30821 #ifdef HAVE_VIDEO_FILTER
30822    video.rgb32                       =
30823       p_rarch->video_driver_state_filter ?
30824       p_rarch->video_driver_state_out_rgb32 :
30825       (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
30826 #else
30827    video.rgb32                       =
30828       (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
30829 #endif
30830    video.parent                      = 0;
30831 
30832    p_rarch->video_started_fullscreen = video.fullscreen;
30833 
30834    /* Reset video frame count */
30835    p_rarch->video_driver_frame_count = 0;
30836 
30837    tmp                               = p_rarch->current_input;
30838    /* Need to grab the "real" video driver interface on a reinit. */
30839    video_driver_find_driver(p_rarch, settings,
30840          "video driver", verbosity_enabled);
30841 
30842 #ifdef HAVE_THREADS
30843    video.is_threaded                 = VIDEO_DRIVER_IS_THREADED_INTERNAL();
30844    *video_is_threaded                = video.is_threaded;
30845 
30846    if (video.is_threaded)
30847    {
30848       bool ret;
30849       /* Can't do hardware rendering with threaded driver currently. */
30850       RARCH_LOG("[Video]: Starting threaded video driver ...\n");
30851 
30852       ret = video_init_thread((const video_driver_t**)&p_rarch->current_video,
30853                &p_rarch->video_driver_data,
30854                &p_rarch->current_input,
30855                (void**)&p_rarch->current_input_data,
30856                p_rarch->current_video,
30857                video);
30858       if (!ret)
30859       {
30860          RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n");
30861          goto error;
30862       }
30863    }
30864    else
30865 #endif
30866       p_rarch->video_driver_data = p_rarch->current_video->init(
30867             &video,
30868             &p_rarch->current_input,
30869             (void**)&p_rarch->current_input_data);
30870 
30871    if (!p_rarch->video_driver_data)
30872    {
30873       RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n");
30874       goto error;
30875    }
30876 
30877    p_rarch->video_driver_poke = NULL;
30878    if (p_rarch->current_video->poke_interface)
30879       p_rarch->current_video->poke_interface(
30880             p_rarch->video_driver_data, &p_rarch->video_driver_poke);
30881 
30882    if (p_rarch->current_video->viewport_info &&
30883          (!custom_vp->width  ||
30884           !custom_vp->height))
30885    {
30886       /* Force custom viewport to have sane parameters. */
30887       custom_vp->width = width;
30888       custom_vp->height = height;
30889 
30890       video_driver_get_viewport_info(custom_vp);
30891    }
30892 
30893    video_driver_set_rotation(retroarch_get_rotation() % 4);
30894 
30895    p_rarch->current_video->suppress_screensaver(p_rarch->video_driver_data,
30896          settings->bools.ui_suspend_screensaver_enable);
30897 
30898    video_driver_init_input(tmp, settings, verbosity_enabled);
30899 
30900 #ifdef HAVE_OVERLAY
30901    retroarch_overlay_deinit(p_rarch);
30902    retroarch_overlay_init(p_rarch);
30903 #endif
30904 
30905 #ifdef HAVE_VIDEO_LAYOUT
30906    if (settings->bools.video_layout_enable)
30907    {
30908       video_layout_init(p_rarch->video_driver_data,
30909             video_driver_layout_render_interface());
30910       video_layout_load(settings->paths.path_video_layout);
30911       video_layout_view_select(settings->uints.video_layout_selected_view);
30912    }
30913 #endif
30914 
30915    if (!p_rarch->current_core.game_loaded)
30916       video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8);
30917 
30918 #if defined(PSP)
30919    video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f);
30920 #endif
30921 
30922    video_context_driver_reset();
30923 
30924    video_display_server_init(p_rarch->video_driver_display_type);
30925 
30926    if ((enum rotation)settings->uints.screen_orientation != ORIENTATION_NORMAL)
30927       video_display_server_set_screen_orientation((enum rotation)settings->uints.screen_orientation);
30928 
30929    /* Ensure that we preserve the 'grab mouse'
30930     * state if it was enabled prior to driver
30931     * (re-)initialisation */
30932    if (p_rarch->input_driver_grab_mouse_state)
30933    {
30934       video_driver_hide_mouse();
30935       input_driver_grab_mouse(p_rarch);
30936    }
30937    else if (video.fullscreen)
30938    {
30939       video_driver_hide_mouse();
30940       if (!settings->bools.video_windowed_fullscreen)
30941          input_driver_grab_mouse(p_rarch);
30942    }
30943 
30944    return true;
30945 
30946 error:
30947    retroarch_fail(p_rarch, 1, "init_video()");
30948    return false;
30949 }
30950 
video_driver_set_viewport(unsigned width,unsigned height,bool force_fullscreen,bool allow_rotate)30951 void video_driver_set_viewport(unsigned width, unsigned height,
30952       bool force_fullscreen, bool allow_rotate)
30953 {
30954    struct rarch_state            *p_rarch = &rarch_st;
30955    if (p_rarch->current_video && p_rarch->current_video->set_viewport)
30956       p_rarch->current_video->set_viewport(
30957             p_rarch->video_driver_data, width, height,
30958             force_fullscreen, allow_rotate);
30959 }
30960 
video_driver_set_rotation(unsigned rotation)30961 bool video_driver_set_rotation(unsigned rotation)
30962 {
30963    struct rarch_state            *p_rarch = &rarch_st;
30964    if (!p_rarch->current_video || !p_rarch->current_video->set_rotation)
30965       return false;
30966    p_rarch->current_video->set_rotation(p_rarch->video_driver_data, rotation);
30967    return true;
30968 }
30969 
video_driver_set_video_mode(unsigned width,unsigned height,bool fullscreen)30970 bool video_driver_set_video_mode(unsigned width,
30971       unsigned height, bool fullscreen)
30972 {
30973    struct rarch_state            *p_rarch = &rarch_st;
30974    if (  p_rarch->video_driver_poke &&
30975          p_rarch->video_driver_poke->set_video_mode)
30976    {
30977       p_rarch->video_driver_poke->set_video_mode(p_rarch->video_driver_data,
30978             width, height, fullscreen);
30979       return true;
30980    }
30981    return false;
30982 }
30983 
video_driver_get_video_output_size(unsigned * width,unsigned * height)30984 bool video_driver_get_video_output_size(unsigned *width, unsigned *height)
30985 {
30986    struct rarch_state            *p_rarch = &rarch_st;
30987    if (!p_rarch->video_driver_poke || !p_rarch->video_driver_poke->get_video_output_size)
30988       return false;
30989    p_rarch->video_driver_poke->get_video_output_size(p_rarch->video_driver_data,
30990          width, height);
30991    return true;
30992 }
30993 
30994 /* Draw text on top of the screen */
gfx_display_draw_text(const font_data_t * font,const char * text,float x,float y,int width,int height,uint32_t color,enum text_alignment text_align,float scale,bool shadows_enable,float shadow_offset,bool draw_outside)30995 void gfx_display_draw_text(
30996       const font_data_t *font, const char *text,
30997       float x, float y, int width, int height,
30998       uint32_t color, enum text_alignment text_align,
30999       float scale, bool shadows_enable, float shadow_offset,
31000       bool draw_outside)
31001 {
31002    struct font_params params;
31003    struct rarch_state *p_rarch = &rarch_st;
31004 
31005    if ((color & 0x000000FF) == 0)
31006       return;
31007 
31008    /* Don't draw outside of the screen */
31009    if (!draw_outside &&
31010            ((x < -64 || x > width  + 64)
31011          || (y < -64 || y > height + 64))
31012       )
31013       return;
31014 
31015    params.x           = x / width;
31016    params.y           = 1.0f - y / height;
31017    params.scale       = scale;
31018    params.drop_mod    = 0.0f;
31019    params.drop_x      = 0.0f;
31020    params.drop_y      = 0.0f;
31021    params.color       = color;
31022    params.full_screen = true;
31023    params.text_align  = text_align;
31024 
31025    if (shadows_enable)
31026    {
31027       params.drop_x      = shadow_offset;
31028       params.drop_y      = -shadow_offset;
31029       params.drop_alpha  = 0.35f;
31030    }
31031 
31032    if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_osd_msg)
31033       p_rarch->video_driver_poke->set_osd_msg(p_rarch->video_driver_data,
31034             text, &params, (void*)font);
31035 }
31036 
31037 
video_driver_set_texture_enable(bool enable,bool fullscreen)31038 void video_driver_set_texture_enable(bool enable, bool fullscreen)
31039 {
31040    struct rarch_state            *p_rarch = &rarch_st;
31041    if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_texture_enable)
31042       p_rarch->video_driver_poke->set_texture_enable(p_rarch->video_driver_data,
31043             enable, fullscreen);
31044 }
31045 
video_driver_set_texture_frame(const void * frame,bool rgb32,unsigned width,unsigned height,float alpha)31046 void video_driver_set_texture_frame(const void *frame, bool rgb32,
31047       unsigned width, unsigned height, float alpha)
31048 {
31049    struct rarch_state            *p_rarch = &rarch_st;
31050    if (p_rarch->video_driver_poke &&
31051          p_rarch->video_driver_poke->set_texture_frame)
31052       p_rarch->video_driver_poke->set_texture_frame(p_rarch->video_driver_data,
31053             frame, rgb32, width, height, alpha);
31054 }
31055 
31056 #ifdef HAVE_OVERLAY
video_driver_overlay_interface(const video_overlay_interface_t ** iface)31057 static bool video_driver_overlay_interface(
31058       const video_overlay_interface_t **iface)
31059 {
31060    struct rarch_state            *p_rarch = &rarch_st;
31061    if (!p_rarch->current_video || !p_rarch->current_video->overlay_interface)
31062       return false;
31063    p_rarch->current_video->overlay_interface(p_rarch->video_driver_data, iface);
31064    return true;
31065 }
31066 #endif
31067 
31068 #ifdef HAVE_VIDEO_LAYOUT
video_driver_layout_render_interface(void)31069 const video_layout_render_interface_t *video_driver_layout_render_interface(void)
31070 {
31071    struct rarch_state            *p_rarch = &rarch_st;
31072    if (  !p_rarch->current_video ||
31073          !p_rarch->current_video->video_layout_render_interface)
31074       return NULL;
31075 
31076    return p_rarch->current_video->video_layout_render_interface(
31077          p_rarch->video_driver_data);
31078 }
31079 #endif
31080 
video_driver_read_frame_raw(unsigned * width,unsigned * height,size_t * pitch)31081 void *video_driver_read_frame_raw(unsigned *width,
31082    unsigned *height, size_t *pitch)
31083 {
31084    struct rarch_state            *p_rarch = &rarch_st;
31085    if (!p_rarch->current_video || !p_rarch->current_video->read_frame_raw)
31086       return NULL;
31087    return p_rarch->current_video->read_frame_raw(
31088          p_rarch->video_driver_data, width,
31089          height, pitch);
31090 }
31091 
video_driver_set_filtering(unsigned index,bool smooth,bool ctx_scaling)31092 void video_driver_set_filtering(unsigned index, bool smooth, bool ctx_scaling)
31093 {
31094    struct rarch_state            *p_rarch = &rarch_st;
31095    if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->set_filtering)
31096       p_rarch->video_driver_poke->set_filtering(p_rarch->video_driver_data,
31097             index, smooth, ctx_scaling);
31098 }
31099 
video_driver_cached_frame_set(const void * data,unsigned width,unsigned height,size_t pitch)31100 void video_driver_cached_frame_set(const void *data, unsigned width,
31101       unsigned height, size_t pitch)
31102 {
31103    struct rarch_state *p_rarch  = &rarch_st;
31104 
31105    if (data)
31106       p_rarch->frame_cache_data = data;
31107 
31108    p_rarch->frame_cache_width   = width;
31109    p_rarch->frame_cache_height  = height;
31110    p_rarch->frame_cache_pitch   = pitch;
31111 }
31112 
video_driver_cached_frame_get(const void ** data,unsigned * width,unsigned * height,size_t * pitch)31113 void video_driver_cached_frame_get(const void **data, unsigned *width,
31114       unsigned *height, size_t *pitch)
31115 {
31116    struct rarch_state *p_rarch  = &rarch_st;
31117    if (data)
31118       *data    = p_rarch->frame_cache_data;
31119    if (width)
31120       *width   = p_rarch->frame_cache_width;
31121    if (height)
31122       *height  = p_rarch->frame_cache_height;
31123    if (pitch)
31124       *pitch   = p_rarch->frame_cache_pitch;
31125 }
31126 
video_driver_get_size(unsigned * width,unsigned * height)31127 void video_driver_get_size(unsigned *width, unsigned *height)
31128 {
31129    struct rarch_state *p_rarch = &rarch_st;
31130 #ifdef HAVE_THREADS
31131    bool            is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL();
31132 
31133    VIDEO_DRIVER_THREADED_LOCK(is_threaded);
31134 #endif
31135    if (width)
31136       *width  = p_rarch->video_driver_width;
31137    if (height)
31138       *height = p_rarch->video_driver_height;
31139 #ifdef HAVE_THREADS
31140    VIDEO_DRIVER_THREADED_UNLOCK(is_threaded);
31141 #endif
31142 }
31143 
video_driver_set_size(unsigned width,unsigned height)31144 void video_driver_set_size(unsigned width, unsigned height)
31145 {
31146    struct rarch_state *p_rarch   = &rarch_st;
31147 #ifdef HAVE_THREADS
31148    bool            is_threaded   = VIDEO_DRIVER_IS_THREADED_INTERNAL();
31149 
31150    VIDEO_DRIVER_THREADED_LOCK(is_threaded);
31151 #endif
31152    p_rarch->video_driver_width   = width;
31153    p_rarch->video_driver_height  = height;
31154 
31155 #ifdef HAVE_THREADS
31156    VIDEO_DRIVER_THREADED_UNLOCK(is_threaded);
31157 #endif
31158 }
31159 
31160 /**
31161  * video_monitor_set_refresh_rate:
31162  * @hz                 : New refresh rate for monitor.
31163  *
31164  * Sets monitor refresh rate to new value.
31165  **/
video_monitor_set_refresh_rate(float hz)31166 void video_monitor_set_refresh_rate(float hz)
31167 {
31168    char msg[128];
31169    struct rarch_state *p_rarch = &rarch_st;
31170    settings_t        *settings = p_rarch->configuration_settings;
31171 
31172    snprintf(msg, sizeof(msg),
31173          "[Video]: Setting refresh rate to: %.3f Hz.", hz);
31174    if (settings->bools.notification_show_refresh_rate)
31175       runloop_msg_queue_push(msg, 1, 180, false, NULL,
31176             MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
31177    RARCH_LOG("%s\n", msg);
31178 
31179    configuration_set_float(settings,
31180          settings->floats.video_refresh_rate,
31181          hz);
31182 }
31183 
31184 /**
31185  * video_monitor_fps_statistics
31186  * @refresh_rate       : Monitor refresh rate.
31187  * @deviation          : Deviation from measured refresh rate.
31188  * @sample_points      : Amount of sampled points.
31189  *
31190  * Gets the monitor FPS statistics based on the current
31191  * runtime.
31192  *
31193  * Returns: true (1) on success.
31194  * false (0) if:
31195  * a) threaded video mode is enabled
31196  * b) less than 2 frame time samples.
31197  * c) FPS monitor enable is off.
31198  **/
video_monitor_fps_statistics(double * refresh_rate,double * deviation,unsigned * sample_points)31199 bool video_monitor_fps_statistics(double *refresh_rate,
31200       double *deviation, unsigned *sample_points)
31201 {
31202    unsigned i;
31203    retro_time_t accum          = 0;
31204    retro_time_t avg            = 0;
31205    retro_time_t accum_var      = 0;
31206    unsigned samples            = 0;
31207    struct rarch_state *p_rarch = &rarch_st;
31208 
31209 #ifdef HAVE_THREADS
31210    if (VIDEO_DRIVER_IS_THREADED_INTERNAL())
31211       return false;
31212 #endif
31213 
31214    samples = MIN(MEASURE_FRAME_TIME_SAMPLES_COUNT,
31215          (unsigned)p_rarch->video_driver_frame_time_count);
31216 
31217    if (samples < 2)
31218       return false;
31219 
31220    /* Measure statistics on frame time (microsecs), *not* FPS. */
31221    for (i = 0; i < samples; i++)
31222    {
31223       accum += p_rarch->video_driver_frame_time_samples[i];
31224 #if 0
31225       RARCH_LOG("[Video]: Interval #%u: %d usec / frame.\n",
31226             i, (int)frame_time_samples[i]);
31227 #endif
31228    }
31229 
31230    avg = accum / samples;
31231 
31232    /* Drop first measurement. It is likely to be bad. */
31233    for (i = 0; i < samples; i++)
31234    {
31235       retro_time_t diff = p_rarch->video_driver_frame_time_samples[i] - avg;
31236       accum_var         += diff * diff;
31237    }
31238 
31239    *deviation        = sqrt((double)accum_var / (samples - 1)) / avg;
31240 
31241    if (refresh_rate)
31242       *refresh_rate  = 1000000.0 / avg;
31243 
31244    if (sample_points)
31245       *sample_points = samples;
31246 
31247    return true;
31248 }
31249 
video_driver_get_aspect_ratio(void)31250 float video_driver_get_aspect_ratio(void)
31251 {
31252    struct rarch_state *p_rarch = &rarch_st;
31253    return p_rarch->video_driver_aspect_ratio;
31254 }
31255 
video_driver_set_aspect_ratio_value(float value)31256 void video_driver_set_aspect_ratio_value(float value)
31257 {
31258    struct rarch_state        *p_rarch = &rarch_st;
31259    p_rarch->video_driver_aspect_ratio = value;
31260 }
31261 
video_driver_get_pixel_format(void)31262 enum retro_pixel_format video_driver_get_pixel_format(void)
31263 {
31264    struct rarch_state *p_rarch = &rarch_st;
31265    return p_rarch->video_driver_pix_fmt;
31266 }
31267 
31268 /**
31269  * video_driver_cached_frame:
31270  *
31271  * Renders the current video frame.
31272  **/
video_driver_cached_frame(void)31273 void video_driver_cached_frame(void)
31274 {
31275    struct rarch_state *p_rarch  = &rarch_st;
31276    void             *recording  = p_rarch->recording_data;
31277    struct retro_callbacks *cbs  = &p_rarch->retro_ctx;
31278 
31279    /* Cannot allow recording when pushing duped frames. */
31280    p_rarch->recording_data      = NULL;
31281 
31282    if (p_rarch->current_core.inited)
31283       cbs->frame_cb(
31284             (p_rarch->frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID)
31285             ? p_rarch->frame_cache_data : NULL,
31286             p_rarch->frame_cache_width,
31287             p_rarch->frame_cache_height,
31288             p_rarch->frame_cache_pitch);
31289 
31290    p_rarch->recording_data      = recording;
31291 }
31292 
video_driver_monitor_adjust_system_rates(float timing_skew_hz,float video_refresh_rate,bool vrr_runloop_enable,float audio_max_timing_skew,double input_fps)31293 static bool video_driver_monitor_adjust_system_rates(
31294       float timing_skew_hz,
31295       float video_refresh_rate,
31296       bool vrr_runloop_enable,
31297       float audio_max_timing_skew,
31298       double input_fps)
31299 {
31300    if (!vrr_runloop_enable)
31301    {
31302       float timing_skew                    = fabs(
31303             1.0f - input_fps / timing_skew_hz);
31304       /* We don't want to adjust pitch too much. If we have extreme cases,
31305        * just don't readjust at all. */
31306       if (timing_skew <= audio_max_timing_skew)
31307          return true;
31308       RARCH_LOG("[Video]: Timings deviate too much. Will not adjust."
31309             " (Display = %.2f Hz, Game = %.2f Hz)\n",
31310             video_refresh_rate,
31311             (float)input_fps);
31312    }
31313    return input_fps <= timing_skew_hz;
31314 }
31315 
video_driver_lock_new(struct rarch_state * p_rarch)31316 static void video_driver_lock_new(struct rarch_state *p_rarch)
31317 {
31318    VIDEO_DRIVER_LOCK_FREE();
31319 #ifdef HAVE_THREADS
31320    if (!p_rarch->display_lock)
31321       p_rarch->display_lock = slock_new();
31322    retro_assert(p_rarch->display_lock);
31323 
31324    if (!p_rarch->context_lock)
31325       p_rarch->context_lock = slock_new();
31326    retro_assert(p_rarch->context_lock);
31327 #endif
31328 }
31329 
video_driver_set_cached_frame_ptr(const void * data)31330 void video_driver_set_cached_frame_ptr(const void *data)
31331 {
31332    struct rarch_state *p_rarch = &rarch_st;
31333    p_rarch->frame_cache_data = data;
31334 }
31335 
video_driver_set_stub_frame(void)31336 void video_driver_set_stub_frame(void)
31337 {
31338    struct rarch_state *p_rarch   = &rarch_st;
31339 
31340    p_rarch->frame_bak            = p_rarch->current_video->frame;
31341    p_rarch->current_video->frame = video_null.frame;
31342 }
31343 
video_driver_unset_stub_frame(void)31344 void video_driver_unset_stub_frame(void)
31345 {
31346    struct rarch_state *p_rarch      = &rarch_st;
31347 
31348    if (p_rarch->frame_bak)
31349       p_rarch->current_video->frame = p_rarch->frame_bak;
31350 
31351    p_rarch->frame_bak               = NULL;
31352 }
31353 
video_driver_supports_viewport_read(void)31354 bool video_driver_supports_viewport_read(void)
31355 {
31356    struct rarch_state *p_rarch      = &rarch_st;
31357 
31358    return p_rarch->current_video->read_viewport
31359       && p_rarch->current_video->viewport_info;
31360 }
31361 
video_driver_prefer_viewport_read(void)31362 bool video_driver_prefer_viewport_read(void)
31363 {
31364    struct rarch_state *p_rarch = &rarch_st;
31365    settings_t *settings        = p_rarch->configuration_settings;
31366 #ifdef HAVE_SCREENSHOTS
31367    bool video_gpu_screenshot   = settings->bools.video_gpu_screenshot;
31368    if (video_gpu_screenshot)
31369       return true;
31370 #endif
31371    return (video_driver_is_hw_context() &&
31372        !p_rarch->current_video->read_frame_raw);
31373 }
31374 
video_driver_supports_read_frame_raw(void)31375 bool video_driver_supports_read_frame_raw(void)
31376 {
31377    struct rarch_state *p_rarch = &rarch_st;
31378    if (p_rarch->current_video->read_frame_raw)
31379       return true;
31380    return false;
31381 }
31382 
video_driver_set_viewport_core(void)31383 void video_driver_set_viewport_core(void)
31384 {
31385    struct rarch_state        *p_rarch   = &rarch_st;
31386    struct retro_game_geometry *geom     = &p_rarch->video_driver_av_info.geometry;
31387 
31388    if (!geom || geom->base_width <= 0.0f || geom->base_height <= 0.0f)
31389       return;
31390 
31391    /* Fallback to 1:1 pixel ratio if none provided */
31392    if (geom->aspect_ratio > 0.0f)
31393       aspectratio_lut[ASPECT_RATIO_CORE].value = geom->aspect_ratio;
31394    else
31395       aspectratio_lut[ASPECT_RATIO_CORE].value =
31396          (float)geom->base_width / geom->base_height;
31397 }
31398 
video_driver_set_viewport_full(void)31399 void video_driver_set_viewport_full(void)
31400 {
31401    unsigned width = 0;
31402    unsigned height = 0;
31403 
31404    video_driver_get_size(&width, &height);
31405 
31406    if (width == 0 || height == 0)
31407       return;
31408 
31409    aspectratio_lut[ASPECT_RATIO_FULL].value = (float)width / (float)height;
31410 }
31411 
video_driver_reset_custom_viewport(void)31412 void video_driver_reset_custom_viewport(void)
31413 {
31414    struct rarch_state *p_rarch      = &rarch_st;
31415    settings_t             *settings = p_rarch->configuration_settings;
31416    struct video_viewport *custom_vp = &settings->video_viewport_custom;
31417 
31418    custom_vp->width  = 0;
31419    custom_vp->height = 0;
31420    custom_vp->x      = 0;
31421    custom_vp->y      = 0;
31422 }
31423 
video_driver_set_rgba(void)31424 void video_driver_set_rgba(void)
31425 {
31426    struct rarch_state *p_rarch    = &rarch_st;
31427    VIDEO_DRIVER_LOCK();
31428    p_rarch->video_driver_use_rgba = true;
31429    VIDEO_DRIVER_UNLOCK();
31430 }
31431 
video_driver_unset_rgba(void)31432 void video_driver_unset_rgba(void)
31433 {
31434    struct rarch_state *p_rarch    = &rarch_st;
31435    VIDEO_DRIVER_LOCK();
31436    p_rarch->video_driver_use_rgba = false;
31437    VIDEO_DRIVER_UNLOCK();
31438 }
31439 
video_driver_supports_rgba(void)31440 bool video_driver_supports_rgba(void)
31441 {
31442    bool tmp;
31443    struct rarch_state *p_rarch = &rarch_st;
31444    VIDEO_DRIVER_LOCK();
31445    tmp = p_rarch->video_driver_use_rgba;
31446    VIDEO_DRIVER_UNLOCK();
31447    return tmp;
31448 }
31449 
video_driver_get_next_video_out(void)31450 bool video_driver_get_next_video_out(void)
31451 {
31452    struct rarch_state *p_rarch = &rarch_st;
31453    if (     !p_rarch->video_driver_poke
31454          || !p_rarch->video_driver_poke->get_video_output_next
31455       )
31456       return false;
31457 
31458    p_rarch->video_driver_poke->get_video_output_next(
31459          p_rarch->video_driver_data);
31460    return true;
31461 }
31462 
video_driver_get_prev_video_out(void)31463 bool video_driver_get_prev_video_out(void)
31464 {
31465    struct rarch_state *p_rarch = &rarch_st;
31466    if (
31467             !p_rarch->video_driver_poke
31468          || !p_rarch->video_driver_poke->get_video_output_prev
31469       )
31470       return false;
31471 
31472    p_rarch->video_driver_poke->get_video_output_prev(
31473          p_rarch->video_driver_data);
31474    return true;
31475 }
31476 
video_driver_monitor_reset(void)31477 void video_driver_monitor_reset(void)
31478 {
31479    struct rarch_state            *p_rarch = &rarch_st;
31480    p_rarch->video_driver_frame_time_count = 0;
31481 }
31482 
video_driver_set_aspect_ratio(void)31483 void video_driver_set_aspect_ratio(void)
31484 {
31485    struct rarch_state *p_rarch = &rarch_st;
31486    settings_t  *settings       = p_rarch->configuration_settings;
31487    unsigned  aspect_ratio_idx  = settings->uints.video_aspect_ratio_idx;
31488 
31489    switch (aspect_ratio_idx)
31490    {
31491       case ASPECT_RATIO_SQUARE:
31492          video_driver_set_viewport_square_pixel(&p_rarch->video_driver_av_info.geometry);
31493          break;
31494 
31495       case ASPECT_RATIO_CORE:
31496          video_driver_set_viewport_core();
31497          break;
31498 
31499       case ASPECT_RATIO_CONFIG:
31500          video_driver_set_viewport_config(
31501                &p_rarch->video_driver_av_info.geometry,
31502                settings->floats.video_aspect_ratio,
31503                settings->bools.video_aspect_ratio_auto);
31504          break;
31505 
31506       case ASPECT_RATIO_FULL:
31507          video_driver_set_viewport_full();
31508          break;
31509 
31510       default:
31511          break;
31512    }
31513 
31514    video_driver_set_aspect_ratio_value(
31515             aspectratio_lut[aspect_ratio_idx].value);
31516 
31517    if (  p_rarch->video_driver_poke &&
31518          p_rarch->video_driver_poke->set_aspect_ratio)
31519       p_rarch->video_driver_poke->set_aspect_ratio(
31520             p_rarch->video_driver_data, aspect_ratio_idx);
31521 }
31522 
video_driver_update_viewport(struct video_viewport * vp,bool force_full,bool keep_aspect)31523 void video_driver_update_viewport(
31524       struct video_viewport* vp, bool force_full, bool keep_aspect)
31525 {
31526    struct rarch_state *p_rarch     = &rarch_st;
31527    float            device_aspect  = (float)vp->full_width / vp->full_height;
31528    settings_t *settings            = p_rarch->configuration_settings;
31529    bool video_scale_integer        = settings->bools.video_scale_integer;
31530    unsigned video_aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
31531    float video_driver_aspect_ratio = p_rarch->video_driver_aspect_ratio;
31532 
31533    vp->x                           = 0;
31534    vp->y                           = 0;
31535    vp->width                       = vp->full_width;
31536    vp->height                      = vp->full_height;
31537 
31538    if (video_scale_integer && !force_full)
31539       video_viewport_get_scaled_integer(
31540             vp,
31541             vp->full_width,
31542             vp->full_height,
31543             video_driver_aspect_ratio, keep_aspect);
31544    else if (keep_aspect && !force_full)
31545    {
31546       float desired_aspect = video_driver_aspect_ratio;
31547 
31548 #if defined(HAVE_MENU)
31549       if (video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
31550       {
31551          const struct video_viewport *custom = &settings->video_viewport_custom;
31552 
31553          vp->x      = custom->x;
31554          vp->y      = custom->y;
31555          vp->width  = custom->width;
31556          vp->height = custom->height;
31557       }
31558       else
31559 #endif
31560       {
31561          float delta;
31562 
31563          if (fabsf(device_aspect - desired_aspect) < 0.0001f)
31564          {
31565             /* If the aspect ratios of screen and desired aspect
31566              * ratio are sufficiently equal (floating point stuff),
31567              * assume they are actually equal.
31568              */
31569          }
31570          else if (device_aspect > desired_aspect)
31571          {
31572             delta      = (desired_aspect / device_aspect - 1.0f)
31573                / 2.0f + 0.5f;
31574             vp->x      = (int)roundf(vp->full_width * (0.5f - delta));
31575             vp->width  = (unsigned)roundf(2.0f * vp->full_width * delta);
31576             vp->y      = 0;
31577             vp->height = vp->full_height;
31578          }
31579          else
31580          {
31581             vp->x      = 0;
31582             vp->width  = vp->full_width;
31583             delta      = (device_aspect / desired_aspect - 1.0f)
31584                / 2.0f + 0.5f;
31585             vp->y      = (int)roundf(vp->full_height * (0.5f - delta));
31586             vp->height = (unsigned)roundf(2.0f * vp->full_height * delta);
31587          }
31588       }
31589    }
31590 
31591 #if defined(RARCH_MOBILE)
31592    /* In portrait mode, we want viewport to gravitate to top of screen. */
31593    if (device_aspect < 1.0f)
31594       vp->y = 0;
31595 #endif
31596 }
31597 
video_driver_show_mouse(void)31598 void video_driver_show_mouse(void)
31599 {
31600    struct rarch_state *p_rarch = &rarch_st;
31601    if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->show_mouse)
31602       p_rarch->video_driver_poke->show_mouse(p_rarch->video_driver_data, true);
31603 }
31604 
video_driver_hide_mouse(void)31605 void video_driver_hide_mouse(void)
31606 {
31607    struct rarch_state *p_rarch = &rarch_st;
31608    if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->show_mouse)
31609       p_rarch->video_driver_poke->show_mouse(p_rarch->video_driver_data, false);
31610 }
31611 
video_driver_save_as_cached(struct rarch_state * p_rarch,settings_t * settings,const char * rdr_context_name)31612 static void video_driver_save_as_cached(struct rarch_state *p_rarch,
31613       settings_t *settings, const char *rdr_context_name)
31614 {
31615    RARCH_LOG("[Video]: \"%s\" saved as cached driver.\n",
31616          settings->arrays.video_driver);
31617    strlcpy(p_rarch->cached_video_driver,
31618          settings->arrays.video_driver,
31619          sizeof(p_rarch->cached_video_driver));
31620    configuration_set_string(settings,
31621          settings->arrays.video_driver,
31622          rdr_context_name);
31623 }
31624 
video_driver_restore_cached(struct rarch_state * p_rarch,settings_t * settings)31625 static void video_driver_restore_cached(struct rarch_state *p_rarch,
31626       settings_t *settings)
31627 {
31628    if (p_rarch->cached_video_driver[0])
31629    {
31630       configuration_set_string(settings,
31631             settings->arrays.video_driver, p_rarch->cached_video_driver);
31632 
31633       p_rarch->cached_video_driver[0] = 0;
31634       RARCH_LOG("[Video]: Restored video driver to \"%s\".\n",
31635             settings->arrays.video_driver);
31636    }
31637 }
31638 
video_driver_find_driver(struct rarch_state * p_rarch,settings_t * settings,const char * prefix,bool verbosity_enabled)31639 static bool video_driver_find_driver(struct rarch_state *p_rarch,
31640       settings_t *settings,
31641       const char *prefix, bool verbosity_enabled)
31642 {
31643    int i;
31644 
31645    if (video_driver_is_hw_context())
31646    {
31647       struct retro_hw_render_callback *hwr =
31648          VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
31649       int rdr_major                        = hwr->version_major;
31650       int rdr_minor                        = hwr->version_minor;
31651       const char *rdr_context_name         = hw_render_context_name(hwr->context_type, rdr_major, rdr_minor);
31652       enum retro_hw_context_type rdr_type  = hw_render_context_type(rdr_context_name);
31653 
31654       p_rarch->current_video               = NULL;
31655 
31656       if (hwr)
31657       {
31658          switch (rdr_type)
31659          {
31660             case RETRO_HW_CONTEXT_OPENGL_CORE:
31661             case RETRO_HW_CONTEXT_VULKAN:
31662             case RETRO_HW_CONTEXT_DIRECT3D:
31663 #if defined(HAVE_VULKAN) || defined(HAVE_D3D11) || defined(HAVE_D3D9) || defined(HAVE_OPENGL_CORE)
31664                RARCH_LOG("[Video]: Using HW render, %s driver forced.\n",
31665                      rdr_context_name);
31666 
31667                if (!string_is_equal(settings->arrays.video_driver,
31668                         rdr_context_name))
31669                   video_driver_save_as_cached(p_rarch, settings, rdr_context_name);
31670 
31671                p_rarch->current_video = hw_render_context_driver(rdr_type, rdr_major, rdr_minor);
31672                return true;
31673 #else
31674                break;
31675 #endif
31676             case RETRO_HW_CONTEXT_OPENGL:
31677 #if defined(HAVE_OPENGL)
31678                RARCH_LOG("[Video]: Using HW render, OpenGL driver forced.\n");
31679 
31680                /* If we have configured one of the HW render
31681                 * capable GL drivers, go with that. */
31682 #if defined(HAVE_OPENGL_CORE)
31683                if (  !string_is_equal(settings->arrays.video_driver, "gl") &&
31684                      !string_is_equal(settings->arrays.video_driver, "glcore"))
31685                {
31686                   video_driver_save_as_cached(p_rarch, settings, "glcore");
31687                   p_rarch->current_video = &video_gl_core;
31688                   return true;
31689                }
31690 #else
31691                if (  !string_is_equal(settings->arrays.video_driver, "gl"))
31692                {
31693                   video_driver_save_as_cached(p_rarch, settings, "gl");
31694                   p_rarch->current_video = &video_gl2;
31695                   return true;
31696                }
31697 #endif
31698 
31699                RARCH_LOG("[Video]: Using configured \"%s\""
31700                      " driver for GL HW render.\n",
31701                      settings->arrays.video_driver);
31702                break;
31703 #endif
31704             default:
31705             case RETRO_HW_CONTEXT_NONE:
31706                break;
31707          }
31708       }
31709    }
31710 
31711    if (frontend_driver_has_get_video_driver_func())
31712    {
31713       if ((p_rarch->current_video = (video_driver_t*)
31714                frontend_driver_get_video_driver()))
31715          return true;
31716 
31717       RARCH_WARN("[Video]: Frontend supports get_video_driver() but did not specify one.\n");
31718    }
31719 
31720    i                   = (int)driver_find_index(
31721          "video_driver",
31722          settings->arrays.video_driver);
31723 
31724    if (i >= 0)
31725       p_rarch->current_video = (video_driver_t*)video_drivers[i];
31726    else
31727    {
31728       if (verbosity_enabled)
31729       {
31730          unsigned d;
31731          RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
31732                settings->arrays.video_driver);
31733          RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
31734          for (d = 0; video_drivers[d]; d++)
31735             RARCH_LOG_OUTPUT("\t%s\n", video_drivers[d]->ident);
31736          RARCH_WARN("Going to default to first %s...\n", prefix);
31737       }
31738 
31739       if (!(p_rarch->current_video = (video_driver_t*)video_drivers[0]))
31740          retroarch_fail(p_rarch, 1, "find_video_driver()");
31741    }
31742    return true;
31743 }
31744 
video_driver_apply_state_changes(void)31745 void video_driver_apply_state_changes(void)
31746 {
31747    struct rarch_state *p_rarch = &rarch_st;
31748    if (  p_rarch->video_driver_poke &&
31749          p_rarch->video_driver_poke->apply_state_changes)
31750       p_rarch->video_driver_poke->apply_state_changes(
31751             p_rarch->video_driver_data);
31752 }
31753 
video_driver_read_viewport(uint8_t * buffer,bool is_idle)31754 bool video_driver_read_viewport(uint8_t *buffer, bool is_idle)
31755 {
31756    struct rarch_state *p_rarch = &rarch_st;
31757    if (     p_rarch->current_video->read_viewport
31758          && p_rarch->current_video->read_viewport(
31759             p_rarch->video_driver_data, buffer, is_idle))
31760       return true;
31761    return false;
31762 }
31763 
video_driver_reinit_context(struct rarch_state * p_rarch,settings_t * settings,int flags)31764 static void video_driver_reinit_context(struct rarch_state *p_rarch,
31765       settings_t *settings, int flags)
31766 {
31767    /* RARCH_DRIVER_CTL_UNINIT clears the callback struct so we
31768     * need to make sure to keep a copy */
31769    struct retro_hw_render_callback hwr_copy;
31770    struct retro_hw_render_callback *hwr =
31771       VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
31772    const struct retro_hw_render_context_negotiation_interface *iface =
31773       p_rarch->hw_render_context_negotiation;
31774    memcpy(&hwr_copy, hwr, sizeof(hwr_copy));
31775 
31776    driver_uninit(p_rarch, flags);
31777 
31778    memcpy(hwr, &hwr_copy, sizeof(*hwr));
31779    p_rarch->hw_render_context_negotiation = iface;
31780 
31781    drivers_init(p_rarch, settings, flags, verbosity_is_enabled());
31782 }
31783 
video_driver_reinit(int flags)31784 void video_driver_reinit(int flags)
31785 {
31786    struct rarch_state          *p_rarch    = &rarch_st;
31787    settings_t *settings                    = p_rarch->configuration_settings;
31788    struct retro_hw_render_callback *hwr    =
31789       VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
31790 
31791    p_rarch->video_driver_cache_context     = (hwr->cache_context != false);
31792    p_rarch->video_driver_cache_context_ack = false;
31793    video_driver_reinit_context(p_rarch, settings, flags);
31794    p_rarch->video_driver_cache_context     = false;
31795 }
31796 
video_driver_is_hw_context(void)31797 bool video_driver_is_hw_context(void)
31798 {
31799    bool            is_hw_context = false;
31800    struct rarch_state   *p_rarch = &rarch_st;
31801 
31802    VIDEO_DRIVER_CONTEXT_LOCK();
31803    is_hw_context                 = (p_rarch->hw_render.context_type
31804          != RETRO_HW_CONTEXT_NONE);
31805    VIDEO_DRIVER_CONTEXT_UNLOCK();
31806 
31807    return is_hw_context;
31808 }
31809 
31810 const struct retro_hw_render_context_negotiation_interface *
video_driver_get_context_negotiation_interface(void)31811    video_driver_get_context_negotiation_interface(void)
31812 {
31813    struct rarch_state *p_rarch = &rarch_st;
31814    return p_rarch->hw_render_context_negotiation;
31815 }
31816 
video_driver_is_video_cache_context(void)31817 bool video_driver_is_video_cache_context(void)
31818 {
31819    struct rarch_state *p_rarch = &rarch_st;
31820    return p_rarch->video_driver_cache_context;
31821 }
31822 
video_driver_set_video_cache_context_ack(void)31823 void video_driver_set_video_cache_context_ack(void)
31824 {
31825    struct rarch_state *p_rarch = &rarch_st;
31826    p_rarch->video_driver_cache_context_ack = true;
31827 }
31828 
video_driver_get_viewport_info(struct video_viewport * viewport)31829 bool video_driver_get_viewport_info(struct video_viewport *viewport)
31830 {
31831    struct rarch_state *p_rarch = &rarch_st;
31832    if (!p_rarch->current_video || !p_rarch->current_video->viewport_info)
31833       return false;
31834    p_rarch->current_video->viewport_info(
31835          p_rarch->video_driver_data, viewport);
31836    return true;
31837 }
31838 
31839 /**
31840  * video_viewport_get_scaled_integer:
31841  * @vp            : Viewport handle
31842  * @width         : Width.
31843  * @height        : Height.
31844  * @aspect_ratio  : Aspect ratio (in float).
31845  * @keep_aspect   : Preserve aspect ratio?
31846  *
31847  * Gets viewport scaling dimensions based on
31848  * scaled integer aspect ratio.
31849  **/
video_viewport_get_scaled_integer(struct video_viewport * vp,unsigned width,unsigned height,float aspect_ratio,bool keep_aspect)31850 void video_viewport_get_scaled_integer(struct video_viewport *vp,
31851       unsigned width, unsigned height,
31852       float aspect_ratio, bool keep_aspect)
31853 {
31854    int padding_x                   = 0;
31855    int padding_y                   = 0;
31856    struct rarch_state     *p_rarch = &rarch_st;
31857    settings_t *settings            = p_rarch->configuration_settings;
31858    unsigned video_aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
31859    bool overscale                  = settings->bools.video_scale_integer_overscale;
31860 
31861    if (video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
31862    {
31863       struct video_viewport *custom = &settings->video_viewport_custom;
31864 
31865       if (custom)
31866       {
31867          padding_x = width - custom->width;
31868          padding_y = height - custom->height;
31869          width     = custom->width;
31870          height    = custom->height;
31871       }
31872    }
31873    else
31874    {
31875       unsigned base_width;
31876       /* Use system reported sizes as these define the
31877        * geometry for the "normal" case. */
31878       unsigned base_height  =
31879          p_rarch->video_driver_av_info.geometry.base_height;
31880       unsigned int rotation = retroarch_get_rotation();
31881 
31882       if (rotation % 2)
31883          base_height = p_rarch->video_driver_av_info.geometry.base_width;
31884 
31885       if (base_height == 0)
31886          base_height = 1;
31887 
31888       /* Account for non-square pixels.
31889        * This is sort of contradictory with the goal of integer scale,
31890        * but it is desirable in some cases.
31891        *
31892        * If square pixels are used, base_height will be equal to
31893        * system->av_info.base_height. */
31894       base_width = (unsigned)roundf(base_height * aspect_ratio);
31895 
31896       /* Make sure that we don't get 0x scale ... */
31897       if (width >= base_width && height >= base_height)
31898       {
31899          if (keep_aspect)
31900          {
31901             /* X/Y scale must be same. */
31902             unsigned max_scale = 1;
31903 
31904             if (overscale)
31905                max_scale = MIN((width / base_width) + !!(width % base_width),
31906                      (height / base_height) + !!(height % base_height));
31907             else
31908                max_scale = MIN(width / base_width,
31909                      height / base_height);
31910 
31911             padding_x          = width - base_width * max_scale;
31912             padding_y          = height - base_height * max_scale;
31913          }
31914          else
31915          {
31916             /* X/Y can be independent, each scaled as much as possible. */
31917             padding_x = width % base_width;
31918             padding_y = height % base_height;
31919          }
31920       }
31921 
31922       width     -= padding_x;
31923       height    -= padding_y;
31924    }
31925 
31926    vp->width  = width;
31927    vp->height = height;
31928    vp->x      = padding_x / 2;
31929    vp->y      = padding_y / 2;
31930 }
31931 
video_viewport_get_custom(void)31932 struct video_viewport *video_viewport_get_custom(void)
31933 {
31934    struct rarch_state *p_rarch = &rarch_st;
31935    settings_t        *settings = p_rarch->configuration_settings;
31936    return &settings->video_viewport_custom;
31937 }
31938 
31939 /**
31940  * video_driver_frame:
31941  * @data                 : pointer to data of the video frame.
31942  * @width                : width of the video frame.
31943  * @height               : height of the video frame.
31944  * @pitch                : pitch of the video frame.
31945  *
31946  * Video frame render callback function.
31947  **/
video_driver_frame(const void * data,unsigned width,unsigned height,size_t pitch)31948 static void video_driver_frame(const void *data, unsigned width,
31949       unsigned height, size_t pitch)
31950 {
31951    char status_text[128];
31952    static char video_driver_msg[256];
31953    static retro_time_t curr_time;
31954    static retro_time_t fps_time;
31955    static float last_fps, frame_time;
31956    static uint64_t last_used_memory, last_total_memory;
31957    retro_time_t new_time;
31958    video_frame_info_t video_info;
31959    struct rarch_state *p_rarch  = &rarch_st;
31960    const enum retro_pixel_format
31961       video_driver_pix_fmt      = p_rarch->video_driver_pix_fmt;
31962    bool runloop_idle            = runloop_state.idle;
31963    bool video_driver_active     = p_rarch->video_driver_active;
31964 #if defined(HAVE_GFX_WIDGETS)
31965    bool widgets_active          = p_rarch->widgets_active;
31966 #endif
31967 
31968    status_text[0]               = '\0';
31969    video_driver_msg[0]          = '\0';
31970 
31971    if (!video_driver_active)
31972       return;
31973 
31974    new_time                     = cpu_features_get_time_usec();
31975 
31976    if (data)
31977       p_rarch->frame_cache_data = data;
31978    p_rarch->frame_cache_width   = width;
31979    p_rarch->frame_cache_height  = height;
31980    p_rarch->frame_cache_pitch   = pitch;
31981 
31982    if (
31983             p_rarch->video_driver_scaler_ptr
31984          && data
31985          && (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_0RGB1555)
31986          && (data != RETRO_HW_FRAME_BUFFER_VALID)
31987          && video_pixel_frame_scale(
31988             p_rarch->video_driver_scaler_ptr->scaler,
31989             p_rarch->video_driver_scaler_ptr->scaler_out,
31990             data, width, height, pitch)
31991       )
31992    {
31993       data                = p_rarch->video_driver_scaler_ptr->scaler_out;
31994       pitch               = p_rarch->video_driver_scaler_ptr->scaler->out_stride;
31995    }
31996 
31997    video_driver_build_info(&video_info);
31998 
31999    /* Get the amount of frames per seconds. */
32000    if (p_rarch->video_driver_frame_count)
32001    {
32002       unsigned fps_update_interval                 =
32003          video_info.fps_update_interval;
32004       unsigned memory_update_interval              =
32005          video_info.memory_update_interval;
32006       size_t buf_pos                               = 1;
32007       /* set this to 1 to avoid an offset issue */
32008       unsigned write_index                         =
32009          p_rarch->video_driver_frame_time_count++ &
32010          (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1);
32011       frame_time                                   = new_time - fps_time;
32012       p_rarch->video_driver_frame_time_samples
32013          [write_index]                             = frame_time;
32014       fps_time                                     = new_time;
32015 
32016       if (video_info.fps_show)
32017          buf_pos = snprintf(
32018                status_text, sizeof(status_text),
32019                "FPS: %6.2f", last_fps);
32020 
32021       if (video_info.framecount_show)
32022       {
32023          char frames_text[64];
32024          if (status_text[buf_pos-1] != '\0')
32025             strlcat(status_text, " || ", sizeof(status_text));
32026          snprintf(frames_text,
32027                sizeof(frames_text),
32028                "%s: %" PRIu64, msg_hash_to_str(MSG_FRAMES),
32029                (uint64_t)p_rarch->video_driver_frame_count);
32030          buf_pos = strlcat(status_text, frames_text, sizeof(status_text));
32031       }
32032 
32033       if (video_info.memory_show)
32034       {
32035          char mem[128];
32036 
32037          if ((p_rarch->video_driver_frame_count % memory_update_interval) == 0)
32038          {
32039             last_total_memory = frontend_driver_get_total_memory();
32040             last_used_memory  = last_total_memory - frontend_driver_get_free_memory();
32041          }
32042 
32043          mem[0] = '\0';
32044          snprintf(
32045                mem, sizeof(mem), "MEM: %.2f/%.2fMB", last_used_memory / (1024.0f * 1024.0f),
32046                last_total_memory / (1024.0f * 1024.0f));
32047          if (status_text[buf_pos-1] != '\0')
32048             strlcat(status_text, " || ", sizeof(status_text));
32049          strlcat(status_text, mem, sizeof(status_text));
32050       }
32051 
32052       if ((p_rarch->video_driver_frame_count % fps_update_interval) == 0)
32053       {
32054          last_fps = TIME_TO_FPS(curr_time, new_time,
32055                fps_update_interval);
32056 
32057          strlcpy(p_rarch->video_driver_window_title,
32058                p_rarch->video_driver_title_buf,
32059                sizeof(p_rarch->video_driver_window_title));
32060 
32061          if (!string_is_empty(status_text))
32062          {
32063             strlcat(p_rarch->video_driver_window_title,
32064                   " || ", sizeof(p_rarch->video_driver_window_title));
32065             strlcat(p_rarch->video_driver_window_title,
32066                   status_text, sizeof(p_rarch->video_driver_window_title));
32067          }
32068 
32069          curr_time                                 = new_time;
32070          p_rarch->video_driver_window_title_update = true;
32071       }
32072    }
32073    else
32074    {
32075       curr_time = fps_time = new_time;
32076 
32077       strlcpy(p_rarch->video_driver_window_title,
32078             p_rarch->video_driver_title_buf,
32079             sizeof(p_rarch->video_driver_window_title));
32080 
32081       if (video_info.fps_show)
32082          strlcpy(status_text,
32083                msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
32084                sizeof(status_text));
32085 
32086       p_rarch->video_driver_window_title_update = true;
32087    }
32088 
32089    /* Add core status message to status text */
32090    if (video_info.core_status_msg_show)
32091    {
32092       /* Note: We need to lock a mutex here. Strictly
32093        * speaking, runloop_core_status_msg is not part
32094        * of the message queue, but:
32095        * - It may be implemented as a queue in the future
32096        * - It seems unnecessary to create a new slock_t
32097        *   object for this type of message when
32098        *   _runloop_msg_queue_lock is already available
32099        * We therefore just call runloop_msg_queue_lock()/
32100        * runloop_msg_queue_unlock() in this case */
32101       RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
32102 
32103       /* Check whether duration timer has elapsed */
32104       runloop_core_status_msg.duration -= p_rarch->anim.delta_time;
32105 
32106       if (runloop_core_status_msg.duration < 0.0f)
32107       {
32108          runloop_core_status_msg.str[0]   = '\0';
32109          runloop_core_status_msg.priority = 0;
32110          runloop_core_status_msg.duration = 0.0f;
32111          runloop_core_status_msg.set      = false;
32112       }
32113       else
32114       {
32115          /* If status text is already set, add status
32116           * message at the end */
32117          if (!string_is_empty(status_text))
32118          {
32119             strlcat(status_text,
32120                   " || ", sizeof(status_text));
32121             strlcat(status_text,
32122                   runloop_core_status_msg.str, sizeof(status_text));
32123          }
32124          else
32125             strlcpy(status_text, runloop_core_status_msg.str,
32126                   sizeof(status_text));
32127       }
32128 
32129       RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
32130    }
32131 
32132    /* Slightly messy code,
32133     * but we really need to do processing before blocking on VSync
32134     * for best possible scheduling.
32135     */
32136    if (
32137          (
32138 #ifdef HAVE_VIDEO_FILTER
32139              !p_rarch->video_driver_state_filter ||
32140 #endif
32141              !video_info.post_filter_record
32142           || !data
32143           || p_rarch->video_driver_record_gpu_buffer
32144          ) && p_rarch->recording_data
32145            && p_rarch->recording_driver
32146            && p_rarch->recording_driver->push_video)
32147       recording_dump_frame(p_rarch,
32148             data, width, height,
32149             pitch, runloop_idle);
32150 
32151 #ifdef HAVE_VIDEO_FILTER
32152    if (data && p_rarch->video_driver_state_filter)
32153    {
32154       unsigned output_width                             = 0;
32155       unsigned output_height                            = 0;
32156       unsigned output_pitch                             = 0;
32157 
32158       rarch_softfilter_get_output_size(p_rarch->video_driver_state_filter,
32159             &output_width, &output_height, width, height);
32160 
32161       output_pitch = (output_width) * p_rarch->video_driver_state_out_bpp;
32162 
32163       rarch_softfilter_process(p_rarch->video_driver_state_filter,
32164             p_rarch->video_driver_state_buffer, output_pitch,
32165             data, width, height, pitch);
32166 
32167       if (video_info.post_filter_record
32168             && p_rarch->recording_data
32169             && p_rarch->recording_driver
32170             && p_rarch->recording_driver->push_video)
32171          recording_dump_frame(p_rarch,
32172                p_rarch->video_driver_state_buffer,
32173                output_width, output_height, output_pitch,
32174                runloop_idle);
32175 
32176       data   = p_rarch->video_driver_state_buffer;
32177       width  = output_width;
32178       height = output_height;
32179       pitch  = output_pitch;
32180    }
32181 #endif
32182 
32183    if (runloop_state.msg_queue_size > 0)
32184    {
32185       /* If widgets are currently enabled, then
32186        * messages were pushed to the queue before
32187        * widgets were initialised - in this case, the
32188        * first item in the message queue should be
32189        * extracted and pushed to the widget message
32190        * queue instead */
32191 #if defined(HAVE_GFX_WIDGETS)
32192       if (widgets_active)
32193       {
32194          msg_queue_entry_t msg_entry;
32195          bool msg_found = false;
32196 
32197          RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
32198          msg_found                       = msg_queue_extract(
32199                &runloop_state.msg_queue, &msg_entry);
32200          runloop_state.msg_queue_size = msg_queue_size(
32201                &runloop_state.msg_queue);
32202          RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
32203 
32204          if (msg_found)
32205             gfx_widgets_msg_queue_push(
32206                   &p_rarch->dispwidget_st,
32207                   NULL,
32208                   msg_entry.msg,
32209                   roundf((float)msg_entry.duration / 60.0f * 1000.0f),
32210                   msg_entry.title,
32211                   msg_entry.icon,
32212                   msg_entry.category,
32213                   msg_entry.prio,
32214                   false,
32215 #ifdef HAVE_MENU
32216                   p_rarch->menu_driver_alive
32217 #else
32218                   false
32219 #endif
32220             );
32221       }
32222       /* ...otherwise, just output message via
32223        * regular OSD notification text (if enabled) */
32224       else if (video_info.font_enable)
32225 #else
32226       if (video_info.font_enable)
32227 #endif
32228       {
32229          const char *msg                 = NULL;
32230          RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
32231          msg                             = msg_queue_pull(&runloop_state.msg_queue);
32232          runloop_state.msg_queue_size = msg_queue_size(&runloop_state.msg_queue);
32233          if (msg)
32234             strlcpy(video_driver_msg, msg, sizeof(video_driver_msg));
32235          RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
32236       }
32237    }
32238 
32239    if (video_info.statistics_show)
32240    {
32241       audio_statistics_t audio_stats;
32242       double stddev                          = 0.0;
32243       struct retro_system_av_info *av_info   = &p_rarch->video_driver_av_info;
32244       unsigned red                           = 255;
32245       unsigned green                         = 255;
32246       unsigned blue                          = 255;
32247       unsigned alpha                         = 255;
32248 
32249       audio_stats.samples                    = 0;
32250       audio_stats.average_buffer_saturation  = 0.0f;
32251       audio_stats.std_deviation_percentage   = 0.0f;
32252       audio_stats.close_to_underrun          = 0.0f;
32253       audio_stats.close_to_blocking          = 0.0f;
32254 
32255       video_monitor_fps_statistics(NULL, &stddev, NULL);
32256 
32257       video_info.osd_stat_params.x           = 0.010f;
32258       video_info.osd_stat_params.y           = 0.950f;
32259       video_info.osd_stat_params.scale       = 1.0f;
32260       video_info.osd_stat_params.full_screen = true;
32261       video_info.osd_stat_params.drop_x      = -2;
32262       video_info.osd_stat_params.drop_y      = -2;
32263       video_info.osd_stat_params.drop_mod    = 0.3f;
32264       video_info.osd_stat_params.drop_alpha  = 1.0f;
32265       video_info.osd_stat_params.color       = COLOR_ABGR(
32266             red, green, blue, alpha);
32267 
32268       audio_compute_buffer_statistics(p_rarch, &audio_stats);
32269 
32270       snprintf(video_info.stat_text,
32271             sizeof(video_info.stat_text),
32272             "Video Statistics:\n -Frame rate: %6.2f fps\n -Frame time: %6.2f ms\n -Frame time deviation: %.3f %%\n"
32273             " -Frame count: %" PRIu64"\n -Viewport: %d x %d x %3.2f\n"
32274             "Audio Statistics:\n -Average buffer saturation: %.2f %%\n -Standard deviation: %.2f %%\n -Time spent close to underrun: %.2f %%\n -Time spent close to blocking: %.2f %%\n -Sample count: %d\n"
32275             "Core Geometry:\n -Size: %u x %u\n -Max Size: %u x %u\n -Aspect: %3.2f\nCore Timing:\n -FPS: %3.2f\n -Sample Rate: %6.2f\n",
32276             last_fps,
32277             frame_time / 1000.0f,
32278             100.0f * stddev,
32279             p_rarch->video_driver_frame_count,
32280             video_info.width,
32281             video_info.height,
32282             video_info.refresh_rate,
32283             audio_stats.average_buffer_saturation,
32284             audio_stats.std_deviation_percentage,
32285             audio_stats.close_to_underrun,
32286             audio_stats.close_to_blocking,
32287             audio_stats.samples,
32288             av_info->geometry.base_width,
32289             av_info->geometry.base_height,
32290             av_info->geometry.max_width,
32291             av_info->geometry.max_height,
32292             av_info->geometry.aspect_ratio,
32293             av_info->timing.fps,
32294             av_info->timing.sample_rate);
32295 
32296       /* TODO/FIXME - add OSD chat text here */
32297    }
32298 
32299    if (p_rarch->current_video && p_rarch->current_video->frame)
32300       p_rarch->video_driver_active = p_rarch->current_video->frame(
32301             p_rarch->video_driver_data, data, width, height,
32302             p_rarch->video_driver_frame_count, (unsigned)pitch,
32303             video_info.menu_screensaver_active ? "" : video_driver_msg,
32304             &video_info);
32305 
32306    p_rarch->video_driver_frame_count++;
32307 
32308    /* Display the status text, with a higher priority. */
32309    if (  (   video_info.fps_show
32310           || video_info.framecount_show
32311           || video_info.memory_show
32312           || video_info.core_status_msg_show
32313          )
32314        && !video_info.menu_screensaver_active
32315       )
32316    {
32317 #if defined(HAVE_GFX_WIDGETS)
32318       if (widgets_active)
32319          strlcpy(
32320                p_rarch->dispwidget_st.gfx_widgets_status_text,
32321                status_text,
32322                sizeof(p_rarch->dispwidget_st.gfx_widgets_status_text)
32323                );
32324       else
32325 #endif
32326       {
32327          runloop_msg_queue_push(status_text, 2, 1, true, NULL,
32328                MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
32329       }
32330    }
32331 
32332 #if defined(HAVE_CRTSWITCHRES)
32333    /* trigger set resolution*/
32334    if (video_info.crt_switch_resolution)
32335    {
32336       unsigned native_width                      = width;
32337       bool dynamic_super_width                   = false;
32338 
32339       p_rarch->video_driver_crt_switching_active = true;
32340 
32341       switch (video_info.crt_switch_resolution_super)
32342       {
32343          case 2560:
32344          case 3840:
32345          case 1920:
32346             width               = video_info.crt_switch_resolution_super;
32347             dynamic_super_width = false;
32348             break;
32349          case 1:
32350             dynamic_super_width = true;
32351             break;
32352          default:
32353             break;
32354       }
32355 
32356       crt_switch_res_core(
32357             &p_rarch->crt_switch_st,
32358             native_width, width,
32359             height,
32360             p_rarch->video_driver_core_hz,
32361             video_info.crt_switch_resolution,
32362             video_info.crt_switch_center_adjust,
32363             video_info.crt_switch_porch_adjust,
32364             video_info.monitor_index,
32365             dynamic_super_width,
32366             video_info.crt_switch_resolution_super,
32367             video_info.crt_switch_hires_menu);
32368    }
32369    else if (!video_info.crt_switch_resolution)
32370 #endif
32371       p_rarch->video_driver_crt_switching_active = false;
32372 }
32373 
crt_switch_driver_refresh(void)32374 void crt_switch_driver_refresh(void)
32375 {
32376    /*video_context_driver_reset();*/
32377    video_driver_reinit(DRIVERS_CMD_ALL);
32378 }
32379 
crt_switch_core_name(void)32380 char* crt_switch_core_name(void)
32381 {
32382    return (char*)runloop_state.system.info.library_name;
32383 }
32384 
video_driver_display_type_set(enum rarch_display_type type)32385 void video_driver_display_type_set(enum rarch_display_type type)
32386 {
32387    struct rarch_state            *p_rarch = &rarch_st;
32388    p_rarch->video_driver_display_type     = type;
32389 }
32390 
video_driver_display_get(void)32391 uintptr_t video_driver_display_get(void)
32392 {
32393    struct rarch_state *p_rarch = &rarch_st;
32394    return p_rarch->video_driver_display;
32395 }
32396 
video_driver_display_userdata_get(void)32397 uintptr_t video_driver_display_userdata_get(void)
32398 {
32399    struct rarch_state *p_rarch = &rarch_st;
32400    return p_rarch->video_driver_display_userdata;
32401 }
32402 
video_driver_display_userdata_set(uintptr_t idx)32403 void video_driver_display_userdata_set(uintptr_t idx)
32404 {
32405    struct rarch_state            *p_rarch = &rarch_st;
32406    p_rarch->video_driver_display_userdata = idx;
32407 }
32408 
video_driver_display_set(uintptr_t idx)32409 void video_driver_display_set(uintptr_t idx)
32410 {
32411    struct rarch_state   *p_rarch = &rarch_st;
32412    p_rarch->video_driver_display = idx;
32413 }
32414 
video_driver_display_type_get(void)32415 enum rarch_display_type video_driver_display_type_get(void)
32416 {
32417    struct rarch_state            *p_rarch = &rarch_st;
32418    return p_rarch->video_driver_display_type;
32419 }
32420 
video_driver_window_set(uintptr_t idx)32421 void video_driver_window_set(uintptr_t idx)
32422 {
32423    struct rarch_state *p_rarch = &rarch_st;
32424    p_rarch->video_driver_window = idx;
32425 }
32426 
video_driver_window_get(void)32427 uintptr_t video_driver_window_get(void)
32428 {
32429    struct rarch_state *p_rarch = &rarch_st;
32430    return p_rarch->video_driver_window;
32431 }
32432 
video_driver_texture_load(void * data,enum texture_filter_type filter_type,uintptr_t * id)32433 bool video_driver_texture_load(void *data,
32434       enum texture_filter_type  filter_type,
32435       uintptr_t *id)
32436 {
32437    struct rarch_state *p_rarch = &rarch_st;
32438    if (     !id
32439          || !p_rarch->video_driver_poke
32440          || !p_rarch->video_driver_poke->load_texture)
32441       return false;
32442    *id = p_rarch->video_driver_poke->load_texture(
32443          p_rarch->video_driver_data, data,
32444          VIDEO_DRIVER_IS_THREADED_INTERNAL(),
32445          filter_type);
32446    return true;
32447 }
32448 
video_driver_texture_unload(uintptr_t * id)32449 bool video_driver_texture_unload(uintptr_t *id)
32450 {
32451    struct rarch_state *p_rarch = &rarch_st;
32452    if (     !p_rarch->video_driver_poke
32453          || !p_rarch->video_driver_poke->unload_texture)
32454       return false;
32455    p_rarch->video_driver_poke->unload_texture(
32456          p_rarch->video_driver_data,
32457          VIDEO_DRIVER_IS_THREADED_INTERNAL(),
32458          *id);
32459    *id = 0;
32460    return true;
32461 }
32462 
video_driver_build_info(video_frame_info_t * video_info)32463 void video_driver_build_info(video_frame_info_t *video_info)
32464 {
32465    video_viewport_t *custom_vp             = NULL;
32466    struct rarch_state       *p_rarch       = &rarch_st;
32467    settings_t *settings                    = p_rarch->configuration_settings;
32468 #ifdef HAVE_THREADS
32469    bool is_threaded                        =
32470       VIDEO_DRIVER_IS_THREADED_INTERNAL();
32471 
32472    VIDEO_DRIVER_THREADED_LOCK(is_threaded);
32473 #endif
32474    custom_vp                               = &settings->video_viewport_custom;
32475 #ifdef HAVE_GFX_WIDGETS
32476    video_info->widgets_active              = p_rarch->widgets_active;
32477 #else
32478    video_info->widgets_active              = false;
32479 #endif
32480    video_info->refresh_rate                = settings->floats.video_refresh_rate;
32481    video_info->crt_switch_resolution       = settings->uints.crt_switch_resolution;
32482    video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super;
32483    video_info->crt_switch_center_adjust    = settings->ints.crt_switch_center_adjust;
32484    video_info->crt_switch_porch_adjust     = settings->ints.crt_switch_porch_adjust;
32485    video_info->crt_switch_hires_menu       = settings->bools.crt_switch_hires_menu;
32486    video_info->black_frame_insertion       = settings->uints.video_black_frame_insertion;
32487    video_info->hard_sync                   = settings->bools.video_hard_sync;
32488    video_info->hard_sync_frames            = settings->uints.video_hard_sync_frames;
32489    video_info->fps_show                    = settings->bools.video_fps_show;
32490    video_info->memory_show                 = settings->bools.video_memory_show;
32491    video_info->statistics_show             = settings->bools.video_statistics_show;
32492    video_info->framecount_show             = settings->bools.video_framecount_show;
32493    video_info->core_status_msg_show        = runloop_core_status_msg.set;
32494    video_info->aspect_ratio_idx            = settings->uints.video_aspect_ratio_idx;
32495    video_info->post_filter_record          = settings->bools.video_post_filter_record;
32496    video_info->input_menu_swap_ok_cancel_buttons    = settings->bools.input_menu_swap_ok_cancel_buttons;
32497    video_info->max_swapchain_images        = settings->uints.video_max_swapchain_images;
32498    video_info->windowed_fullscreen         = settings->bools.video_windowed_fullscreen;
32499    video_info->fullscreen                  = settings->bools.video_fullscreen
32500       || p_rarch->rarch_force_fullscreen;
32501    video_info->menu_mouse_enable           = settings->bools.menu_mouse_enable;
32502    video_info->monitor_index               = settings->uints.video_monitor_index;
32503 
32504    video_info->font_enable                 = settings->bools.video_font_enable;
32505    video_info->font_msg_pos_x              = settings->floats.video_msg_pos_x;
32506    video_info->font_msg_pos_y              = settings->floats.video_msg_pos_y;
32507    video_info->font_msg_color_r            = settings->floats.video_msg_color_r;
32508    video_info->font_msg_color_g            = settings->floats.video_msg_color_g;
32509    video_info->font_msg_color_b            = settings->floats.video_msg_color_b;
32510    video_info->custom_vp_x                 = custom_vp->x;
32511    video_info->custom_vp_y                 = custom_vp->y;
32512    video_info->custom_vp_width             = custom_vp->width;
32513    video_info->custom_vp_height            = custom_vp->height;
32514    video_info->custom_vp_full_width        = custom_vp->full_width;
32515    video_info->custom_vp_full_height       = custom_vp->full_height;
32516 
32517 #if defined(HAVE_GFX_WIDGETS)
32518    video_info->widgets_userdata            = &p_rarch->dispwidget_st;
32519    video_info->widgets_is_paused           = p_rarch->gfx_widgets_paused;
32520    video_info->widgets_is_fast_forwarding  = p_rarch->gfx_widgets_fast_forward;
32521    video_info->widgets_is_rewinding        = p_rarch->gfx_widgets_rewinding;
32522 #else
32523    video_info->widgets_userdata            = NULL;
32524    video_info->widgets_is_paused           = false;
32525    video_info->widgets_is_fast_forwarding  = false;
32526    video_info->widgets_is_rewinding        = false;
32527 #endif
32528 
32529    video_info->width                       = p_rarch->video_driver_width;
32530    video_info->height                      = p_rarch->video_driver_height;
32531 
32532    video_info->use_rgba                    = p_rarch->video_driver_use_rgba;
32533 
32534    video_info->libretro_running            = false;
32535    video_info->msg_bgcolor_enable          =
32536       settings->bools.video_msg_bgcolor_enable;
32537 
32538    video_info->fps_update_interval         = settings->uints.fps_update_interval;
32539    video_info->memory_update_interval      = settings->uints.memory_update_interval;
32540 
32541 #ifdef HAVE_MENU
32542    video_info->menu_is_alive               = p_rarch->menu_driver_alive;
32543    video_info->menu_screensaver_active     = p_rarch->menu_driver_state.screensaver_active;
32544    video_info->menu_footer_opacity         = settings->floats.menu_footer_opacity;
32545    video_info->menu_header_opacity         = settings->floats.menu_header_opacity;
32546    video_info->materialui_color_theme      = settings->uints.menu_materialui_color_theme;
32547    video_info->ozone_color_theme           = settings->uints.menu_ozone_color_theme;
32548    video_info->menu_shader_pipeline        = settings->uints.menu_xmb_shader_pipeline;
32549    video_info->xmb_theme                   = settings->uints.menu_xmb_theme;
32550    video_info->xmb_color_theme             = settings->uints.menu_xmb_color_theme;
32551    video_info->timedate_enable             = settings->bools.menu_timedate_enable;
32552    video_info->battery_level_enable        = settings->bools.menu_battery_level_enable;
32553    video_info->xmb_shadows_enable          =
32554       settings->bools.menu_xmb_shadows_enable;
32555    video_info->xmb_alpha_factor            =
32556       settings->uints.menu_xmb_alpha_factor;
32557    video_info->menu_wallpaper_opacity      =
32558       settings->floats.menu_wallpaper_opacity;
32559    video_info->menu_framebuffer_opacity    =
32560       settings->floats.menu_framebuffer_opacity;
32561 
32562    video_info->libretro_running            = p_rarch->current_core.game_loaded;
32563 #else
32564    video_info->menu_is_alive               = false;
32565    video_info->menu_screensaver_active     = false;
32566    video_info->menu_footer_opacity         = 0.0f;
32567    video_info->menu_header_opacity         = 0.0f;
32568    video_info->materialui_color_theme      = 0;
32569    video_info->menu_shader_pipeline        = 0;
32570    video_info->xmb_color_theme             = 0;
32571    video_info->xmb_theme                   = 0;
32572    video_info->timedate_enable             = false;
32573    video_info->battery_level_enable        = false;
32574    video_info->xmb_shadows_enable          = false;
32575    video_info->xmb_alpha_factor            = 0.0f;
32576    video_info->menu_framebuffer_opacity    = 0.0f;
32577    video_info->menu_wallpaper_opacity      = 0.0f;
32578 #endif
32579 
32580    video_info->runloop_is_paused           = runloop_state.paused;
32581    video_info->runloop_is_slowmotion       = runloop_state.slowmotion;
32582 
32583    video_info->input_driver_nonblock_state = p_rarch->input_driver_nonblock_state;
32584    video_info->input_driver_grab_mouse_state = p_rarch->input_driver_grab_mouse_state;
32585    video_info->disp_userdata               = &p_rarch->dispgfx;
32586 
32587    video_info->userdata                    = VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch);
32588 
32589 #ifdef HAVE_THREADS
32590    VIDEO_DRIVER_THREADED_UNLOCK(is_threaded);
32591 #endif
32592 }
32593 
32594 /**
32595  * video_driver_translate_coord_viewport:
32596  * @mouse_x                        : Pointer X coordinate.
32597  * @mouse_y                        : Pointer Y coordinate.
32598  * @res_x                          : Scaled  X coordinate.
32599  * @res_y                          : Scaled  Y coordinate.
32600  * @res_screen_x                   : Scaled screen X coordinate.
32601  * @res_screen_y                   : Scaled screen Y coordinate.
32602  *
32603  * Translates pointer [X,Y] coordinates into scaled screen
32604  * coordinates based on viewport info.
32605  *
32606  * Returns: true (1) if successful, false if video driver doesn't support
32607  * viewport info.
32608  **/
video_driver_translate_coord_viewport(struct video_viewport * vp,int mouse_x,int mouse_y,int16_t * res_x,int16_t * res_y,int16_t * res_screen_x,int16_t * res_screen_y)32609 bool video_driver_translate_coord_viewport(
32610       struct video_viewport *vp,
32611       int mouse_x,           int mouse_y,
32612       int16_t *res_x,        int16_t *res_y,
32613       int16_t *res_screen_x, int16_t *res_screen_y)
32614 {
32615    int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y;
32616    int norm_vp_width         = (int)vp->width;
32617    int norm_vp_height        = (int)vp->height;
32618    int norm_full_vp_width    = (int)vp->full_width;
32619    int norm_full_vp_height   = (int)vp->full_height;
32620    if (norm_vp_width <= 0 ||
32621        norm_vp_height <= 0 ||
32622        norm_full_vp_width <= 0 ||
32623        norm_full_vp_height <= 0)
32624       return false;
32625 
32626    if (mouse_x >= 0 && mouse_x <= norm_full_vp_width)
32627       scaled_screen_x = ((2 * mouse_x * 0x7fff)
32628             / norm_full_vp_width)  - 0x7fff;
32629    else
32630       scaled_screen_x = -0x8000; /* OOB */
32631 
32632    if (mouse_y >= 0 && mouse_y <= norm_full_vp_height)
32633       scaled_screen_y = ((2 * mouse_y * 0x7fff)
32634             / norm_full_vp_height) - 0x7fff;
32635    else
32636       scaled_screen_y = -0x8000; /* OOB */
32637 
32638    mouse_x           -= vp->x;
32639    mouse_y           -= vp->y;
32640 
32641    if (mouse_x >= 0 && mouse_x <= norm_vp_width)
32642       scaled_x        = ((2 * mouse_x * 0x7fff)
32643             / norm_vp_width) - 0x7fff;
32644    else
32645       scaled_x        = -0x8000; /* OOB */
32646 
32647    if (mouse_y >= 0 && mouse_y <= norm_vp_height)
32648       scaled_y        = ((2 * mouse_y * 0x7fff)
32649             / norm_vp_height) - 0x7fff;
32650    else
32651       scaled_y        = -0x8000; /* OOB */
32652 
32653    *res_x             = scaled_x;
32654    *res_y             = scaled_y;
32655    *res_screen_x      = scaled_screen_x;
32656    *res_screen_y      = scaled_screen_y;
32657    return true;
32658 }
32659 
video_driver_has_focus(void)32660 bool video_driver_has_focus(void)
32661 {
32662    struct rarch_state *p_rarch = &rarch_st;
32663    return VIDEO_HAS_FOCUS(p_rarch);
32664 }
32665 
video_driver_get_window_title(char * buf,unsigned len)32666 void video_driver_get_window_title(char *buf, unsigned len)
32667 {
32668    struct rarch_state *p_rarch  = &rarch_st;
32669 
32670    if (buf && p_rarch->video_driver_window_title_update)
32671    {
32672       struct rarch_state *p_rarch = &rarch_st;
32673       strlcpy(buf, p_rarch->video_driver_window_title, len);
32674       p_rarch->video_driver_window_title_update = false;
32675    }
32676 }
32677 
32678 /**
32679  * video_context_driver_init:
32680  * @data                    : Input data.
32681  * @ctx                     : Graphics context driver to initialize.
32682  * @ident                   : Identifier of graphics context driver to find.
32683  * @api                     : API of higher-level graphics API.
32684  * @major                   : Major version number of higher-level graphics API.
32685  * @minor                   : Minor version number of higher-level graphics API.
32686  * @hw_render_ctx           : Request a graphics context driver capable of
32687  *                            hardware rendering?
32688  *
32689  * Initialize graphics context driver.
32690  *
32691  * Returns: graphics context driver if successfully initialized,
32692  * otherwise NULL.
32693  **/
video_context_driver_init(struct rarch_state * p_rarch,settings_t * settings,void * data,const gfx_ctx_driver_t * ctx,const char * ident,enum gfx_ctx_api api,unsigned major,unsigned minor,bool hw_render_ctx,void ** ctx_data)32694 static const gfx_ctx_driver_t *video_context_driver_init(
32695       struct rarch_state *p_rarch,
32696       settings_t *settings,
32697       void *data,
32698       const gfx_ctx_driver_t *ctx,
32699       const char *ident,
32700       enum gfx_ctx_api api, unsigned major,
32701       unsigned minor, bool hw_render_ctx,
32702       void **ctx_data)
32703 {
32704    if (!ctx->bind_api(data, api, major, minor))
32705    {
32706       RARCH_WARN("Failed to bind API (#%u, version %u.%u)"
32707             " on context driver \"%s\".\n",
32708             (unsigned)api, major, minor, ctx->ident);
32709 
32710       return NULL;
32711    }
32712 
32713    if (!(*ctx_data = ctx->init(data)))
32714       return NULL;
32715 
32716    if (ctx->bind_hw_render)
32717    {
32718       bool  video_shared_context  =
32719          settings->bools.video_shared_context || p_rarch->core_set_shared_context;
32720 
32721       ctx->bind_hw_render(*ctx_data,
32722             video_shared_context && hw_render_ctx);
32723    }
32724 
32725    return ctx;
32726 }
32727 
32728 #ifdef HAVE_VULKAN
vk_context_driver_init_first(struct rarch_state * p_rarch,settings_t * settings,void * data,const char * ident,enum gfx_ctx_api api,unsigned major,unsigned minor,bool hw_render_ctx,void ** ctx_data)32729 static const gfx_ctx_driver_t *vk_context_driver_init_first(
32730       struct rarch_state *p_rarch,
32731       settings_t *settings,
32732       void *data,
32733       const char *ident, enum gfx_ctx_api api, unsigned major,
32734       unsigned minor, bool hw_render_ctx, void **ctx_data)
32735 {
32736    unsigned j;
32737    int i = -1;
32738 
32739    for (j = 0; gfx_ctx_vk_drivers[j]; j++)
32740    {
32741       if (string_is_equal_noncase(ident, gfx_ctx_vk_drivers[j]->ident))
32742       {
32743          i = j;
32744          break;
32745       }
32746    }
32747 
32748    if (i >= 0)
32749    {
32750       const gfx_ctx_driver_t *ctx = video_context_driver_init(p_rarch,
32751             settings,
32752             data,
32753             gfx_ctx_vk_drivers[i], ident,
32754             api, major, minor, hw_render_ctx, ctx_data);
32755       if (ctx)
32756       {
32757          p_rarch->video_context_data = *ctx_data;
32758          return ctx;
32759       }
32760    }
32761 
32762    for (i = 0; gfx_ctx_vk_drivers[i]; i++)
32763    {
32764       const gfx_ctx_driver_t *ctx =
32765          video_context_driver_init(
32766                p_rarch,
32767                settings,
32768                data,
32769                gfx_ctx_vk_drivers[i], ident,
32770                api, major, minor, hw_render_ctx, ctx_data);
32771 
32772       if (ctx)
32773       {
32774          p_rarch->video_context_data = *ctx_data;
32775          return ctx;
32776       }
32777    }
32778 
32779    return NULL;
32780 }
32781 #endif
32782 
gl_context_driver_init_first(struct rarch_state * p_rarch,settings_t * settings,void * data,const char * ident,enum gfx_ctx_api api,unsigned major,unsigned minor,bool hw_render_ctx,void ** ctx_data)32783 static const gfx_ctx_driver_t *gl_context_driver_init_first(
32784       struct rarch_state *p_rarch,
32785       settings_t *settings,
32786       void *data,
32787       const char *ident, enum gfx_ctx_api api, unsigned major,
32788       unsigned minor, bool hw_render_ctx, void **ctx_data)
32789 {
32790    unsigned j;
32791    int i = -1;
32792 
32793    for (j = 0; gfx_ctx_gl_drivers[j]; j++)
32794    {
32795       if (string_is_equal_noncase(ident, gfx_ctx_gl_drivers[j]->ident))
32796       {
32797          i = j;
32798          break;
32799       }
32800    }
32801 
32802    if (i >= 0)
32803    {
32804       const gfx_ctx_driver_t *ctx = video_context_driver_init(
32805             p_rarch,
32806             settings,
32807             data,
32808             gfx_ctx_gl_drivers[i], ident,
32809             api, major, minor, hw_render_ctx, ctx_data);
32810       if (ctx)
32811       {
32812          p_rarch->video_context_data = *ctx_data;
32813          return ctx;
32814       }
32815    }
32816 
32817    for (i = 0; gfx_ctx_gl_drivers[i]; i++)
32818    {
32819       const gfx_ctx_driver_t *ctx =
32820          video_context_driver_init(
32821                p_rarch,
32822                settings,
32823                data,
32824                gfx_ctx_gl_drivers[i], ident,
32825                api, major, minor, hw_render_ctx, ctx_data);
32826 
32827       if (ctx)
32828       {
32829          p_rarch->video_context_data = *ctx_data;
32830          return ctx;
32831       }
32832    }
32833 
32834    return NULL;
32835 }
32836 
32837 /**
32838  * video_context_driver_init_first:
32839  * @data                    : Input data.
32840  * @ident                   : Identifier of graphics context driver to find.
32841  * @api                     : API of higher-level graphics API.
32842  * @major                   : Major version number of higher-level graphics API.
32843  * @minor                   : Minor version number of higher-level graphics API.
32844  * @hw_render_ctx           : Request a graphics context driver capable of
32845  *                            hardware rendering?
32846  *
32847  * Finds first suitable graphics context driver and initializes.
32848  *
32849  * Returns: graphics context driver if found, otherwise NULL.
32850  **/
video_context_driver_init_first(void * data,const char * ident,enum gfx_ctx_api api,unsigned major,unsigned minor,bool hw_render_ctx,void ** ctx_data)32851 const gfx_ctx_driver_t *video_context_driver_init_first(void *data,
32852       const char *ident, enum gfx_ctx_api api, unsigned major,
32853       unsigned minor, bool hw_render_ctx, void **ctx_data)
32854 {
32855    struct rarch_state *p_rarch = &rarch_st;
32856    settings_t *settings        = p_rarch->configuration_settings;
32857 
32858    switch (api)
32859    {
32860       case GFX_CTX_VULKAN_API:
32861 #ifdef HAVE_VULKAN
32862          {
32863             const gfx_ctx_driver_t *ptr = vk_context_driver_init_first(
32864                   p_rarch, settings,
32865                   data, ident, api, major, minor, hw_render_ctx, ctx_data);
32866             if (ptr && !string_is_equal(ptr->ident, "null"))
32867                return ptr;
32868             /* fall-through if no valid driver was found */
32869          }
32870 #endif
32871       case GFX_CTX_OPENGL_API:
32872       case GFX_CTX_OPENGL_ES_API:
32873       case GFX_CTX_OPENVG_API:
32874       case GFX_CTX_METAL_API:
32875       case GFX_CTX_RSX_API:
32876          return gl_context_driver_init_first(
32877                p_rarch, settings,
32878                data, ident, api, major, minor,
32879                hw_render_ctx, ctx_data);
32880       case GFX_CTX_NONE:
32881       default:
32882          break;
32883    }
32884 
32885 
32886    return NULL;
32887 }
32888 
video_context_driver_free(void)32889 void video_context_driver_free(void)
32890 {
32891    struct rarch_state   *p_rarch = &rarch_st;
32892    video_context_driver_destroy_internal(&p_rarch->current_video_context);
32893    p_rarch->video_context_data    = NULL;
32894 }
32895 
video_context_driver_get_metrics(gfx_ctx_metrics_t * metrics)32896 bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics)
32897 {
32898    struct rarch_state *p_rarch   = &rarch_st;
32899    if (p_rarch && p_rarch->current_video_context.get_metrics)
32900       return p_rarch->current_video_context.get_metrics(
32901             p_rarch->video_context_data,
32902             metrics->type,
32903             metrics->value);
32904    return false;
32905 }
32906 
video_context_driver_get_refresh_rate(float * refresh_rate)32907 bool video_context_driver_get_refresh_rate(float *refresh_rate)
32908 {
32909    struct rarch_state *p_rarch = &rarch_st;
32910    if (!p_rarch->current_video_context.get_refresh_rate || !refresh_rate)
32911       return false;
32912    if (!p_rarch->video_context_data)
32913       return false;
32914 
32915    if (!p_rarch->video_driver_crt_switching_active)
32916    {
32917       if (refresh_rate)
32918          *refresh_rate =
32919              p_rarch->current_video_context.get_refresh_rate(
32920                    p_rarch->video_context_data);
32921    }
32922    else
32923    {
32924       float refresh_holder      = 0;
32925       if (refresh_rate)
32926          refresh_holder         =
32927              p_rarch->current_video_context.get_refresh_rate(
32928                    p_rarch->video_context_data);
32929 
32930       /* Fix for incorrect interlacing detection --
32931        * HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/
32932       if (refresh_holder != p_rarch->video_driver_core_hz)
32933          *refresh_rate          = p_rarch->video_driver_core_hz;
32934    }
32935 
32936    return true;
32937 }
32938 
video_context_driver_get_ident(gfx_ctx_ident_t * ident)32939 bool video_context_driver_get_ident(gfx_ctx_ident_t *ident)
32940 {
32941    struct rarch_state      *p_rarch = &rarch_st;
32942    if (!ident)
32943       return false;
32944    ident->ident = p_rarch->current_video_context.ident;
32945    return true;
32946 }
32947 
video_context_driver_get_flags(gfx_ctx_flags_t * flags)32948 bool video_context_driver_get_flags(gfx_ctx_flags_t *flags)
32949 {
32950    struct rarch_state *p_rarch = &rarch_st;
32951    if (!p_rarch->current_video_context.get_flags)
32952       return false;
32953 
32954    if (p_rarch->deferred_video_context_driver_set_flags)
32955    {
32956       flags->flags                                     =
32957          p_rarch->deferred_flag_data.flags;
32958       p_rarch->deferred_video_context_driver_set_flags = false;
32959       return true;
32960    }
32961 
32962    flags->flags = p_rarch->current_video_context.get_flags(
32963          p_rarch->video_context_data);
32964    return true;
32965 }
32966 
video_driver_get_flags(struct rarch_state * p_rarch,gfx_ctx_flags_t * flags)32967 static bool video_driver_get_flags(
32968       struct rarch_state *p_rarch,
32969       gfx_ctx_flags_t *flags)
32970 {
32971    if (!p_rarch->video_driver_poke || !p_rarch->video_driver_poke->get_flags)
32972       return false;
32973    flags->flags = p_rarch->video_driver_poke->get_flags(p_rarch->video_driver_data);
32974    return true;
32975 }
32976 
video_driver_get_flags_wrapper(void)32977 gfx_ctx_flags_t video_driver_get_flags_wrapper(void)
32978 {
32979    gfx_ctx_flags_t flags;
32980    struct rarch_state *p_rarch = &rarch_st;
32981    flags.flags                 = 0;
32982 
32983    if (!video_driver_get_flags(p_rarch, &flags))
32984       video_context_driver_get_flags(&flags);
32985 
32986    return flags;
32987 }
32988 
32989 /**
32990  * video_driver_test_all_flags:
32991  * @testflag          : flag to test
32992  *
32993  * Poll both the video and context driver's flags and test
32994  * whether @testflag is set or not.
32995  **/
video_driver_test_all_flags(enum display_flags testflag)32996 bool video_driver_test_all_flags(enum display_flags testflag)
32997 {
32998    gfx_ctx_flags_t flags;
32999    struct rarch_state *p_rarch = &rarch_st;
33000 
33001    if (video_driver_get_flags(p_rarch, &flags))
33002       if (BIT32_GET(flags.flags, testflag))
33003          return true;
33004 
33005    if (video_context_driver_get_flags(&flags))
33006       if (BIT32_GET(flags.flags, testflag))
33007          return true;
33008 
33009    return false;
33010 }
33011 
video_context_driver_set_flags(gfx_ctx_flags_t * flags)33012 bool video_context_driver_set_flags(gfx_ctx_flags_t *flags)
33013 {
33014    struct rarch_state *p_rarch = &rarch_st;
33015    if (!flags)
33016       return false;
33017 
33018    if (p_rarch->current_video_context.set_flags)
33019    {
33020       p_rarch->current_video_context.set_flags(
33021             p_rarch->video_context_data, flags->flags);
33022       return true;
33023    }
33024 
33025    p_rarch->deferred_flag_data.flags                = flags->flags;
33026    p_rarch->deferred_video_context_driver_set_flags = true;
33027    return false;
33028 }
33029 
video_context_driver_get_api(void)33030 enum gfx_ctx_api video_context_driver_get_api(void)
33031 {
33032    struct rarch_state      *p_rarch = &rarch_st;
33033    enum gfx_ctx_api         ctx_api = p_rarch->video_context_data ?
33034       p_rarch->current_video_context.get_api(
33035             p_rarch->video_context_data) : GFX_CTX_NONE;
33036 
33037    if (ctx_api == GFX_CTX_NONE)
33038    {
33039       const char *video_ident  = (p_rarch->current_video)
33040          ? p_rarch->current_video->ident
33041          : NULL;
33042       if (string_starts_with_size(video_ident, "d3d", STRLEN_CONST("d3d")))
33043       {
33044          if (string_is_equal(video_ident, "d3d9"))
33045             return GFX_CTX_DIRECT3D9_API;
33046          else if (string_is_equal(video_ident, "d3d10"))
33047             return GFX_CTX_DIRECT3D10_API;
33048          else if (string_is_equal(video_ident, "d3d11"))
33049             return GFX_CTX_DIRECT3D11_API;
33050          else if (string_is_equal(video_ident, "d3d12"))
33051             return GFX_CTX_DIRECT3D12_API;
33052       }
33053       if (string_starts_with_size(video_ident, "gl", STRLEN_CONST("gl")))
33054       {
33055          if (string_is_equal(video_ident, "gl"))
33056             return GFX_CTX_OPENGL_API;
33057          else if (string_is_equal(video_ident, "gl1"))
33058             return GFX_CTX_OPENGL_API;
33059          else if (string_is_equal(video_ident, "glcore"))
33060             return GFX_CTX_OPENGL_API;
33061       }
33062       else if (string_is_equal(video_ident, "vulkan"))
33063          return GFX_CTX_VULKAN_API;
33064       else if (string_is_equal(video_ident, "metal"))
33065          return GFX_CTX_METAL_API;
33066 
33067       return GFX_CTX_NONE;
33068    }
33069 
33070    return ctx_api;
33071 }
33072 
video_driver_has_windowed(void)33073 bool video_driver_has_windowed(void)
33074 {
33075 #if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE))
33076    struct rarch_state      *p_rarch = &rarch_st;
33077    if (p_rarch->video_driver_data && p_rarch->current_video->has_windowed)
33078       return p_rarch->current_video->has_windowed(p_rarch->video_driver_data);
33079 #endif
33080    return false;
33081 }
33082 
video_driver_cached_frame_has_valid_framebuffer(void)33083 bool video_driver_cached_frame_has_valid_framebuffer(void)
33084 {
33085    struct rarch_state *p_rarch = &rarch_st;
33086    if (p_rarch->frame_cache_data)
33087       return (p_rarch->frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID);
33088    return false;
33089 }
33090 
33091 
video_shader_driver_get_current_shader(video_shader_ctx_t * shader)33092 bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader)
33093 {
33094    struct rarch_state              *p_rarch = &rarch_st;
33095    void *video_driver                       = p_rarch->video_driver_data;
33096    const video_poke_interface_t *video_poke = p_rarch->video_driver_poke;
33097 
33098    shader->data = NULL;
33099    if (!video_poke || !video_driver || !video_poke->get_current_shader)
33100       return false;
33101    shader->data = video_poke->get_current_shader(video_driver);
33102    return true;
33103 }
33104 
video_driver_get_refresh_rate(void)33105 float video_driver_get_refresh_rate(void)
33106 {
33107    struct rarch_state *p_rarch = &rarch_st;
33108    if (p_rarch->video_driver_poke && p_rarch->video_driver_poke->get_refresh_rate)
33109       return p_rarch->video_driver_poke->get_refresh_rate(p_rarch->video_driver_data);
33110 
33111    return 0.0f;
33112 }
33113 
33114 #if defined(HAVE_GFX_WIDGETS)
video_driver_has_widgets(void)33115 bool video_driver_has_widgets(void)
33116 {
33117    struct rarch_state *p_rarch = &rarch_st;
33118    return p_rarch->current_video
33119          && p_rarch->current_video->gfx_widgets_enabled
33120          && p_rarch->current_video->gfx_widgets_enabled(
33121                p_rarch->video_driver_data);
33122 }
33123 #endif
33124 
video_driver_set_gpu_device_string(const char * str)33125 void video_driver_set_gpu_device_string(const char *str)
33126 {
33127    struct rarch_state *p_rarch = &rarch_st;
33128    strlcpy(p_rarch->video_driver_gpu_device_string, str,
33129          sizeof(p_rarch->video_driver_gpu_device_string));
33130 }
33131 
video_driver_get_gpu_device_string(void)33132 const char* video_driver_get_gpu_device_string(void)
33133 {
33134    struct rarch_state *p_rarch = &rarch_st;
33135    return p_rarch->video_driver_gpu_device_string;
33136 }
33137 
video_driver_set_gpu_api_version_string(const char * str)33138 void video_driver_set_gpu_api_version_string(const char *str)
33139 {
33140    struct rarch_state *p_rarch = &rarch_st;
33141    strlcpy(p_rarch->video_driver_gpu_api_version_string, str,
33142          sizeof(p_rarch->video_driver_gpu_api_version_string));
33143 }
33144 
video_driver_get_gpu_api_version_string(void)33145 const char* video_driver_get_gpu_api_version_string(void)
33146 {
33147    struct rarch_state *p_rarch = &rarch_st;
33148    return p_rarch->video_driver_gpu_api_version_string;
33149 }
33150 
33151 /* string list stays owned by the caller and must be available at
33152  * all times after the video driver is inited */
video_driver_set_gpu_api_devices(enum gfx_ctx_api api,struct string_list * list)33153 void video_driver_set_gpu_api_devices(
33154       enum gfx_ctx_api api, struct string_list *list)
33155 {
33156    int i;
33157 
33158    for (i = 0; i < ARRAY_SIZE(gpu_map); i++)
33159    {
33160       if (api == gpu_map[i].api)
33161       {
33162          gpu_map[i].list = list;
33163          break;
33164       }
33165    }
33166 }
33167 
video_driver_get_gpu_api_devices(enum gfx_ctx_api api)33168 struct string_list* video_driver_get_gpu_api_devices(enum gfx_ctx_api api)
33169 {
33170    int i;
33171 
33172    for (i = 0; i < ARRAY_SIZE(gpu_map); i++)
33173    {
33174       if (api == gpu_map[i].api)
33175          return gpu_map[i].list;
33176    }
33177 
33178    return NULL;
33179 }
33180 
33181 
33182 /* LOCATION */
33183 
33184 /**
33185  * config_get_location_driver_options:
33186  *
33187  * Get an enumerated list of all location driver names,
33188  * separated by '|'.
33189  *
33190  * Returns: string listing of all location driver names,
33191  * separated by '|'.
33192  **/
config_get_location_driver_options(void)33193 const char *config_get_location_driver_options(void)
33194 {
33195    return char_list_new_special(STRING_LIST_LOCATION_DRIVERS, NULL);
33196 }
33197 
location_driver_find_driver(struct rarch_state * p_rarch,settings_t * settings,const char * prefix,bool verbosity_enabled)33198 static void location_driver_find_driver(struct rarch_state *p_rarch,
33199       settings_t *settings,
33200       const char *prefix,
33201       bool verbosity_enabled)
33202 {
33203    int i                        = (int)driver_find_index(
33204          "location_driver",
33205          settings->arrays.location_driver);
33206 
33207    if (i >= 0)
33208       p_rarch->location_driver  = (const location_driver_t*)location_drivers[i];
33209    else
33210    {
33211       if (verbosity_enabled)
33212       {
33213          unsigned d;
33214          RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
33215                settings->arrays.location_driver);
33216          RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
33217          for (d = 0; location_drivers[d]; d++)
33218             RARCH_LOG_OUTPUT("\t%s\n", location_drivers[d]->ident);
33219 
33220          RARCH_WARN("Going to default to first %s...\n", prefix);
33221       }
33222 
33223       p_rarch->location_driver = (const location_driver_t*)location_drivers[0];
33224 
33225       if (!p_rarch->location_driver)
33226          retroarch_fail(p_rarch, 1, "find_location_driver()");
33227    }
33228 }
33229 
33230 /**
33231  * driver_location_start:
33232  *
33233  * Starts location driver interface..
33234  * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
33235  *
33236  * Returns: true (1) if successful, otherwise false (0).
33237  **/
driver_location_start(void)33238 static bool driver_location_start(void)
33239 {
33240    struct rarch_state  *p_rarch = &rarch_st;
33241    if (     p_rarch->location_driver
33242          && p_rarch->location_data
33243          && p_rarch->location_driver->start)
33244    {
33245       settings_t *settings = p_rarch->configuration_settings;
33246       bool location_allow  = settings->bools.location_allow;
33247       if (location_allow)
33248          return p_rarch->location_driver->start(p_rarch->location_data);
33249 
33250       runloop_msg_queue_push("Location is explicitly disabled.\n",
33251             1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
33252             MESSAGE_QUEUE_CATEGORY_INFO);
33253    }
33254    return false;
33255 }
33256 
33257 /**
33258  * driver_location_stop:
33259  *
33260  * Stops location driver interface..
33261  * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
33262  *
33263  * Returns: true (1) if successful, otherwise false (0).
33264  **/
driver_location_stop(void)33265 static void driver_location_stop(void)
33266 {
33267    struct rarch_state  *p_rarch = &rarch_st;
33268    if (     p_rarch->location_driver
33269          && p_rarch->location_driver->stop
33270          && p_rarch->location_data)
33271       p_rarch->location_driver->stop(p_rarch->location_data);
33272 }
33273 
33274 /**
33275  * driver_location_set_interval:
33276  * @interval_msecs     : Interval time in milliseconds.
33277  * @interval_distance  : Distance at which to update.
33278  *
33279  * Sets interval update time for location driver interface.
33280  * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
33281  **/
driver_location_set_interval(unsigned interval_msecs,unsigned interval_distance)33282 static void driver_location_set_interval(unsigned interval_msecs,
33283       unsigned interval_distance)
33284 {
33285    struct rarch_state  *p_rarch = &rarch_st;
33286    if (     p_rarch->location_driver
33287          && p_rarch->location_driver->set_interval
33288          && p_rarch->location_data)
33289       p_rarch->location_driver->set_interval(p_rarch->location_data,
33290             interval_msecs, interval_distance);
33291 }
33292 
33293 /**
33294  * driver_location_get_position:
33295  * @lat                : Latitude of current position.
33296  * @lon                : Longitude of current position.
33297  * @horiz_accuracy     : Horizontal accuracy.
33298  * @vert_accuracy      : Vertical accuracy.
33299  *
33300  * Gets current positioning information from
33301  * location driver interface.
33302  * Used by RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE.
33303  *
33304  * Returns: bool (1) if successful, otherwise false (0).
33305  **/
driver_location_get_position(double * lat,double * lon,double * horiz_accuracy,double * vert_accuracy)33306 static bool driver_location_get_position(double *lat, double *lon,
33307       double *horiz_accuracy, double *vert_accuracy)
33308 {
33309    struct rarch_state  *p_rarch = &rarch_st;
33310    if (     p_rarch->location_driver
33311          && p_rarch->location_driver->get_position
33312          && p_rarch->location_data)
33313       return p_rarch->location_driver->get_position(p_rarch->location_data,
33314             lat, lon, horiz_accuracy, vert_accuracy);
33315 
33316    *lat            = 0.0;
33317    *lon            = 0.0;
33318    *horiz_accuracy = 0.0;
33319    *vert_accuracy  = 0.0;
33320    return false;
33321 }
33322 
init_location(struct rarch_state * p_rarch,rarch_system_info_t * system,settings_t * settings,bool verbosity_enabled)33323 static void init_location(
33324       struct rarch_state *p_rarch,
33325       rarch_system_info_t *system,
33326       settings_t *settings,
33327       bool verbosity_enabled)
33328 {
33329    /* Resource leaks will follow if location interface is initialized twice. */
33330    if (p_rarch->location_data)
33331       return;
33332 
33333    location_driver_find_driver(p_rarch, settings,
33334          "location driver", verbosity_enabled);
33335 
33336    p_rarch->location_data = p_rarch->location_driver->init();
33337 
33338    if (!p_rarch->location_data)
33339    {
33340       RARCH_ERR("Failed to initialize location driver. Will continue without location.\n");
33341       p_rarch->location_driver_active = false;
33342    }
33343 
33344    if (system->location_cb.initialized)
33345       system->location_cb.initialized();
33346 }
33347 
uninit_location(struct rarch_state * p_rarch,rarch_system_info_t * system)33348 static void uninit_location(
33349       struct rarch_state *p_rarch,
33350       rarch_system_info_t  *system
33351       )
33352 {
33353    if (p_rarch->location_data && p_rarch->location_driver)
33354    {
33355       if (system->location_cb.deinitialized)
33356          system->location_cb.deinitialized();
33357 
33358       if (p_rarch->location_driver->free)
33359          p_rarch->location_driver->free(p_rarch->location_data);
33360    }
33361 
33362    p_rarch->location_data = NULL;
33363 }
33364 
33365 /* CAMERA */
33366 
33367 /**
33368  * config_get_camera_driver_options:
33369  *
33370  * Get an enumerated list of all camera driver names,
33371  * separated by '|'.
33372  *
33373  * Returns: string listing of all camera driver names,
33374  * separated by '|'.
33375  **/
config_get_camera_driver_options(void)33376 const char *config_get_camera_driver_options(void)
33377 {
33378    return char_list_new_special(STRING_LIST_CAMERA_DRIVERS, NULL);
33379 }
33380 
driver_camera_start(void)33381 static bool driver_camera_start(void)
33382 {
33383    struct rarch_state  *p_rarch = &rarch_st;
33384    if (  p_rarch->camera_driver &&
33385          p_rarch->camera_data   &&
33386          p_rarch->camera_driver->start)
33387    {
33388       settings_t *settings = p_rarch->configuration_settings;
33389       bool camera_allow    = settings->bools.camera_allow;
33390       if (camera_allow)
33391          return p_rarch->camera_driver->start(p_rarch->camera_data);
33392 
33393       runloop_msg_queue_push(
33394             "Camera is explicitly disabled.\n", 1, 180, false,
33395             NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
33396    }
33397    return true;
33398 }
33399 
driver_camera_stop(void)33400 static void driver_camera_stop(void)
33401 {
33402    struct rarch_state  *p_rarch = &rarch_st;
33403    if (     p_rarch->camera_driver
33404          && p_rarch->camera_driver->stop
33405          && p_rarch->camera_data)
33406       p_rarch->camera_driver->stop(p_rarch->camera_data);
33407 }
33408 
camera_driver_find_driver(struct rarch_state * p_rarch,settings_t * settings,const char * prefix,bool verbosity_enabled)33409 static void camera_driver_find_driver(struct rarch_state *p_rarch,
33410       settings_t *settings,
33411       const char *prefix,
33412       bool verbosity_enabled)
33413 {
33414    int i                        = (int)driver_find_index(
33415          "camera_driver",
33416          settings->arrays.camera_driver);
33417 
33418    if (i >= 0)
33419       p_rarch->camera_driver = (const camera_driver_t*)camera_drivers[i];
33420    else
33421    {
33422       if (verbosity_enabled)
33423       {
33424          unsigned d;
33425          RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
33426                settings->arrays.camera_driver);
33427          RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
33428          for (d = 0; camera_drivers[d]; d++)
33429          {
33430             if (camera_drivers[d])
33431             {
33432                RARCH_LOG_OUTPUT("\t%s\n", camera_drivers[d]->ident);
33433             }
33434          }
33435 
33436          RARCH_WARN("Going to default to first %s...\n", prefix);
33437       }
33438 
33439       p_rarch->camera_driver = (const camera_driver_t*)camera_drivers[0];
33440 
33441       if (!p_rarch->camera_driver)
33442          retroarch_fail(p_rarch, 1, "find_camera_driver()");
33443    }
33444 }
33445 
driver_adjust_system_rates(struct rarch_state * p_rarch,bool vrr_runloop_enable,float video_refresh_rate,float audio_max_timing_skew,bool video_adaptive_vsync,unsigned video_swap_interval)33446 static void driver_adjust_system_rates(
33447       struct rarch_state *p_rarch,
33448       bool vrr_runloop_enable,
33449       float video_refresh_rate,
33450       float audio_max_timing_skew,
33451       bool video_adaptive_vsync,
33452       unsigned video_swap_interval)
33453 {
33454    struct retro_system_av_info *av_info   = &p_rarch->video_driver_av_info;
33455    const struct retro_system_timing *info =
33456       (const struct retro_system_timing*)&av_info->timing;
33457    double input_sample_rate               = info->sample_rate;
33458    double input_fps                       = info->fps;
33459 
33460    if (input_sample_rate > 0.0)
33461    {
33462       if (vrr_runloop_enable)
33463          p_rarch->audio_driver_input = input_sample_rate;
33464       else
33465          p_rarch->audio_driver_input =
33466             audio_driver_monitor_adjust_system_rates(
33467                   input_sample_rate,
33468                   input_fps,
33469                   video_refresh_rate,
33470                   video_swap_interval,
33471                   audio_max_timing_skew);
33472 
33473       RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
33474             p_rarch->audio_driver_input);
33475    }
33476 
33477    runloop_state.force_nonblock = false;
33478 
33479    if (input_fps > 0.0)
33480    {
33481       float timing_skew_hz          = video_refresh_rate;
33482 
33483       if (p_rarch->video_driver_crt_switching_active)
33484          timing_skew_hz             = input_fps;
33485       p_rarch->video_driver_core_hz = input_fps;
33486 
33487       if (!video_driver_monitor_adjust_system_rates(
33488          timing_skew_hz,
33489          video_refresh_rate,
33490          vrr_runloop_enable,
33491          audio_max_timing_skew,
33492          input_fps))
33493       {
33494          /* We won't be able to do VSync reliably when game FPS > monitor FPS. */
33495          runloop_state.force_nonblock = true;
33496          RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n");
33497 
33498          if (VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch))
33499          {
33500             if (p_rarch->current_video->set_nonblock_state)
33501                p_rarch->current_video->set_nonblock_state(
33502                      p_rarch->video_driver_data, true,
33503                      video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
33504                      video_adaptive_vsync,
33505                      video_swap_interval
33506                      );
33507          }
33508          return;
33509       }
33510    }
33511 
33512    if (VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch))
33513       driver_set_nonblock_state();
33514 }
33515 
33516 /**
33517  * driver_set_nonblock_state:
33518  *
33519  * Sets audio and video drivers to nonblock state (if enabled).
33520  *
33521  * If nonblock state is false, sets
33522  * blocking state for both audio and video drivers instead.
33523  **/
driver_set_nonblock_state(void)33524 void driver_set_nonblock_state(void)
33525 {
33526    struct rarch_state *p_rarch = &rarch_st;
33527    bool                 enable = p_rarch->input_driver_nonblock_state;
33528    settings_t       *settings  = p_rarch->configuration_settings;
33529    bool audio_sync             = settings->bools.audio_sync;
33530    bool video_vsync            = settings->bools.video_vsync;
33531    bool adaptive_vsync         = settings->bools.video_adaptive_vsync;
33532    unsigned swap_interval      = settings->uints.video_swap_interval;
33533    bool video_driver_active    = p_rarch->video_driver_active;
33534    bool audio_driver_active    = p_rarch->audio_driver_active;
33535    bool runloop_force_nonblock = runloop_state.force_nonblock;
33536 
33537    /* Only apply non-block-state for video if we're using vsync. */
33538    if (video_driver_active && VIDEO_DRIVER_GET_PTR_INTERNAL(p_rarch))
33539    {
33540       if (p_rarch->current_video->set_nonblock_state)
33541       {
33542          bool video_nonblock        = enable;
33543          if (!video_vsync || runloop_force_nonblock)
33544             video_nonblock = true;
33545          p_rarch->current_video->set_nonblock_state(p_rarch->video_driver_data,
33546                video_nonblock,
33547                video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
33548                adaptive_vsync, swap_interval);
33549       }
33550    }
33551 
33552    if (audio_driver_active && p_rarch->audio_driver_context_audio_data)
33553       p_rarch->current_audio->set_nonblock_state(
33554             p_rarch->audio_driver_context_audio_data,
33555             audio_sync ? enable : true);
33556 
33557    p_rarch->audio_driver_chunk_size = enable
33558       ? p_rarch->audio_driver_chunk_nonblock_size
33559       : p_rarch->audio_driver_chunk_block_size;
33560 }
33561 
33562 /**
33563  * drivers_init:
33564  * @flags              : Bitmask of drivers to initialize.
33565  *
33566  * Initializes drivers.
33567  * @flags determines which drivers get initialized.
33568  **/
drivers_init(struct rarch_state * p_rarch,settings_t * settings,int flags,bool verbosity_enabled)33569 static void drivers_init(struct rarch_state *p_rarch,
33570       settings_t *settings,
33571       int flags,
33572       bool verbosity_enabled)
33573 {
33574 #ifdef HAVE_MENU
33575    struct menu_state  *menu_st = &p_rarch->menu_driver_state;
33576 #endif
33577    bool video_is_threaded      = VIDEO_DRIVER_IS_THREADED_INTERNAL();
33578    gfx_display_t *p_disp       = &p_rarch->dispgfx;
33579 #if defined(HAVE_GFX_WIDGETS)
33580    bool video_font_enable      = settings->bools.video_font_enable;
33581    bool menu_enable_widgets    = settings->bools.menu_enable_widgets;
33582 
33583    /* By default, we want display widgets to persist through driver reinits. */
33584    p_rarch->widgets_persisting = true;
33585 #endif
33586 
33587 #ifdef HAVE_MENU
33588    /* By default, we want the menu to persist through driver reinits. */
33589    if (menu_st)
33590       menu_st->data_own = true;
33591 #endif
33592 
33593    if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
33594       driver_adjust_system_rates(p_rarch,
33595                                  settings->bools.vrr_runloop_enable,
33596                                  settings->floats.video_refresh_rate,
33597                                  settings->floats.audio_max_timing_skew,
33598                                  settings->bools.video_adaptive_vsync,
33599                                  settings->uints.video_swap_interval
33600                                  );
33601 
33602    /* Initialize video driver */
33603    if (flags & DRIVER_VIDEO_MASK)
33604    {
33605       struct retro_hw_render_callback *hwr   =
33606          VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(p_rarch);
33607 
33608       p_rarch->video_driver_frame_time_count = 0;
33609 
33610       video_driver_lock_new(p_rarch);
33611 #ifdef HAVE_VIDEO_FILTER
33612       video_driver_filter_free();
33613 #endif
33614       video_driver_set_cached_frame_ptr(NULL);
33615       video_driver_init_internal(p_rarch, settings, &video_is_threaded,
33616             verbosity_enabled);
33617 
33618       if (!p_rarch->video_driver_cache_context_ack
33619             && hwr->context_reset)
33620          hwr->context_reset();
33621       p_rarch->video_driver_cache_context_ack = false;
33622       runloop_state.frame_time_last        = 0;
33623    }
33624 
33625    /* Initialize audio driver */
33626    if (flags & DRIVER_AUDIO_MASK)
33627    {
33628       audio_driver_init_internal(p_rarch,
33629             settings,
33630             p_rarch->audio_callback.callback != NULL);
33631       if (  p_rarch->current_audio &&
33632             p_rarch->current_audio->device_list_new &&
33633             p_rarch->audio_driver_context_audio_data)
33634          p_rarch->audio_driver_devices_list = (struct string_list*)
33635             p_rarch->current_audio->device_list_new(
33636                   p_rarch->audio_driver_context_audio_data);
33637    }
33638 
33639    if (flags & DRIVER_CAMERA_MASK)
33640    {
33641       /* Only initialize camera driver if we're ever going to use it. */
33642       if (p_rarch->camera_driver_active)
33643       {
33644          /* Resource leaks will follow if camera is initialized twice. */
33645          if (!p_rarch->camera_data)
33646          {
33647             camera_driver_find_driver(p_rarch, settings, "camera driver",
33648                   verbosity_enabled);
33649 
33650             if (p_rarch->camera_driver)
33651             {
33652                p_rarch->camera_data = p_rarch->camera_driver->init(
33653                      *settings->arrays.camera_device ?
33654                      settings->arrays.camera_device : NULL,
33655                      p_rarch->camera_cb.caps,
33656                      settings->uints.camera_width ?
33657                      settings->uints.camera_width : p_rarch->camera_cb.width,
33658                      settings->uints.camera_height ?
33659                      settings->uints.camera_height : p_rarch->camera_cb.height);
33660 
33661                if (!p_rarch->camera_data)
33662                {
33663                   RARCH_ERR("Failed to initialize camera driver. Will continue without camera.\n");
33664                   p_rarch->camera_driver_active = false;
33665                }
33666 
33667                if (p_rarch->camera_cb.initialized)
33668                   p_rarch->camera_cb.initialized();
33669             }
33670          }
33671       }
33672    }
33673 
33674    if (flags & DRIVER_BLUETOOTH_MASK)
33675       bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_INIT, NULL);
33676 
33677    if ((flags & DRIVER_WIFI_MASK))
33678       wifi_driver_ctl(RARCH_WIFI_CTL_INIT, NULL);
33679 
33680    if (flags & DRIVER_LOCATION_MASK)
33681    {
33682       /* Only initialize location driver if we're ever going to use it. */
33683       if (p_rarch->location_driver_active)
33684          init_location(p_rarch, &runloop_state.system, settings, verbosity_is_enabled());
33685    }
33686 
33687    core_info_init_current_core();
33688 
33689 #if defined(HAVE_GFX_WIDGETS)
33690    /* Note that we only enable widgets if 'video_font_enable'
33691     * is true. 'video_font_enable' corresponds to the generic
33692     * 'On-Screen Notifications' setting, which should serve as
33693     * a global notifications on/off toggle switch */
33694    if (video_font_enable &&
33695        menu_enable_widgets &&
33696        video_driver_has_widgets())
33697    {
33698       bool rarch_force_fullscreen = p_rarch->rarch_force_fullscreen;
33699       bool video_is_fullscreen    = settings->bools.video_fullscreen ||
33700             rarch_force_fullscreen;
33701 
33702       p_rarch->widgets_active     = gfx_widgets_init(
33703             &p_rarch->dispwidget_st,
33704             &p_rarch->dispgfx,
33705             &p_rarch->anim,
33706             settings,
33707             (uintptr_t)&p_rarch->widgets_active,
33708             video_is_threaded,
33709             p_rarch->video_driver_width,
33710             p_rarch->video_driver_height,
33711             video_is_fullscreen,
33712             settings->paths.directory_assets,
33713             settings->paths.path_font);
33714    }
33715    else
33716 #endif
33717    {
33718       gfx_display_init_first_driver(p_disp, video_is_threaded);
33719    }
33720 
33721 #ifdef HAVE_MENU
33722    if (flags & DRIVER_VIDEO_MASK)
33723    {
33724       /* Initialize menu driver */
33725       if (flags & DRIVER_MENU_MASK)
33726       {
33727          if (!menu_driver_init(video_is_threaded))
33728              RARCH_ERR("Unable to init menu driver.\n");
33729 
33730 #ifdef HAVE_LIBRETRODB
33731          menu_explore_context_init();
33732 #endif
33733       }
33734    }
33735 
33736    /* Initialising the menu driver will also initialise
33737     * core info - if we are not initialising the menu
33738     * driver, must initialise core info 'by hand' */
33739    if (!(flags & DRIVER_VIDEO_MASK) ||
33740        !(flags & DRIVER_MENU_MASK))
33741    {
33742       command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
33743       command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
33744    }
33745 
33746 #else
33747    /* Qt uses core info, even if the menu is disabled */
33748    command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
33749    command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
33750 #endif
33751 
33752    if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK))
33753    {
33754       /* Keep non-throttled state as good as possible. */
33755       if (p_rarch->input_driver_nonblock_state)
33756          driver_set_nonblock_state();
33757    }
33758 
33759    /* Initialize LED driver */
33760    if (flags & DRIVER_LED_MASK)
33761       led_driver_init(settings->arrays.led_driver);
33762 
33763    /* Initialize MIDI  driver */
33764    if (flags & DRIVER_MIDI_MASK)
33765       midi_driver_init(p_rarch, settings);
33766 
33767 #ifdef HAVE_LAKKA
33768    cpu_scaling_driver_init();
33769 #endif
33770 }
33771 
33772 /**
33773  * Driver ownership - set this to true if the platform in
33774  * question needs to 'own'
33775  * the respective handle and therefore skip regular RetroArch
33776  * driver teardown/reiniting procedure.
33777  *
33778  * If  to true, the 'free' function will get skipped. It is
33779  * then up to the driver implementation to properly handle
33780  * 'reiniting' inside the 'init' function and make sure it
33781  * returns the existing handle instead of allocating and
33782  * returning a pointer to a new handle.
33783  *
33784  * Typically, if a driver intends to make use of this, it should
33785  * set this to true at the end of its 'init' function.
33786  **/
driver_uninit(struct rarch_state * p_rarch,int flags)33787 static void driver_uninit(struct rarch_state *p_rarch, int flags)
33788 {
33789    core_info_deinit_list();
33790    core_info_free_current_core(&p_rarch->core_info_st);
33791 
33792 #if defined(HAVE_GFX_WIDGETS)
33793    /* This absolutely has to be done before video_driver_free_internal()
33794     * is called/completes, otherwise certain menu drivers
33795     * (e.g. Vulkan) will segfault */
33796    if (p_rarch->dispwidget_st.widgets_inited)
33797    {
33798       gfx_widgets_deinit(&p_rarch->dispwidget_st, p_rarch->widgets_persisting);
33799       p_rarch->widgets_active = false;
33800    }
33801 #endif
33802 
33803 #ifdef HAVE_MENU
33804    if (flags & DRIVER_MENU_MASK)
33805    {
33806 #ifdef HAVE_LIBRETRODB
33807       menu_explore_context_deinit();
33808 #endif
33809 
33810       menu_driver_ctl(RARCH_MENU_CTL_DEINIT, NULL);
33811    }
33812 #endif
33813 
33814    if ((flags & DRIVER_LOCATION_MASK))
33815       uninit_location(p_rarch, &runloop_state.system);
33816 
33817    if ((flags & DRIVER_CAMERA_MASK))
33818    {
33819       if (p_rarch->camera_data && p_rarch->camera_driver)
33820       {
33821          if (p_rarch->camera_cb.deinitialized)
33822             p_rarch->camera_cb.deinitialized();
33823 
33824          if (p_rarch->camera_driver->free)
33825             p_rarch->camera_driver->free(p_rarch->camera_data);
33826       }
33827 
33828       p_rarch->camera_data = NULL;
33829    }
33830 
33831    if ((flags & DRIVER_BLUETOOTH_MASK))
33832       bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DEINIT, NULL);
33833 
33834    if ((flags & DRIVER_WIFI_MASK))
33835       wifi_driver_ctl(RARCH_WIFI_CTL_DEINIT, NULL);
33836 
33837    if (flags & DRIVER_LED)
33838       led_driver_free();
33839 
33840    if (flags & DRIVERS_VIDEO_INPUT)
33841    {
33842       video_driver_free_internal(p_rarch);
33843       VIDEO_DRIVER_LOCK_FREE();
33844       p_rarch->video_driver_data = NULL;
33845       video_driver_set_cached_frame_ptr(NULL);
33846    }
33847 
33848    if (flags & DRIVER_AUDIO_MASK)
33849       audio_driver_deinit(p_rarch, p_rarch->configuration_settings);
33850 
33851    if ((flags & DRIVER_VIDEO_MASK))
33852       p_rarch->video_driver_data = NULL;
33853 
33854    if ((flags & DRIVER_INPUT_MASK))
33855       p_rarch->current_input_data = NULL;
33856 
33857    if ((flags & DRIVER_AUDIO_MASK))
33858       p_rarch->audio_driver_context_audio_data = NULL;
33859 
33860    if (flags & DRIVER_MIDI_MASK)
33861       midi_driver_free(p_rarch);
33862 
33863 #ifdef HAVE_LAKKA
33864    cpu_scaling_driver_free();
33865 #endif
33866 }
33867 
retroarch_deinit_drivers(struct rarch_state * p_rarch,struct retro_callbacks * cbs)33868 static void retroarch_deinit_drivers(
33869       struct rarch_state *p_rarch, struct retro_callbacks *cbs)
33870 {
33871 #if defined(HAVE_GFX_WIDGETS)
33872    /* Tear down display widgets no matter what
33873     * in case the handle is lost in the threaded
33874     * video driver in the meantime
33875     * (breaking video_driver_has_widgets) */
33876    if (p_rarch->dispwidget_st.widgets_inited)
33877    {
33878       gfx_widgets_deinit(&p_rarch->dispwidget_st,
33879             p_rarch->widgets_persisting);
33880       p_rarch->widgets_active = false;
33881    }
33882 #endif
33883 
33884 #if defined(HAVE_CRTSWITCHRES)
33885    /* Switchres deinit */
33886    if (p_rarch->video_driver_crt_switching_active)
33887    {
33888 #if defined(DEBUG)
33889       RARCH_LOG("[CRT]: Getting video info\n");
33890       RARCH_LOG("[CRT]: About to destroy SR\n");
33891 #endif
33892       crt_destroy_modes(&p_rarch->crt_switch_st);
33893    }
33894 #endif
33895 
33896    /* Video */
33897    video_display_server_destroy();
33898 
33899    p_rarch->video_driver_use_rgba                   = false;
33900    p_rarch->video_driver_active                     = false;
33901    p_rarch->video_driver_cache_context              = false;
33902    p_rarch->video_driver_cache_context_ack          = false;
33903    p_rarch->video_driver_record_gpu_buffer          = NULL;
33904    p_rarch->current_video                           = NULL;
33905    video_driver_set_cached_frame_ptr(NULL);
33906 
33907    /* Audio */
33908    p_rarch->audio_driver_active                     = false;
33909    p_rarch->current_audio                           = NULL;
33910 
33911    /* Input */
33912    p_rarch->input_driver_keyboard_linefeed_enable   = false;
33913    p_rarch->input_driver_block_hotkey               = false;
33914    p_rarch->input_driver_block_libretro_input       = false;
33915    p_rarch->input_driver_nonblock_state             = false;
33916    p_rarch->input_driver_flushing_input             = 0;
33917    memset(&p_rarch->input_driver_turbo_btns, 0, sizeof(turbo_buttons_t));
33918    memset(&p_rarch->input_driver_analog_requested, 0,
33919          sizeof(p_rarch->input_driver_analog_requested));
33920    p_rarch->current_input                           = NULL;
33921 
33922 #ifdef HAVE_MENU
33923    menu_driver_destroy(p_rarch,
33924          &p_rarch->menu_driver_state);
33925    p_rarch->menu_driver_alive                       = false;
33926 #endif
33927    p_rarch->location_driver_active                  = false;
33928    p_rarch->location_driver                         = NULL;
33929 
33930    /* Camera */
33931    p_rarch->camera_driver_active                    = false;
33932    p_rarch->camera_driver                           = NULL;
33933    p_rarch->camera_data                             = NULL;
33934 
33935    bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_DESTROY, NULL);
33936    wifi_driver_ctl(RARCH_WIFI_CTL_DESTROY, NULL);
33937 
33938    cbs->frame_cb                                    = retro_frame_null;
33939    cbs->poll_cb                                     = retro_input_poll_null;
33940    cbs->sample_cb                                   = NULL;
33941    cbs->sample_batch_cb                             = NULL;
33942    cbs->state_cb                                    = NULL;
33943 
33944    p_rarch->current_core.inited                     = false;
33945 
33946 }
33947 
driver_ctl(enum driver_ctl_state state,void * data)33948 bool driver_ctl(enum driver_ctl_state state, void *data)
33949 {
33950    struct rarch_state *p_rarch = &rarch_st;
33951    driver_ctx_info_t      *drv = (driver_ctx_info_t*)data;
33952 
33953    switch (state)
33954    {
33955       case RARCH_DRIVER_CTL_SET_REFRESH_RATE:
33956          {
33957             float *hz                    = (float*)data;
33958             settings_t *settings         = p_rarch->configuration_settings;
33959             unsigned audio_output_sample_rate = settings->uints.audio_output_sample_rate;
33960             bool vrr_runloop_enable      = settings->bools.vrr_runloop_enable;
33961             float video_refresh_rate     = settings->floats.video_refresh_rate;
33962             float audio_max_timing_skew  = settings->floats.audio_max_timing_skew;
33963             bool video_adaptive_vsync    = settings->bools.video_adaptive_vsync;
33964             unsigned video_swap_interval = settings->uints.video_swap_interval;
33965 
33966             video_monitor_set_refresh_rate(*hz);
33967 
33968             /* Sets audio monitor rate to new value. */
33969             p_rarch->audio_source_ratio_original   =
33970             p_rarch->audio_source_ratio_current    = (double)audio_output_sample_rate
33971                                                      / p_rarch->audio_driver_input;
33972 
33973             driver_adjust_system_rates(p_rarch,
33974                                        vrr_runloop_enable,
33975                                        video_refresh_rate,
33976                                        audio_max_timing_skew,
33977                                        video_adaptive_vsync,
33978                                        video_swap_interval
33979                                        );
33980          }
33981          break;
33982       case RARCH_DRIVER_CTL_FIND_FIRST:
33983          if (!drv)
33984             return false;
33985          find_driver_nonempty(drv->label, 0, drv->s, drv->len);
33986          break;
33987       case RARCH_DRIVER_CTL_FIND_LAST:
33988          if (!drv)
33989             return false;
33990          driver_find_last(drv->label, drv->s, drv->len);
33991          break;
33992       case RARCH_DRIVER_CTL_FIND_PREV:
33993          if (!drv)
33994             return false;
33995          return driver_find_prev(drv->label, drv->s, drv->len);
33996       case RARCH_DRIVER_CTL_FIND_NEXT:
33997          if (!drv)
33998             return false;
33999          return driver_find_next(drv->label, drv->s, drv->len);
34000       case RARCH_DRIVER_CTL_NONE:
34001       default:
34002          break;
34003    }
34004 
34005    return true;
34006 }
34007 
34008 /* RUNAHEAD */
34009 
34010 #ifdef HAVE_RUNAHEAD
mylist_resize(my_list * list,int new_size,bool run_constructor)34011 static void mylist_resize(my_list *list,
34012       int new_size, bool run_constructor)
34013 {
34014    int i;
34015    int new_capacity;
34016    int old_size;
34017    void *element    = NULL;
34018    if (new_size < 0)
34019       new_size      = 0;
34020    new_capacity     = new_size;
34021    old_size         = list->size;
34022 
34023    if (new_size == old_size)
34024       return;
34025 
34026    if (new_size > list->capacity)
34027    {
34028       if (new_capacity < list->capacity * 2)
34029          new_capacity = list->capacity * 2;
34030 
34031       /* try to realloc */
34032       list->data      = (void**)realloc(
34033             (void*)list->data, new_capacity * sizeof(void*));
34034 
34035       for (i = list->capacity; i < new_capacity; i++)
34036          list->data[i] = NULL;
34037 
34038       list->capacity = new_capacity;
34039    }
34040 
34041    if (new_size <= list->size)
34042    {
34043       for (i = new_size; i < list->size; i++)
34044       {
34045          element = list->data[i];
34046 
34047          if (element)
34048          {
34049             list->destructor(element);
34050             list->data[i] = NULL;
34051          }
34052       }
34053    }
34054    else
34055    {
34056       for (i = list->size; i < new_size; i++)
34057       {
34058          list->data[i] = NULL;
34059          if (run_constructor)
34060             list->data[i] = list->constructor();
34061       }
34062    }
34063 
34064    list->size = new_size;
34065 }
34066 
mylist_add_element(my_list * list)34067 static void *mylist_add_element(my_list *list)
34068 {
34069    int old_size = list->size;
34070    if (list)
34071       mylist_resize(list, old_size + 1, true);
34072    return list->data[old_size];
34073 }
34074 
mylist_destroy(my_list ** list_p)34075 static void mylist_destroy(my_list **list_p)
34076 {
34077    my_list *list = NULL;
34078    if (!list_p)
34079       return;
34080 
34081    list = *list_p;
34082 
34083    if (list)
34084    {
34085       mylist_resize(list, 0, false);
34086       free(list->data);
34087       free(list);
34088       *list_p = NULL;
34089    }
34090 }
34091 
mylist_create(my_list ** list_p,int initial_capacity,constructor_t constructor,destructor_t destructor)34092 static void mylist_create(my_list **list_p, int initial_capacity,
34093       constructor_t constructor, destructor_t destructor)
34094 {
34095    my_list *list        = NULL;
34096 
34097    if (!list_p)
34098       return;
34099 
34100    list                = *list_p;
34101    if (list)
34102       mylist_destroy(list_p);
34103 
34104    list               = (my_list*)malloc(sizeof(my_list));
34105    *list_p            = list;
34106    list->size         = 0;
34107    list->constructor  = constructor;
34108    list->destructor   = destructor;
34109    list->data         = (void**)calloc(initial_capacity, sizeof(void*));
34110    list->capacity     = initial_capacity;
34111 }
34112 
input_list_element_constructor(void)34113 static void *input_list_element_constructor(void)
34114 {
34115    void *ptr                   = malloc(sizeof(input_list_element));
34116    input_list_element *element = (input_list_element*)ptr;
34117 
34118    element->port               = 0;
34119    element->device             = 0;
34120    element->index              = 0;
34121    element->state              = (int16_t*)calloc(256, sizeof(int16_t));
34122    element->state_size         = 256;
34123 
34124    return ptr;
34125 }
34126 
input_list_element_realloc(input_list_element * element,unsigned int new_size)34127 static void input_list_element_realloc(
34128       input_list_element *element,
34129       unsigned int new_size)
34130 {
34131    if (new_size > element->state_size)
34132    {
34133       element->state = (int16_t*)realloc(element->state,
34134             new_size * sizeof(int16_t));
34135       memset(&element->state[element->state_size], 0,
34136             (new_size - element->state_size) * sizeof(int16_t));
34137       element->state_size = new_size;
34138    }
34139 }
34140 
input_list_element_expand(input_list_element * element,unsigned int new_index)34141 static void input_list_element_expand(
34142       input_list_element *element, unsigned int new_index)
34143 {
34144    unsigned int new_size = element->state_size;
34145    if (new_size == 0)
34146       new_size = 32;
34147    while (new_index >= new_size)
34148       new_size *= 2;
34149    input_list_element_realloc(element, new_size);
34150 }
34151 
input_list_element_destructor(void * element_ptr)34152 static void input_list_element_destructor(void* element_ptr)
34153 {
34154    input_list_element *element = (input_list_element*)element_ptr;
34155    if (!element)
34156       return;
34157 
34158    free(element->state);
34159    free(element_ptr);
34160 }
34161 
input_state_set_last(struct rarch_state * p_rarch,unsigned port,unsigned device,unsigned index,unsigned id,int16_t value)34162 static void input_state_set_last(
34163       struct rarch_state *p_rarch,
34164       unsigned port, unsigned device,
34165       unsigned index, unsigned id, int16_t value)
34166 {
34167    unsigned i;
34168    input_list_element *element = NULL;
34169 
34170    if (!p_rarch->input_state_list)
34171       mylist_create(&p_rarch->input_state_list, 16,
34172             input_list_element_constructor,
34173             input_list_element_destructor);
34174 
34175    /* Find list item */
34176    for (i = 0; i < (unsigned)p_rarch->input_state_list->size; i++)
34177    {
34178       element = (input_list_element*)p_rarch->input_state_list->data[i];
34179       if (  (element->port   == port)   &&
34180             (element->device == device) &&
34181             (element->index  == index)
34182          )
34183       {
34184          if (id >= element->state_size)
34185             input_list_element_expand(element, id);
34186          element->state[id] = value;
34187          return;
34188       }
34189    }
34190 
34191    element               = NULL;
34192    if (p_rarch->input_state_list)
34193       element            = (input_list_element*)
34194          mylist_add_element(p_rarch->input_state_list);
34195    if (element)
34196    {
34197       element->port         = port;
34198       element->device       = device;
34199       element->index        = index;
34200       if (id >= element->state_size)
34201          input_list_element_expand(element, id);
34202       element->state[id]    = value;
34203    }
34204 }
34205 
input_state_get_last(unsigned port,unsigned device,unsigned index,unsigned id)34206 static int16_t input_state_get_last(unsigned port,
34207       unsigned device, unsigned index, unsigned id)
34208 {
34209    unsigned i;
34210    struct rarch_state      *p_rarch = &rarch_st;
34211 
34212    if (!p_rarch->input_state_list)
34213       return 0;
34214 
34215    /* find list item */
34216    for (i = 0; i < (unsigned)p_rarch->input_state_list->size; i++)
34217    {
34218       input_list_element *element =
34219          (input_list_element*)p_rarch->input_state_list->data[i];
34220 
34221       if (  (element->port   == port)   &&
34222             (element->device == device) &&
34223             (element->index  == index))
34224       {
34225          if (id < element->state_size)
34226             return element->state[id];
34227          return 0;
34228       }
34229    }
34230    return 0;
34231 }
34232 
input_state_with_logging(unsigned port,unsigned device,unsigned index,unsigned id)34233 static int16_t input_state_with_logging(unsigned port,
34234       unsigned device, unsigned index, unsigned id)
34235 {
34236    struct rarch_state      *p_rarch = &rarch_st;
34237 
34238    if (p_rarch->input_state_callback_original)
34239    {
34240       int16_t result              = p_rarch->input_state_callback_original(
34241             port, device, index, id);
34242       int16_t last_input          =
34243          input_state_get_last(port, device, index, id);
34244       if (result != last_input)
34245          p_rarch->input_is_dirty  = true;
34246       /*arbitrary limit of up to 65536 elements in state array*/
34247       if (id < 65536)
34248          input_state_set_last(p_rarch, port, device, index, id, result);
34249 
34250       return result;
34251    }
34252    return 0;
34253 }
34254 
reset_hook(void)34255 static void reset_hook(void)
34256 {
34257    struct rarch_state     *p_rarch = &rarch_st;
34258 
34259    p_rarch->input_is_dirty         = true;
34260 
34261    if (p_rarch->retro_reset_callback_original)
34262       p_rarch->retro_reset_callback_original();
34263 }
34264 
unserialize_hook(const void * buf,size_t size)34265 static bool unserialize_hook(const void *buf, size_t size)
34266 {
34267    struct rarch_state     *p_rarch = &rarch_st;
34268 
34269    p_rarch->input_is_dirty         = true;
34270 
34271    if (p_rarch->retro_unserialize_callback_original)
34272       return p_rarch->retro_unserialize_callback_original(buf, size);
34273    return false;
34274 }
34275 
add_input_state_hook(struct rarch_state * p_rarch)34276 static void add_input_state_hook(struct rarch_state *p_rarch)
34277 {
34278    struct retro_callbacks *cbs      = &p_rarch->retro_ctx;
34279 
34280    if (!p_rarch->input_state_callback_original)
34281    {
34282       p_rarch->input_state_callback_original = cbs->state_cb;
34283       cbs->state_cb                          = input_state_with_logging;
34284       p_rarch->current_core.retro_set_input_state(cbs->state_cb);
34285    }
34286 
34287    if (!p_rarch->retro_reset_callback_original)
34288    {
34289       p_rarch->retro_reset_callback_original = p_rarch->current_core.retro_reset;
34290       p_rarch->current_core.retro_reset      = reset_hook;
34291    }
34292 
34293    if (!p_rarch->retro_unserialize_callback_original)
34294    {
34295       p_rarch->retro_unserialize_callback_original = p_rarch->current_core.retro_unserialize;
34296       p_rarch->current_core.retro_unserialize      = unserialize_hook;
34297    }
34298 }
34299 
remove_input_state_hook(struct rarch_state * p_rarch)34300 static void remove_input_state_hook(struct rarch_state *p_rarch)
34301 {
34302    struct retro_callbacks *cbs      = &p_rarch->retro_ctx;
34303 
34304    if (p_rarch->input_state_callback_original)
34305    {
34306       cbs->state_cb                 = p_rarch->input_state_callback_original;
34307       p_rarch->current_core.retro_set_input_state(cbs->state_cb);
34308       p_rarch->input_state_callback_original = NULL;
34309       mylist_destroy(&p_rarch->input_state_list);
34310    }
34311 
34312    if (p_rarch->retro_reset_callback_original)
34313    {
34314       p_rarch->current_core.retro_reset               =
34315          p_rarch->retro_reset_callback_original;
34316       p_rarch->retro_reset_callback_original          = NULL;
34317    }
34318 
34319    if (p_rarch->retro_unserialize_callback_original)
34320    {
34321       p_rarch->current_core.retro_unserialize                =
34322          p_rarch->retro_unserialize_callback_original;
34323       p_rarch->retro_unserialize_callback_original           = NULL;
34324    }
34325 }
34326 
runahead_save_state_alloc(void)34327 static void *runahead_save_state_alloc(void)
34328 {
34329    struct rarch_state *p_rarch           = &rarch_st;
34330    retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)
34331       malloc(sizeof(retro_ctx_serialize_info_t));
34332 
34333    if (!savestate)
34334       return NULL;
34335 
34336    savestate->data          = NULL;
34337    savestate->data_const    = NULL;
34338    savestate->size          = 0;
34339 
34340    if (  (p_rarch->runahead_save_state_size > 0) &&
34341          p_rarch->runahead_save_state_size_known)
34342    {
34343       savestate->data       = malloc(p_rarch->runahead_save_state_size);
34344       savestate->data_const = savestate->data;
34345       savestate->size       = p_rarch->runahead_save_state_size;
34346    }
34347 
34348    return savestate;
34349 }
34350 
runahead_save_state_free(void * data)34351 static void runahead_save_state_free(void *data)
34352 {
34353    retro_ctx_serialize_info_t *savestate = (retro_ctx_serialize_info_t*)data;
34354    if (!savestate)
34355       return;
34356    free(savestate->data);
34357    free(savestate);
34358 }
34359 
runahead_save_state_list_init(struct rarch_state * p_rarch,size_t save_state_size)34360 static void runahead_save_state_list_init(
34361       struct rarch_state *p_rarch,
34362       size_t save_state_size)
34363 {
34364    p_rarch->runahead_save_state_size       = save_state_size;
34365    p_rarch->runahead_save_state_size_known = true;
34366 
34367    mylist_create(&p_rarch->runahead_save_state_list, 16,
34368          runahead_save_state_alloc, runahead_save_state_free);
34369 }
34370 
34371 /* Hooks - Hooks to cleanup, and add dirty input hooks */
runahead_remove_hooks(struct rarch_state * p_rarch)34372 static void runahead_remove_hooks(struct rarch_state *p_rarch)
34373 {
34374    if (p_rarch->original_retro_deinit)
34375    {
34376       p_rarch->current_core.retro_deinit = p_rarch->original_retro_deinit;
34377       p_rarch->original_retro_deinit     = NULL;
34378    }
34379 
34380    if (p_rarch->original_retro_unload)
34381    {
34382       p_rarch->current_core.retro_unload_game = p_rarch->original_retro_unload;
34383       p_rarch->original_retro_unload          = NULL;
34384    }
34385    remove_input_state_hook(p_rarch);
34386 }
34387 
runahead_destroy(struct rarch_state * p_rarch)34388 static void runahead_destroy(struct rarch_state *p_rarch)
34389 {
34390    mylist_destroy(&p_rarch->runahead_save_state_list);
34391    runahead_remove_hooks(p_rarch);
34392    runahead_clear_variables(p_rarch);
34393 }
34394 
unload_hook(void)34395 static void unload_hook(void)
34396 {
34397    struct rarch_state *p_rarch = &rarch_st;
34398 
34399    runahead_remove_hooks(p_rarch);
34400    runahead_destroy(p_rarch);
34401    secondary_core_destroy(p_rarch);
34402    if (p_rarch->current_core.retro_unload_game)
34403       p_rarch->current_core.retro_unload_game();
34404    p_rarch->core_poll_type_override = POLL_TYPE_OVERRIDE_DONTCARE;
34405 }
34406 
runahead_deinit_hook(void)34407 static void runahead_deinit_hook(void)
34408 {
34409    struct rarch_state *p_rarch     = &rarch_st;
34410 
34411    runahead_remove_hooks(p_rarch);
34412    runahead_destroy(p_rarch);
34413    secondary_core_destroy(p_rarch);
34414    if (p_rarch->current_core.retro_deinit)
34415       p_rarch->current_core.retro_deinit();
34416 }
34417 
runahead_add_hooks(struct rarch_state * p_rarch)34418 static void runahead_add_hooks(struct rarch_state *p_rarch)
34419 {
34420    if (!p_rarch->original_retro_deinit)
34421    {
34422       p_rarch->original_retro_deinit     = p_rarch->current_core.retro_deinit;
34423       p_rarch->current_core.retro_deinit = runahead_deinit_hook;
34424    }
34425 
34426    if (!p_rarch->original_retro_unload)
34427    {
34428       p_rarch->original_retro_unload          = p_rarch->current_core.retro_unload_game;
34429       p_rarch->current_core.retro_unload_game = unload_hook;
34430    }
34431    add_input_state_hook(p_rarch);
34432 }
34433 
34434 /* Runahead Code */
34435 
runahead_error(struct rarch_state * p_rarch)34436 static void runahead_error(struct rarch_state *p_rarch)
34437 {
34438    p_rarch->runahead_available             = false;
34439    mylist_destroy(&p_rarch->runahead_save_state_list);
34440    runahead_remove_hooks(p_rarch);
34441    p_rarch->runahead_save_state_size       = 0;
34442    p_rarch->runahead_save_state_size_known = true;
34443 }
34444 
runahead_create(struct rarch_state * p_rarch)34445 static bool runahead_create(struct rarch_state *p_rarch)
34446 {
34447    /* get savestate size and allocate buffer */
34448    retro_ctx_size_info_t info;
34449 
34450    p_rarch->request_fast_savestate          = true;
34451    core_serialize_size(&info);
34452    p_rarch->request_fast_savestate          = false;
34453 
34454    runahead_save_state_list_init(p_rarch, info.size);
34455    p_rarch->runahead_video_driver_is_active =
34456       p_rarch->video_driver_active;
34457 
34458    if (  (p_rarch->runahead_save_state_size == 0) ||
34459          !p_rarch->runahead_save_state_size_known)
34460    {
34461       runahead_error(p_rarch);
34462       return false;
34463    }
34464 
34465    runahead_add_hooks(p_rarch);
34466    p_rarch->runahead_force_input_dirty = true;
34467    if (p_rarch->runahead_save_state_list)
34468       mylist_resize(p_rarch->runahead_save_state_list, 1, true);
34469    return true;
34470 }
34471 
runahead_save_state(struct rarch_state * p_rarch)34472 static bool runahead_save_state(struct rarch_state *p_rarch)
34473 {
34474    retro_ctx_serialize_info_t *serialize_info;
34475    bool okay                       = false;
34476 
34477    if (!p_rarch->runahead_save_state_list)
34478       return false;
34479 
34480    serialize_info                  =
34481       (retro_ctx_serialize_info_t*)p_rarch->runahead_save_state_list->data[0];
34482 
34483    p_rarch->request_fast_savestate = true;
34484    okay                            = core_serialize(serialize_info);
34485    p_rarch->request_fast_savestate = false;
34486 
34487    if (okay)
34488       return true;
34489 
34490    runahead_error(p_rarch);
34491    return false;
34492 }
34493 
runahead_load_state(struct rarch_state * p_rarch)34494 static bool runahead_load_state(struct rarch_state *p_rarch)
34495 {
34496    bool okay                                  = false;
34497    retro_ctx_serialize_info_t *serialize_info = (retro_ctx_serialize_info_t*)
34498       p_rarch->runahead_save_state_list->data[0];
34499    bool last_dirty                            = p_rarch->input_is_dirty;
34500 
34501    p_rarch->request_fast_savestate            = true;
34502    /* calling core_unserialize has side effects with
34503     * netplay (it triggers transmitting your save state)
34504       call retro_unserialize directly from the core instead */
34505    okay = p_rarch->current_core.retro_unserialize(
34506          serialize_info->data_const, serialize_info->size);
34507 
34508    p_rarch->request_fast_savestate            = false;
34509    p_rarch->input_is_dirty                    = last_dirty;
34510 
34511    if (!okay)
34512       runahead_error(p_rarch);
34513 
34514    return okay;
34515 }
34516 
34517 #if HAVE_DYNAMIC
runahead_load_state_secondary(struct rarch_state * p_rarch)34518 static bool runahead_load_state_secondary(struct rarch_state *p_rarch)
34519 {
34520    bool okay                                  = false;
34521    retro_ctx_serialize_info_t *serialize_info =
34522       (retro_ctx_serialize_info_t*)p_rarch->runahead_save_state_list->data[0];
34523 
34524    p_rarch->request_fast_savestate            = true;
34525    okay                                       = secondary_core_deserialize(
34526          p_rarch, p_rarch->configuration_settings,
34527          serialize_info->data_const, (int)serialize_info->size);
34528    p_rarch->request_fast_savestate            = false;
34529 
34530    if (!okay)
34531    {
34532       p_rarch->runahead_secondary_core_available = false;
34533       runahead_error(p_rarch);
34534       return false;
34535    }
34536 
34537    return true;
34538 }
34539 #endif
34540 
runahead_core_run_use_last_input(struct rarch_state * p_rarch)34541 static bool runahead_core_run_use_last_input(struct rarch_state *p_rarch)
34542 {
34543    struct retro_callbacks *cbs            = &p_rarch->retro_ctx;
34544    retro_input_poll_t old_poll_function   = cbs->poll_cb;
34545    retro_input_state_t old_input_function = cbs->state_cb;
34546 
34547    cbs->poll_cb                           = retro_input_poll_null;
34548    cbs->state_cb                          = input_state_get_last;
34549 
34550    p_rarch->current_core.retro_set_input_poll(cbs->poll_cb);
34551    p_rarch->current_core.retro_set_input_state(cbs->state_cb);
34552 
34553    p_rarch->current_core.retro_run();
34554 
34555    cbs->poll_cb                           = old_poll_function;
34556    cbs->state_cb                          = old_input_function;
34557 
34558    p_rarch->current_core.retro_set_input_poll(cbs->poll_cb);
34559    p_rarch->current_core.retro_set_input_state(cbs->state_cb);
34560 
34561    return true;
34562 }
34563 
do_runahead(struct rarch_state * p_rarch,int runahead_count,bool runahead_hide_warnings,bool use_secondary)34564 static void do_runahead(
34565       struct rarch_state *p_rarch,
34566       int runahead_count,
34567       bool runahead_hide_warnings,
34568       bool use_secondary)
34569 {
34570    int frame_number        = 0;
34571    bool last_frame         = false;
34572    bool suspended_frame    = false;
34573 #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
34574    const bool have_dynamic = true;
34575 #else
34576    const bool have_dynamic = false;
34577 #endif
34578    uint64_t frame_count    = p_rarch->video_driver_frame_count;
34579 
34580    if (runahead_count <= 0 || !p_rarch->runahead_available)
34581       goto force_input_dirty;
34582 
34583    if (!p_rarch->runahead_save_state_size_known)
34584    {
34585       if (!runahead_create(p_rarch))
34586       {
34587          if (!runahead_hide_warnings)
34588             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);
34589          goto force_input_dirty;
34590       }
34591    }
34592 
34593    /* Check for GUI */
34594    /* Hack: If we were in the GUI, force a resync. */
34595    if (frame_count != p_rarch->runahead_last_frame_count + 1)
34596       p_rarch->runahead_force_input_dirty = true;
34597 
34598    p_rarch->runahead_last_frame_count     = frame_count;
34599 
34600    if (     !use_secondary
34601          || !have_dynamic
34602          || !p_rarch->runahead_secondary_core_available)
34603    {
34604       /* TODO: multiple savestates for higher performance
34605        * when not using secondary core */
34606       for (frame_number = 0; frame_number <= runahead_count; frame_number++)
34607       {
34608          last_frame      = frame_number == runahead_count;
34609          suspended_frame = !last_frame;
34610 
34611          if (suspended_frame)
34612          {
34613             p_rarch->audio_suspended     = true;
34614             p_rarch->video_driver_active = false;
34615          }
34616 
34617          if (frame_number == 0)
34618             core_run();
34619          else
34620             runahead_core_run_use_last_input(p_rarch);
34621 
34622          if (suspended_frame)
34623          {
34624             RUNAHEAD_RESUME_VIDEO(p_rarch);
34625             p_rarch->audio_suspended     = false;
34626          }
34627 
34628          if (frame_number == 0)
34629          {
34630             if (!runahead_save_state(p_rarch))
34631             {
34632                runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
34633                return;
34634             }
34635          }
34636 
34637          if (last_frame)
34638          {
34639             if (!runahead_load_state(p_rarch))
34640             {
34641                runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
34642                return;
34643             }
34644          }
34645       }
34646    }
34647    else
34648    {
34649 #if HAVE_DYNAMIC
34650       if (!secondary_core_ensure_exists(p_rarch, p_rarch->configuration_settings))
34651       {
34652          secondary_core_destroy(p_rarch);
34653          p_rarch->runahead_secondary_core_available = false;
34654          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);
34655          goto force_input_dirty;
34656       }
34657 
34658       /* run main core with video suspended */
34659       p_rarch->video_driver_active     = false;
34660       core_run();
34661       RUNAHEAD_RESUME_VIDEO(p_rarch);
34662 
34663       if (     p_rarch->input_is_dirty
34664             || p_rarch->runahead_force_input_dirty)
34665       {
34666          p_rarch->input_is_dirty       = false;
34667 
34668          if (!runahead_save_state(p_rarch))
34669          {
34670             runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
34671             return;
34672          }
34673 
34674          if (!runahead_load_state_secondary(p_rarch))
34675          {
34676             runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
34677             return;
34678          }
34679 
34680          for (frame_number = 0; frame_number < runahead_count - 1; frame_number++)
34681          {
34682             p_rarch->video_driver_active = false;
34683             p_rarch->audio_suspended     = true;
34684             p_rarch->hard_disable_audio  = true;
34685             RUNAHEAD_RUN_SECONDARY(p_rarch);
34686             p_rarch->hard_disable_audio  = false;
34687             p_rarch->audio_suspended     = false;
34688             RUNAHEAD_RESUME_VIDEO(p_rarch);
34689          }
34690       }
34691       p_rarch->audio_suspended           = true;
34692       p_rarch->hard_disable_audio        = true;
34693       RUNAHEAD_RUN_SECONDARY(p_rarch);
34694       p_rarch->hard_disable_audio        = false;
34695       p_rarch->audio_suspended           = false;
34696 #endif
34697    }
34698    p_rarch->runahead_force_input_dirty   = false;
34699    return;
34700 
34701 force_input_dirty:
34702    core_run();
34703    p_rarch->runahead_force_input_dirty   = true;
34704 }
34705 #endif
34706 
rarch_core_runtime_tick(struct rarch_state * p_rarch,float slowmotion_ratio,retro_time_t current_time)34707 static retro_time_t rarch_core_runtime_tick(
34708       struct rarch_state *p_rarch,
34709       float slowmotion_ratio,
34710       retro_time_t current_time)
34711 {
34712    retro_time_t frame_time              =
34713       (1.0 / p_rarch->video_driver_av_info.timing.fps) * 1000000;
34714    bool runloop_slowmotion              = runloop_state.slowmotion;
34715    bool runloop_fastmotion              = runloop_state.fastmotion;
34716 
34717    /* Account for slow motion */
34718    if (runloop_slowmotion)
34719       return (retro_time_t)((double)frame_time * slowmotion_ratio);
34720 
34721    /* Account for fast forward */
34722    if (runloop_fastmotion)
34723    {
34724       /* Doing it this way means we miss the first frame after
34725        * turning fast forward on, but it saves the overhead of
34726        * having to do:
34727        *    retro_time_t current_usec = cpu_features_get_time_usec();
34728        *    libretro_core_runtime_last = current_usec;
34729        * every frame when fast forward is off. */
34730       retro_time_t current_usec           = current_time;
34731       retro_time_t potential_frame_time   = current_usec -
34732          p_rarch->libretro_core_runtime_last;
34733       p_rarch->libretro_core_runtime_last = current_usec;
34734 
34735       if (potential_frame_time < frame_time)
34736          return potential_frame_time;
34737    }
34738 
34739    return frame_time;
34740 }
34741 
retroarch_print_features(void)34742 static void retroarch_print_features(void)
34743 {
34744    char buf[2048];
34745    buf[0] = '\0';
34746    frontend_driver_attach_console();
34747 
34748    strlcpy(buf, "\nFeatures:\n", sizeof(buf));
34749 
34750    _PSUPP_BUF(buf, SUPPORTS_LIBRETRODB,      "LibretroDB",      "LibretroDB support");
34751    _PSUPP_BUF(buf, SUPPORTS_COMMAND,         "Command",         "Command interface support");
34752    _PSUPP_BUF(buf, SUPPORTS_NETWORK_COMMAND, "Network Command", "Network Command interface "
34753          "support");
34754    _PSUPP_BUF(buf, SUPPORTS_SDL,             "SDL",             "SDL input/audio/video drivers");
34755    _PSUPP_BUF(buf, SUPPORTS_SDL2,            "SDL2",            "SDL2 input/audio/video drivers");
34756    _PSUPP_BUF(buf, SUPPORTS_X11,             "X11",             "X11 input/video drivers");
34757    _PSUPP_BUF(buf, SUPPORTS_WAYLAND,         "wayland",         "Wayland input/video drivers");
34758    _PSUPP_BUF(buf, SUPPORTS_THREAD,          "Threads",         "Threading support");
34759    _PSUPP_BUF(buf, SUPPORTS_VULKAN,          "Vulkan",          "Vulkan video driver");
34760    _PSUPP_BUF(buf, SUPPORTS_METAL,           "Metal",           "Metal video driver");
34761    _PSUPP_BUF(buf, SUPPORTS_OPENGL,          "OpenGL",          "OpenGL   video driver support");
34762    _PSUPP_BUF(buf, SUPPORTS_OPENGLES,        "OpenGL ES",       "OpenGLES video driver support");
34763    _PSUPP_BUF(buf, SUPPORTS_XVIDEO,          "XVideo",          "Video driver");
34764    _PSUPP_BUF(buf, SUPPORTS_UDEV,            "UDEV",            "UDEV/EVDEV input driver support");
34765    _PSUPP_BUF(buf, SUPPORTS_EGL,             "EGL",             "Video context driver");
34766    _PSUPP_BUF(buf, SUPPORTS_KMS,             "KMS",             "Video context driver");
34767    _PSUPP_BUF(buf, SUPPORTS_VG,              "OpenVG",          "Video context driver");
34768    _PSUPP_BUF(buf, SUPPORTS_COREAUDIO,       "CoreAudio",       "Audio driver");
34769    _PSUPP_BUF(buf, SUPPORTS_COREAUDIO3,      "CoreAudioV3",     "Audio driver");
34770    _PSUPP_BUF(buf, SUPPORTS_ALSA,            "ALSA",            "Audio driver");
34771    _PSUPP_BUF(buf, SUPPORTS_OSS,             "OSS",             "Audio driver");
34772    _PSUPP_BUF(buf, SUPPORTS_JACK,            "Jack",            "Audio driver");
34773    _PSUPP_BUF(buf, SUPPORTS_RSOUND,          "RSound",          "Audio driver");
34774    _PSUPP_BUF(buf, SUPPORTS_ROAR,            "RoarAudio",       "Audio driver");
34775    _PSUPP_BUF(buf, SUPPORTS_PULSE,           "PulseAudio",      "Audio driver");
34776    _PSUPP_BUF(buf, SUPPORTS_DSOUND,          "DirectSound",     "Audio driver");
34777    _PSUPP_BUF(buf, SUPPORTS_WASAPI,          "WASAPI",     "Audio driver");
34778    _PSUPP_BUF(buf, SUPPORTS_XAUDIO,          "XAudio2",         "Audio driver");
34779    _PSUPP_BUF(buf, SUPPORTS_AL,              "OpenAL",          "Audio driver");
34780    _PSUPP_BUF(buf, SUPPORTS_SL,              "OpenSL",          "Audio driver");
34781    _PSUPP_BUF(buf, SUPPORTS_7ZIP,            "7zip",            "7zip extraction support");
34782    _PSUPP_BUF(buf, SUPPORTS_ZLIB,            "zlib",            ".zip extraction support");
34783    _PSUPP_BUF(buf, SUPPORTS_DYLIB,           "External",        "External filter and plugin support");
34784    _PSUPP_BUF(buf, SUPPORTS_CG,              "Cg",              "Fragment/vertex shader driver");
34785    _PSUPP_BUF(buf, SUPPORTS_GLSL,            "GLSL",            "Fragment/vertex shader driver");
34786    _PSUPP_BUF(buf, SUPPORTS_HLSL,            "HLSL",            "Fragment/vertex shader driver");
34787    _PSUPP_BUF(buf, SUPPORTS_SDL_IMAGE,       "SDL_image",       "SDL_image image loading");
34788    _PSUPP_BUF(buf, SUPPORTS_RPNG,            "rpng",            "PNG image loading/encoding");
34789    _PSUPP_BUF(buf, SUPPORTS_RJPEG,            "rjpeg",           "JPEG image loading");
34790    _PSUPP_BUF(buf, SUPPORTS_DYNAMIC,         "Dynamic",         "Dynamic run-time loading of "
34791                                               "libretro library");
34792    _PSUPP_BUF(buf, SUPPORTS_FFMPEG,          "FFmpeg",          "On-the-fly recording of gameplay "
34793                                               "with libavcodec");
34794    _PSUPP_BUF(buf, SUPPORTS_FREETYPE,        "FreeType",        "TTF font rendering driver");
34795    _PSUPP_BUF(buf, SUPPORTS_CORETEXT,        "CoreText",        "TTF font rendering driver ");
34796    _PSUPP_BUF(buf, SUPPORTS_NETPLAY,         "Netplay",         "Peer-to-peer netplay");
34797    _PSUPP_BUF(buf, SUPPORTS_PYTHON,          "Python",          "Script support in shaders");
34798    _PSUPP_BUF(buf, SUPPORTS_LIBUSB,          "Libusb",          "Libusb support");
34799    _PSUPP_BUF(buf, SUPPORTS_COCOA,           "Cocoa",           "Cocoa UI companion support "
34800                                               "(for OSX and/or iOS)");
34801    _PSUPP_BUF(buf, SUPPORTS_QT,              "Qt",              "Qt UI companion support");
34802    _PSUPP_BUF(buf, SUPPORTS_V4L2,            "Video4Linux2",    "Camera driver");
34803 
34804    puts(buf);
34805 }
34806 
retroarch_print_version(void)34807 static void retroarch_print_version(void)
34808 {
34809    char str[255];
34810    frontend_driver_attach_console();
34811    str[0] = '\0';
34812 
34813    fprintf(stderr, "%s: %s -- v%s",
34814          msg_hash_to_str(MSG_PROGRAM),
34815          msg_hash_to_str(MSG_LIBRETRO_FRONTEND),
34816          PACKAGE_VERSION);
34817 #ifdef HAVE_GIT_VERSION
34818    printf(" -- %s --\n", retroarch_git_version);
34819 #else
34820    printf("\n");
34821 #endif
34822    retroarch_get_capabilities(RARCH_CAPABILITIES_COMPILER, str, sizeof(str));
34823    strlcat(str, " Built: " __DATE__, sizeof(str));
34824    fprintf(stdout, "%s\n", str);
34825 }
34826 
34827 /**
34828  * retroarch_print_help:
34829  *
34830  * Prints help message explaining the program's commandline switches.
34831  **/
retroarch_print_help(const char * arg0)34832 static void retroarch_print_help(const char *arg0)
34833 {
34834    frontend_driver_attach_console();
34835    puts("===================================================================");
34836    retroarch_print_version();
34837    puts("===================================================================");
34838 
34839    printf("Usage: %s [OPTIONS]... [FILE]\n", arg0);
34840 
34841    {
34842       char buf[2148];
34843       buf[0] = '\0';
34844 
34845       strlcpy(buf, "  -h, --help            Show this help message.\n", sizeof(buf));
34846       strlcat(buf, "  -v, --verbose         Verbose logging.\n",        sizeof(buf));
34847       strlcat(buf, "      --log-file FILE   Log messages to FILE.\n",   sizeof(buf));
34848       strlcat(buf, "      --version         Show version.\n",           sizeof(buf));
34849       strlcat(buf, "      --features        Prints available features compiled into "
34850             "program.\n", sizeof(buf));
34851 
34852 #ifdef HAVE_MENU
34853       strlcat(buf, "      --menu            Do not require content or libretro core to "
34854             "be loaded,\n"
34855             "                        starts directly in menu. If no arguments "
34856             "are passed to\n"
34857             "                        the program, it is equivalent to using "
34858             "--menu as only argument.\n", sizeof(buf));
34859 #endif
34860 
34861       strlcat(buf, "  -s, --save=PATH       Path for save files (*.srm). (DEPRECATED, use --appendconfig and savefile_directory)\n", sizeof(buf));
34862       strlcat(buf, "  -S, --savestate=PATH  Path for the save state files (*.state). (DEPRECATED, use --appendconfig and savestate_directory)\n", sizeof(buf));
34863       strlcat(buf, "      --set-shader PATH Path to a shader (preset) that will be loaded each time content is loaded.\n"
34864             "                        Effectively overrides automatic shader presets.\n"
34865             "                        An empty argument \"\" will disable automatic shader presets.\n", sizeof(buf));
34866       strlcat(buf, "  -f, --fullscreen      Start the program in fullscreen regardless "
34867             "of config settings.\n", sizeof(buf));
34868 #ifdef HAVE_CONFIGFILE
34869 #ifdef _WIN32
34870       strlcat(buf, "  -c, --config=FILE     Path for config file."
34871             "\n\t\tDefaults to retroarch.cfg in same directory as retroarch.exe."
34872             "\n\t\tIf a default config is not found, the program will attempt to "
34873             "create one.\n"
34874             , sizeof(buf));
34875 #else
34876       strlcat(buf, "  -c, --config=FILE     Path for config file."
34877             "\n\t\tBy default looks for config in $XDG_CONFIG_HOME/retroarch/"
34878             "retroarch.cfg,\n\t\t$HOME/.config/retroarch/retroarch.cfg,\n\t\t"
34879             "and $HOME/.retroarch.cfg.\n\t\tIf a default config is not found, "
34880             "the program will attempt to create one based on the \n\t\t"
34881             "skeleton config (" GLOBAL_CONFIG_DIR "/retroarch.cfg). \n"
34882             , sizeof(buf));
34883 #endif
34884 #endif
34885       strlcat(buf, "      --appendconfig=FILE\n"
34886             "                        Extra config files are loaded in, "
34887             "and take priority over\n"
34888             "                        config selected in -c (or default). "
34889             "Multiple configs are\n"
34890             "                        delimited by '|'.\n", sizeof(buf));
34891 #ifdef HAVE_DYNAMIC
34892       strlcat(buf, "  -L, --libretro=FILE   Path to libretro implementation. "
34893             "Overrides any config setting.\n", sizeof(buf));
34894 #endif
34895       strlcat(buf, "      --subsystem=NAME  Use a subsystem of the libretro core. "
34896             "Multiple content\n"
34897             "                        files are loaded as multiple arguments. "
34898             "If a content\n"
34899             "                        file is skipped, use a blank (\"\") "
34900             "command line argument.\n"
34901             "                        Content must be loaded in an order "
34902             "which depends on the\n"
34903             "                        particular subsystem used. See verbose "
34904             "log output to learn\n"
34905             "                        how a particular subsystem wants content "
34906             "to be loaded.\n", sizeof(buf));
34907       puts(buf);
34908    }
34909 
34910    printf("  -N, --nodevice=PORT\n"
34911           "                        Disconnects controller device connected "
34912           "to PORT (1 to %d).\n", MAX_USERS);
34913    printf("  -A, --dualanalog=PORT\n"
34914           "                        Connect a DualAnalog controller to PORT "
34915           "(1 to %d).\n", MAX_USERS);
34916    printf("  -d, --device=PORT:ID\n"
34917           "                        Connect a generic device into PORT of "
34918           "the device (1 to %d).\n", MAX_USERS);
34919 
34920    {
34921       char buf[2560];
34922       buf[0] = '\0';
34923       strlcpy(buf, "                        Format is PORT:ID, where ID is a number "
34924             "corresponding to the particular device.\n", sizeof(buf));
34925 #ifdef HAVE_BSV_MOVIE
34926       strlcat(buf, "  -P, --bsvplay=FILE    Playback a BSV movie file.\n", sizeof(buf));
34927       strlcat(buf, "  -R, --bsvrecord=FILE  Start recording a BSV movie file from "
34928             "the beginning.\n", sizeof(buf));
34929       strlcat(buf, "      --eof-exit        Exit upon reaching the end of the "
34930             "BSV movie file.\n", sizeof(buf));
34931 #endif
34932       strlcat(buf, "  -M, --sram-mode=MODE  SRAM handling mode. MODE can be "
34933             "'noload-nosave',\n"
34934             "                        'noload-save', 'load-nosave' or "
34935             "'load-save'.\n"
34936             "                        Note: 'noload-save' implies that "
34937             "save files *WILL BE OVERWRITTEN*.\n", sizeof(buf));
34938 #ifdef HAVE_NETWORKING
34939       strlcat(buf, "  -H, --host            Host netplay as user 1.\n", sizeof(buf));
34940       strlcat(buf, "  -C, --connect=HOST    Connect to netplay server as user 2.\n", sizeof(buf));
34941       strlcat(buf, "      --port=PORT       Port used to netplay. Default is 55435.\n", sizeof(buf));
34942       strlcat(buf, "      --stateless       Use \"stateless\" mode for netplay\n", sizeof(buf));
34943       strlcat(buf, "                        (requires a very fast network).\n", sizeof(buf));
34944       strlcat(buf, "      --check-frames=NUMBER\n"
34945             "                        Check frames when using netplay.\n", sizeof(buf));
34946 #ifdef HAVE_NETWORK_CMD
34947       strlcat(buf, "      --command         Sends a command over UDP to an already "
34948             "running program process.\n", sizeof(buf));
34949       strlcat(buf, "      Available commands are listed if command is invalid.\n", sizeof(buf));
34950 #endif
34951 
34952 #endif
34953 
34954       strlcat(buf, "      --nick=NICK       Picks a username (for use with netplay). "
34955             "Not mandatory.\n", sizeof(buf));
34956       strlcat(buf, "  -r, --record=FILE     Path to record video file.\n        "
34957             "Using .mkv extension is recommended.\n", sizeof(buf));
34958       strlcat(buf, "      --recordconfig    Path to settings used during recording.\n", sizeof(buf));
34959       strlcat(buf, "      --size=WIDTHxHEIGHT\n"
34960             "                        Overrides output video size when recording.\n", sizeof(buf));
34961 #ifdef HAVE_PATCH
34962       strlcat(buf, "  -U, --ups=FILE        Specifies path for UPS patch that will be "
34963             "applied to content.\n", sizeof(buf));
34964       strlcat(buf, "      --bps=FILE        Specifies path for BPS patch that will be "
34965             "applied to content.\n", sizeof(buf));
34966       strlcat(buf, "      --ips=FILE        Specifies path for IPS patch that will be "
34967             "applied to content.\n", sizeof(buf));
34968       strlcat(buf, "      --no-patch        Disables all forms of content patching.\n", sizeof(buf));
34969 #endif
34970       strlcat(buf, "  -D, --detach          Detach program from the running console. "
34971             "Not relevant for all platforms.\n", sizeof(buf));
34972       strlcat(buf, "      --max-frames=NUMBER\n"
34973             "                        Runs for the specified number of frames, "
34974             "then exits.\n", sizeof(buf));
34975 #ifdef HAVE_SCREENSHOTS
34976       strlcat(buf, "      --max-frames-ss\n"
34977             "                        Takes a screenshot at the end of max-frames.\n", sizeof(buf));
34978       strlcat(buf, "      --max-frames-ss-path=FILE\n"
34979             "                        Path to save the screenshot to at the end of max-frames.\n", sizeof(buf));
34980 #endif
34981 #ifdef HAVE_ACCESSIBILITY
34982       strlcat(buf, "      --accessibility\n"
34983             "                        Enables accessibilty for blind users using text-to-speech.\n", sizeof(buf));
34984 #endif
34985       strlcat(buf, "      --load-menu-on-error\n"
34986             "                        Open menu instead of quitting if specified core or content fails to load.\n", sizeof(buf));
34987       puts(buf);
34988    }
34989 }
34990 
34991 /**
34992  * retroarch_parse_input_and_config:
34993  * @argc                 : Count of (commandline) arguments.
34994  * @argv                 : (Commandline) arguments.
34995  *
34996  * Parses (commandline) arguments passed to program and loads the config file,
34997  * with command line options overriding the config file.
34998  *
34999  **/
retroarch_parse_input_and_config(struct rarch_state * p_rarch,global_t * global,int argc,char * argv[])35000 static bool retroarch_parse_input_and_config(
35001       struct rarch_state *p_rarch,
35002       global_t *global,
35003       int argc, char *argv[])
35004 {
35005    unsigned i;
35006    static bool           first_run = true;
35007    bool verbosity_enabled          = false;
35008    const char           *optstring = NULL;
35009    bool              explicit_menu = false;
35010    bool                 cli_active = false;
35011    bool               cli_core_set = false;
35012    bool            cli_content_set = false;
35013 
35014    const struct option opts[]      = {
35015 #ifdef HAVE_DYNAMIC
35016       { "libretro",           1, NULL, 'L' },
35017 #endif
35018       { "menu",               0, NULL, RA_OPT_MENU },
35019       { "help",               0, NULL, 'h' },
35020       { "save",               1, NULL, 's' },
35021       { "fullscreen",         0, NULL, 'f' },
35022       { "record",             1, NULL, 'r' },
35023       { "recordconfig",       1, NULL, RA_OPT_RECORDCONFIG },
35024       { "size",               1, NULL, RA_OPT_SIZE },
35025       { "verbose",            0, NULL, 'v' },
35026 #ifdef HAVE_CONFIGFILE
35027       { "config",             1, NULL, 'c' },
35028       { "appendconfig",       1, NULL, RA_OPT_APPENDCONFIG },
35029 #endif
35030       { "nodevice",           1, NULL, 'N' },
35031       { "dualanalog",         1, NULL, 'A' },
35032       { "device",             1, NULL, 'd' },
35033       { "savestate",          1, NULL, 'S' },
35034       { "set-shader",         1, NULL, RA_OPT_SET_SHADER },
35035 #ifdef HAVE_BSV_MOVIE
35036       { "bsvplay",            1, NULL, 'P' },
35037       { "bsvrecord",          1, NULL, 'R' },
35038 #endif
35039       { "sram-mode",          1, NULL, 'M' },
35040 #ifdef HAVE_NETWORKING
35041       { "host",               0, NULL, 'H' },
35042       { "connect",            1, NULL, 'C' },
35043       { "stateless",          0, NULL, RA_OPT_STATELESS },
35044       { "check-frames",       1, NULL, RA_OPT_CHECK_FRAMES },
35045       { "port",               1, NULL, RA_OPT_PORT },
35046 #ifdef HAVE_NETWORK_CMD
35047       { "command",            1, NULL, RA_OPT_COMMAND },
35048 #endif
35049 #endif
35050       { "nick",               1, NULL, RA_OPT_NICK },
35051 #ifdef HAVE_PATCH
35052       { "ups",                1, NULL, 'U' },
35053       { "bps",                1, NULL, RA_OPT_BPS },
35054       { "ips",                1, NULL, RA_OPT_IPS },
35055       { "no-patch",           0, NULL, RA_OPT_NO_PATCH },
35056 #endif
35057       { "detach",             0, NULL, 'D' },
35058       { "features",           0, NULL, RA_OPT_FEATURES },
35059       { "subsystem",          1, NULL, RA_OPT_SUBSYSTEM },
35060       { "max-frames",         1, NULL, RA_OPT_MAX_FRAMES },
35061       { "max-frames-ss",      0, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT },
35062       { "max-frames-ss-path", 1, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT_PATH },
35063       { "eof-exit",           0, NULL, RA_OPT_EOF_EXIT },
35064       { "version",            0, NULL, RA_OPT_VERSION },
35065       { "log-file",           1, NULL, RA_OPT_LOG_FILE },
35066       { "accessibility",      0, NULL, RA_OPT_ACCESSIBILITY},
35067       { "load-menu-on-error", 0, NULL, RA_OPT_LOAD_MENU_ON_ERROR },
35068       { NULL, 0, NULL, 0 }
35069    };
35070 
35071    if (first_run)
35072    {
35073       /* Copy the args into a buffer so launch arguments can be reused */
35074       for (i = 0; i < (unsigned)argc; i++)
35075       {
35076          strlcat(p_rarch->launch_arguments,
35077                argv[i], sizeof(p_rarch->launch_arguments));
35078          strlcat(p_rarch->launch_arguments, " ",
35079                sizeof(p_rarch->launch_arguments));
35080       }
35081       string_trim_whitespace_left(p_rarch->launch_arguments);
35082       string_trim_whitespace_right(p_rarch->launch_arguments);
35083 
35084       first_run = false;
35085 
35086       /* Command line interface is only considered
35087        * to be 'active' (i.e. used by a third party)
35088        * if this is the first run (subsequent runs
35089        * are triggered by RetroArch itself) */
35090       cli_active = true;
35091    }
35092 
35093    /* Handling the core type is finicky. Based on the arguments we pass in,
35094     * we handle it differently.
35095     * Some current cases which track desired behavior and how it is supposed to work:
35096     *
35097     * Dynamically linked RA:
35098     * ./retroarch                            -> CORE_TYPE_DUMMY
35099     * ./retroarch -v                         -> CORE_TYPE_DUMMY + verbose
35100     * ./retroarch --menu                     -> CORE_TYPE_DUMMY
35101     * ./retroarch --menu -v                  -> CORE_TYPE_DUMMY + verbose
35102     * ./retroarch -L contentless-core        -> CORE_TYPE_PLAIN
35103     * ./retroarch -L content-core            -> CORE_TYPE_PLAIN + FAIL (This currently crashes)
35104     * ./retroarch [-L content-core] ROM      -> CORE_TYPE_PLAIN
35105     * ./retroarch <-L or ROM> --menu         -> FAIL
35106     *
35107     * The heuristic here seems to be that if we use the -L CLI option or
35108     * optind < argc at the end we should set CORE_TYPE_PLAIN.
35109     * To handle --menu, we should ensure that CORE_TYPE_DUMMY is still set
35110     * otherwise, fail early, since the CLI options are non-sensical.
35111     * We could also simply ignore --menu in this case to be more friendly with
35112     * bogus arguments.
35113     */
35114 
35115    if (!p_rarch->has_set_core)
35116       retroarch_set_current_core_type(CORE_TYPE_DUMMY, false);
35117 
35118    path_clear(RARCH_PATH_SUBSYSTEM);
35119 
35120    retroarch_override_setting_free_state();
35121 
35122    p_rarch->has_set_username             = false;
35123 #ifdef HAVE_PATCH
35124    p_rarch->rarch_ups_pref               = false;
35125    p_rarch->rarch_ips_pref               = false;
35126    p_rarch->rarch_bps_pref               = false;
35127    *global->name.ups                     = '\0';
35128    *global->name.bps                     = '\0';
35129    *global->name.ips                     = '\0';
35130 #endif
35131 #ifdef HAVE_CONFIGFILE
35132    runloop_state.overrides_active     = false;
35133 #endif
35134    global->cli_load_menu_on_error        = false;
35135 
35136    /* Make sure we can call retroarch_parse_input several times ... */
35137    optind    = 0;
35138    optstring = "hs:fvS:A:U:DN:d:"
35139       BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG CONFIG_FILE_ARG;
35140 
35141 #ifdef ORBIS
35142    argv      = &(argv[2]);
35143    argc      = argc - 2;
35144 #endif
35145 
35146 #ifndef HAVE_MENU
35147    if (argc == 1)
35148    {
35149       printf("%s\n", msg_hash_to_str(MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN));
35150       retroarch_print_help(argv[0]);
35151       exit(0);
35152    }
35153 #endif
35154 
35155    /* First pass: Read the config file path and any directory overrides, so
35156     * they're in place when we load the config */
35157    if (argc)
35158    {
35159       for (;;)
35160       {
35161          int c = getopt_long(argc, argv, optstring, opts, NULL);
35162 
35163 #if 0
35164          fprintf(stderr, "c is: %c (%d), optarg is: [%s]\n", c, c, string_is_empty(optarg) ? "" : optarg);
35165 #endif
35166 
35167          if (c == -1)
35168             break;
35169 
35170          switch (c)
35171          {
35172             case 'h':
35173                retroarch_print_help(argv[0]);
35174                exit(0);
35175 
35176 #ifdef HAVE_CONFIGFILE
35177             case 'c':
35178                path_set(RARCH_PATH_CONFIG, optarg);
35179                break;
35180             case RA_OPT_APPENDCONFIG:
35181                path_set(RARCH_PATH_CONFIG_APPEND, optarg);
35182                break;
35183 #endif
35184 
35185             case 's':
35186                strlcpy(global->name.savefile, optarg,
35187                      sizeof(global->name.savefile));
35188                retroarch_override_setting_set(
35189                      RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL);
35190                break;
35191 
35192             case 'S':
35193                strlcpy(global->name.savestate, optarg,
35194                      sizeof(global->name.savestate));
35195                retroarch_override_setting_set(
35196                      RARCH_OVERRIDE_SETTING_STATE_PATH, NULL);
35197                break;
35198 
35199             /* Must handle '?' otherwise you get an infinite loop */
35200             case '?':
35201                retroarch_print_help(argv[0]);
35202                retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35203                break;
35204             /* All other arguments are handled in the second pass */
35205          }
35206       }
35207    }
35208 
35209    /* Flush out some states that could have been set
35210     * by core environment variables. */
35211    p_rarch->current_core.has_set_input_descriptors = false;
35212    p_rarch->current_core.has_set_subsystems        = false;
35213 
35214    /* Load the config file now that we know what it is */
35215 #ifdef HAVE_CONFIGFILE
35216    if (!p_rarch->rarch_block_config_read)
35217 #endif
35218    {
35219       /* If this is a static build, load salamander
35220        * config file first (sets RARCH_PATH_CORE) */
35221 #if !defined(HAVE_DYNAMIC)
35222       config_load_file_salamander();
35223 #endif
35224       config_load(&p_rarch->g_extern);
35225    }
35226 
35227    /* Second pass: All other arguments override the config file */
35228    optind = 1;
35229 
35230    if (argc)
35231    {
35232       for (;;)
35233       {
35234          int c = getopt_long(argc, argv, optstring, opts, NULL);
35235 
35236          if (c == -1)
35237             break;
35238 
35239          switch (c)
35240          {
35241             case 'd':
35242                {
35243                   unsigned new_port;
35244                   unsigned id              = 0;
35245                   struct string_list *list = string_split(optarg, ":");
35246                   int    port              = 0;
35247 
35248                   if (list && list->size == 2)
35249                   {
35250                      port = (int)strtol(list->elems[0].data, NULL, 0);
35251                      id   = (unsigned)strtoul(list->elems[1].data, NULL, 0);
35252                   }
35253                   string_list_free(list);
35254 
35255                   if (port < 1 || port > MAX_USERS)
35256                   {
35257                      RARCH_ERR("%s\n", msg_hash_to_str(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT));
35258                      retroarch_print_help(argv[0]);
35259                      retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35260                   }
35261                   new_port = port -1;
35262 
35263                   input_config_set_device(new_port, id);
35264 
35265                   retroarch_override_setting_set(
35266                         RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &new_port);
35267                }
35268                break;
35269 
35270             case 'A':
35271                {
35272                   unsigned new_port;
35273                   int port = (int)strtol(optarg, NULL, 0);
35274 
35275                   if (port < 1 || port > MAX_USERS)
35276                   {
35277                      RARCH_ERR("Connect dualanalog to a valid port.\n");
35278                      retroarch_print_help(argv[0]);
35279                      retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35280                   }
35281                   new_port = port - 1;
35282 
35283                   input_config_set_device(new_port, RETRO_DEVICE_ANALOG);
35284                   retroarch_override_setting_set(
35285                         RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &new_port);
35286                }
35287                break;
35288 
35289             case 'f':
35290                p_rarch->rarch_force_fullscreen = true;
35291                break;
35292 
35293             case 'v':
35294                verbosity_enable();
35295                retroarch_override_setting_set(
35296                      RARCH_OVERRIDE_SETTING_VERBOSITY, NULL);
35297                break;
35298 
35299             case 'N':
35300                {
35301                   unsigned new_port;
35302                   int port = (int)strtol(optarg, NULL, 0);
35303 
35304                   if (port < 1 || port > MAX_USERS)
35305                   {
35306                      RARCH_ERR("%s\n",
35307                            msg_hash_to_str(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT));
35308                      retroarch_print_help(argv[0]);
35309                      retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35310                   }
35311                   new_port = port - 1;
35312                   input_config_set_device(port - 1, RETRO_DEVICE_NONE);
35313                   retroarch_override_setting_set(
35314                         RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE, &new_port);
35315                }
35316                break;
35317 
35318             case 'r':
35319                strlcpy(global->record.path, optarg,
35320                      sizeof(global->record.path));
35321                if (p_rarch->recording_enable)
35322                   p_rarch->recording_enable = true;
35323                break;
35324 
35325             case RA_OPT_SET_SHADER:
35326 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
35327                /* disable auto-shaders */
35328                if (string_is_empty(optarg))
35329                {
35330                   p_rarch->cli_shader_disable = true;
35331                   break;
35332                }
35333 
35334                /* rebase on shader directory */
35335                if (!path_is_absolute(optarg))
35336                {
35337                   settings_t *settings = p_rarch->configuration_settings;
35338                   char       *ref_path = settings->paths.directory_video_shader;
35339                   fill_pathname_join(p_rarch->cli_shader,
35340                         ref_path, optarg, sizeof(p_rarch->cli_shader));
35341                   break;
35342                }
35343 
35344                strlcpy(p_rarch->cli_shader, optarg, sizeof(p_rarch->cli_shader));
35345 #endif
35346                break;
35347 
35348    #ifdef HAVE_DYNAMIC
35349             case 'L':
35350                {
35351                   int path_stats;
35352 
35353                   if (string_ends_with_size(optarg, "builtin",
35354                            strlen(optarg), STRLEN_CONST("builtin")))
35355                   {
35356                      RARCH_LOG("--libretro argument \"%s\" is a built-in core. Ignoring.\n",
35357                            optarg);
35358                      break;
35359                   }
35360 
35361                   path_stats = path_stat(optarg);
35362 
35363                   if ((path_stats & RETRO_VFS_STAT_IS_DIRECTORY) != 0)
35364                   {
35365                      settings_t *settings = p_rarch->configuration_settings;
35366 
35367                      path_clear(RARCH_PATH_CORE);
35368 
35369                      configuration_set_string(settings,
35370                      settings->paths.directory_libretro, optarg);
35371 
35372                      retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
35373                      retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY, NULL);
35374                      RARCH_WARN("Using old --libretro behavior. "
35375                            "Setting libretro_directory to \"%s\" instead.\n",
35376                            optarg);
35377                   }
35378                   else if ((path_stats & RETRO_VFS_STAT_IS_VALID) != 0)
35379                   {
35380                      path_set(RARCH_PATH_CORE, optarg);
35381                      retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
35382 
35383                      /* We requested explicit core, so use PLAIN core type. */
35384                      retroarch_set_current_core_type(CORE_TYPE_PLAIN, false);
35385                   }
35386                   else
35387                   {
35388                      RARCH_WARN("--libretro argument \"%s\" is neither a file nor directory. Ignoring.\n",
35389                            optarg);
35390                   }
35391                }
35392                break;
35393    #endif
35394             case 'P':
35395 #ifdef HAVE_BSV_MOVIE
35396                strlcpy(p_rarch->bsv_movie_state.movie_start_path, optarg,
35397                      sizeof(p_rarch->bsv_movie_state.movie_start_path));
35398 
35399                p_rarch->bsv_movie_state.movie_start_playback  = true;
35400                p_rarch->bsv_movie_state.movie_start_recording = false;
35401 #endif
35402                break;
35403             case 'R':
35404 #ifdef HAVE_BSV_MOVIE
35405                strlcpy(p_rarch->bsv_movie_state.movie_start_path, optarg,
35406                      sizeof(p_rarch->bsv_movie_state.movie_start_path));
35407 
35408                p_rarch->bsv_movie_state.movie_start_playback  = false;
35409                p_rarch->bsv_movie_state.movie_start_recording = true;
35410 #endif
35411                break;
35412 
35413             case 'M':
35414                if (string_is_equal(optarg, "noload-nosave"))
35415                {
35416                   p_rarch->rarch_is_sram_load_disabled = true;
35417                   p_rarch->rarch_is_sram_save_disabled = true;
35418                }
35419                else if (string_is_equal(optarg, "noload-save"))
35420                   p_rarch->rarch_is_sram_load_disabled = true;
35421                else if (string_is_equal(optarg, "load-nosave"))
35422                   p_rarch->rarch_is_sram_save_disabled = true;
35423                else if (string_is_not_equal(optarg, "load-save"))
35424                {
35425                   RARCH_ERR("Invalid argument in --sram-mode.\n");
35426                   retroarch_print_help(argv[0]);
35427                   retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35428                }
35429                break;
35430 
35431 #ifdef HAVE_NETWORKING
35432             case 'H':
35433                retroarch_override_setting_set(
35434                      RARCH_OVERRIDE_SETTING_NETPLAY_MODE, NULL);
35435                netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_SERVER, NULL);
35436                break;
35437 
35438             case 'C':
35439                {
35440                   settings_t *settings = p_rarch->configuration_settings;
35441                   retroarch_override_setting_set(
35442                         RARCH_OVERRIDE_SETTING_NETPLAY_MODE, NULL);
35443                   retroarch_override_setting_set(
35444                         RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS, NULL);
35445                   netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
35446                   configuration_set_string(settings,
35447                   settings->paths.netplay_server, optarg);
35448                }
35449                break;
35450 
35451             case RA_OPT_STATELESS:
35452                {
35453                   settings_t *settings = p_rarch->configuration_settings;
35454 
35455                   configuration_set_bool(settings,
35456                         settings->bools.netplay_stateless_mode, true);
35457 
35458                   retroarch_override_setting_set(
35459                         RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE, NULL);
35460                }
35461                break;
35462 
35463             case RA_OPT_CHECK_FRAMES:
35464                {
35465                   settings_t *settings = p_rarch->configuration_settings;
35466                   retroarch_override_setting_set(
35467                         RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES, NULL);
35468 
35469                   configuration_set_int(settings,
35470                         settings->ints.netplay_check_frames,
35471                         (int)strtoul(optarg, NULL, 0));
35472                }
35473                break;
35474 
35475             case RA_OPT_PORT:
35476                {
35477                   settings_t *settings = p_rarch->configuration_settings;
35478                   retroarch_override_setting_set(
35479                         RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT, NULL);
35480                   configuration_set_uint(settings,
35481                         settings->uints.netplay_port,
35482                         (int)strtoul(optarg, NULL, 0));
35483                }
35484                break;
35485 
35486 #ifdef HAVE_NETWORK_CMD
35487             case RA_OPT_COMMAND:
35488 #ifdef HAVE_COMMAND
35489                if (command_network_send((const char*)optarg))
35490                   exit(0);
35491                else
35492                   retroarch_fail(p_rarch, 1, "network_cmd_send()");
35493 #endif
35494                break;
35495 #endif
35496 
35497 #endif
35498 
35499             case RA_OPT_BPS:
35500 #ifdef HAVE_PATCH
35501                strlcpy(global->name.bps, optarg,
35502                      sizeof(global->name.bps));
35503                p_rarch->rarch_bps_pref = true;
35504                retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_BPS_PREF, NULL);
35505 #endif
35506                break;
35507 
35508             case 'U':
35509 #ifdef HAVE_PATCH
35510                strlcpy(global->name.ups, optarg,
35511                      sizeof(global->name.ups));
35512                p_rarch->rarch_ups_pref = true;
35513                retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_UPS_PREF, NULL);
35514 #endif
35515                break;
35516 
35517             case RA_OPT_IPS:
35518 #ifdef HAVE_PATCH
35519                strlcpy(global->name.ips, optarg,
35520                      sizeof(global->name.ips));
35521                p_rarch->rarch_ips_pref = true;
35522                retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_IPS_PREF, NULL);
35523 #endif
35524                break;
35525 
35526             case RA_OPT_NO_PATCH:
35527 #ifdef HAVE_PATCH
35528                p_rarch->rarch_patch_blocked = true;
35529 #endif
35530                break;
35531 
35532             case 'D':
35533                frontend_driver_detach_console();
35534                break;
35535 
35536             case RA_OPT_MENU:
35537                explicit_menu = true;
35538                break;
35539 
35540             case RA_OPT_NICK:
35541                {
35542                   settings_t *settings      = p_rarch->configuration_settings;
35543 
35544                   p_rarch->has_set_username = true;
35545 
35546                   configuration_set_string(settings,
35547                   settings->paths.username, optarg);
35548                }
35549                break;
35550 
35551             case RA_OPT_SIZE:
35552                if (sscanf(optarg, "%ux%u",
35553                         &p_rarch->recording_width,
35554                         &p_rarch->recording_height) != 2)
35555                {
35556                   RARCH_ERR("Wrong format for --size.\n");
35557                   retroarch_print_help(argv[0]);
35558                   retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35559                }
35560                break;
35561 
35562             case RA_OPT_RECORDCONFIG:
35563                strlcpy(global->record.config, optarg,
35564                      sizeof(global->record.config));
35565                break;
35566 
35567             case RA_OPT_MAX_FRAMES:
35568                runloop_state.max_frames  = (unsigned)strtoul(optarg, NULL, 10);
35569                break;
35570 
35571             case RA_OPT_MAX_FRAMES_SCREENSHOT:
35572 #ifdef HAVE_SCREENSHOTS
35573                runloop_state.max_frames_screenshot = true;
35574 #endif
35575                break;
35576 
35577             case RA_OPT_MAX_FRAMES_SCREENSHOT_PATH:
35578 #ifdef HAVE_SCREENSHOTS
35579                strlcpy(runloop_state.max_frames_screenshot_path,
35580                      optarg,
35581                      sizeof(runloop_state.max_frames_screenshot_path));
35582 #endif
35583                break;
35584 
35585             case RA_OPT_SUBSYSTEM:
35586                path_set(RARCH_PATH_SUBSYSTEM, optarg);
35587                break;
35588 
35589             case RA_OPT_FEATURES:
35590                retroarch_print_features();
35591                exit(0);
35592 
35593             case RA_OPT_EOF_EXIT:
35594 #ifdef HAVE_BSV_MOVIE
35595                p_rarch->bsv_movie_state.eof_exit = true;
35596 #endif
35597                break;
35598 
35599             case RA_OPT_VERSION:
35600                retroarch_print_version();
35601                exit(0);
35602 
35603             case RA_OPT_LOG_FILE:
35604                /* Enable 'log to file' */
35605                configuration_set_bool(p_rarch->configuration_settings,
35606                      p_rarch->configuration_settings->bools.log_to_file, true);
35607 
35608                retroarch_override_setting_set(
35609                      RARCH_OVERRIDE_SETTING_LOG_TO_FILE, NULL);
35610 
35611                /* Cache log file path override */
35612                rarch_log_file_set_override(optarg);
35613                break;
35614 
35615             case 'h':
35616 #ifdef HAVE_CONFIGFILE
35617             case 'c':
35618             case RA_OPT_APPENDCONFIG:
35619 #endif
35620             case 's':
35621             case 'S':
35622                break; /* Handled in the first pass */
35623 
35624             case '?':
35625                retroarch_print_help(argv[0]);
35626                retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35627             case RA_OPT_ACCESSIBILITY:
35628 #ifdef HAVE_ACCESSIBILITY
35629                p_rarch->accessibility_enabled = true;
35630 #endif
35631                break;
35632             case RA_OPT_LOAD_MENU_ON_ERROR:
35633                global->cli_load_menu_on_error = true;
35634                break;
35635             default:
35636                RARCH_ERR("%s\n", msg_hash_to_str(MSG_ERROR_PARSING_ARGUMENTS));
35637                retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35638          }
35639       }
35640    }
35641 
35642    verbosity_enabled = verbosity_is_enabled();
35643 
35644    if (verbosity_enabled)
35645       rarch_log_file_init(
35646             p_rarch->configuration_settings->bools.log_to_file,
35647             p_rarch->configuration_settings->bools.log_to_file_timestamp,
35648             p_rarch->configuration_settings->paths.log_dir);
35649 
35650 #ifdef HAVE_GIT_VERSION
35651    RARCH_LOG("RetroArch %s (Git %s)\n",
35652          PACKAGE_VERSION, retroarch_git_version);
35653 #endif
35654 
35655    if (explicit_menu)
35656    {
35657       if (optind < argc)
35658       {
35659          RARCH_ERR("--menu was used, but content file was passed as well.\n");
35660          retroarch_fail(p_rarch, 1, "retroarch_parse_input()");
35661       }
35662 #ifdef HAVE_DYNAMIC
35663       else
35664       {
35665          /* Allow stray -L arguments to go through to workaround cases
35666           * where it's used as "config file".
35667           *
35668           * This seems to still be the case for Android, which
35669           * should be properly fixed. */
35670          retroarch_set_current_core_type(CORE_TYPE_DUMMY, false);
35671       }
35672 #endif
35673    }
35674 
35675    if (optind < argc)
35676    {
35677       bool subsystem_path_is_empty = path_is_empty(RARCH_PATH_SUBSYSTEM);
35678 
35679       /* We requested explicit ROM, so use PLAIN core type. */
35680       retroarch_set_current_core_type(CORE_TYPE_PLAIN, false);
35681 
35682       if (subsystem_path_is_empty)
35683          path_set(RARCH_PATH_NAMES, (const char*)argv[optind]);
35684       else
35685          path_set_special(argv + optind, argc - optind);
35686 
35687       /* Register that content has been set via the
35688        * command line interface */
35689       cli_content_set = true;
35690    }
35691 
35692    /* Check whether a core has been set via the
35693     * command line interface */
35694    cli_core_set = (p_rarch->current_core_type != CORE_TYPE_DUMMY);
35695 
35696    /* Update global 'content launched from command
35697     * line' status flag */
35698    global->launched_from_cli = cli_active && (cli_core_set || cli_content_set);
35699 
35700    /* Copy SRM/state dirs used, so they can be reused on reentrancy. */
35701    if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL) &&
35702          path_is_directory(global->name.savefile))
35703       dir_set(RARCH_DIR_SAVEFILE, global->name.savefile);
35704 
35705    if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_STATE_PATH, NULL) &&
35706          path_is_directory(global->name.savestate))
35707       dir_set(RARCH_DIR_SAVESTATE, global->name.savestate);
35708 
35709    return verbosity_enabled;
35710 }
35711 
retroarch_validate_per_core_options(char * s,size_t len,bool mkdir,const char * core_name,const char * game_name)35712 static bool retroarch_validate_per_core_options(char *s,
35713       size_t len, bool mkdir,
35714       const char *core_name, const char *game_name)
35715 {
35716    char config_directory[PATH_MAX_LENGTH];
35717    config_directory[0] = '\0';
35718 
35719    if (!s ||
35720        (len < 1) ||
35721        string_is_empty(core_name) ||
35722        string_is_empty(game_name))
35723       return false;
35724 
35725    fill_pathname_application_special(config_directory,
35726          sizeof(config_directory), APPLICATION_SPECIAL_DIRECTORY_CONFIG);
35727 
35728    fill_pathname_join_special_ext(s,
35729          config_directory, core_name, game_name,
35730          ".opt", len);
35731 
35732    /* No need to make a directory if file already exists... */
35733    if (mkdir && !path_is_valid(s))
35734    {
35735       char new_path[PATH_MAX_LENGTH];
35736       new_path[0]             = '\0';
35737 
35738       fill_pathname_join(new_path,
35739             config_directory, core_name, sizeof(new_path));
35740 
35741       if (!path_is_directory(new_path))
35742          path_mkdir(new_path);
35743    }
35744 
35745    return true;
35746 }
35747 
retroarch_validate_game_options(char * s,size_t len,bool mkdir)35748 static bool retroarch_validate_game_options(
35749       char *s, size_t len, bool mkdir)
35750 {
35751    const char *core_name       = runloop_state.system.info.library_name;
35752    const char *game_name       = path_basename(path_get(RARCH_PATH_BASENAME));
35753 
35754    return retroarch_validate_per_core_options(s, len, mkdir,
35755          core_name, game_name);
35756 }
35757 
retroarch_validate_folder_options(char * s,size_t len,bool mkdir)35758 static bool retroarch_validate_folder_options(
35759       char *s, size_t len, bool mkdir)
35760 {
35761    char folder_name[PATH_MAX_LENGTH];
35762    const char *core_name       = runloop_state.system.info.library_name;
35763    const char *game_path       = path_get(RARCH_PATH_BASENAME);
35764 
35765    folder_name[0] = '\0';
35766 
35767    if (string_is_empty(game_path))
35768       return false;
35769 
35770    fill_pathname_parent_dir_name(folder_name,
35771          game_path, sizeof(folder_name));
35772 
35773    return retroarch_validate_per_core_options(s, len, mkdir,
35774          core_name, folder_name);
35775 }
35776 
35777 /* Validates CPU features for given processor architecture.
35778  * Make sure we haven't compiled for something we cannot run.
35779  * Ideally, code would get swapped out depending on CPU support,
35780  * but this will do for now. */
retroarch_validate_cpu_features(struct rarch_state * p_rarch)35781 static void retroarch_validate_cpu_features(struct rarch_state *p_rarch)
35782 {
35783    uint64_t cpu = cpu_features_get();
35784    (void)cpu;
35785 
35786 #ifdef __MMX__
35787    if (!(cpu & RETRO_SIMD_MMX))
35788       FAIL_CPU(p_rarch, "MMX");
35789 #endif
35790 #ifdef __SSE__
35791    if (!(cpu & RETRO_SIMD_SSE))
35792       FAIL_CPU(p_rarch, "SSE");
35793 #endif
35794 #ifdef __SSE2__
35795    if (!(cpu & RETRO_SIMD_SSE2))
35796       FAIL_CPU(p_rarch, "SSE2");
35797 #endif
35798 #ifdef __AVX__
35799    if (!(cpu & RETRO_SIMD_AVX))
35800       FAIL_CPU(p_rarch, "AVX");
35801 #endif
35802 }
35803 
35804 #ifdef HAVE_MENU
menu_driver_find_driver(settings_t * settings,const char * prefix,bool verbosity_enabled)35805 static const menu_ctx_driver_t *menu_driver_find_driver(
35806       settings_t *settings,
35807       const char *prefix,
35808       bool verbosity_enabled)
35809 {
35810    int i = (int)driver_find_index("menu_driver",
35811          settings->arrays.menu_driver);
35812 
35813    if (i >= 0)
35814       return (const menu_ctx_driver_t*)menu_ctx_drivers[i];
35815 
35816    if (verbosity_enabled)
35817    {
35818       unsigned d;
35819       RARCH_WARN("Couldn't find any %s named \"%s\"\n", prefix,
35820             settings->arrays.menu_driver);
35821       RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
35822       for (d = 0; menu_ctx_drivers[d]; d++)
35823       {
35824          if (menu_ctx_drivers[d])
35825          {
35826             RARCH_LOG_OUTPUT("\t%s\n", menu_ctx_drivers[d]->ident);
35827          }
35828       }
35829       RARCH_WARN("Going to default to first %s...\n", prefix);
35830    }
35831 
35832    return (const menu_ctx_driver_t*)menu_ctx_drivers[0];
35833 }
35834 #endif
35835 
input_mapper_reset(input_mapper_t * handle)35836 static void input_mapper_reset(input_mapper_t *handle)
35837 {
35838    unsigned i;
35839    for (i = 0; i < MAX_USERS; i++)
35840    {
35841       unsigned j;
35842       for (j = 0; j < 8; j++)
35843       {
35844          handle->analog_value[i][j]           = 0;
35845          handle->buttons[i].data[j]           = 0;
35846          handle->buttons[i].analogs[j]        = 0;
35847          handle->buttons[i].analog_buttons[j] = 0;
35848       }
35849    }
35850    for (i = 0; i < RETROK_LAST; i++)
35851       handle->key_button[i]         = 0;
35852    for (i = 0; i < (RETROK_LAST / 32 + 1); i++)
35853       handle->keys[i]               = 0;
35854 }
35855 
35856 
35857 /**
35858  * retroarch_main_init:
35859  * @argc                 : Count of (commandline) arguments.
35860  * @argv                 : (Commandline) arguments.
35861  *
35862  * Initializes the program.
35863  *
35864  * Returns: true on success, otherwise false if there was an error.
35865  **/
retroarch_main_init(int argc,char * argv[])35866 bool retroarch_main_init(int argc, char *argv[])
35867 {
35868 #if defined(DEBUG) && defined(HAVE_DRMINGW)
35869    char log_file_name[128];
35870 #endif
35871    bool verbosity_enabled       = false;
35872    bool           init_failed   = false;
35873    struct rarch_state *p_rarch  = &rarch_st;
35874    settings_t *settings         = p_rarch->configuration_settings;
35875    global_t            *global  = &p_rarch->g_extern;
35876    bool accessibility_enable    = false;
35877    unsigned accessibility_narrator_speech_speed = 0;
35878 
35879    p_rarch->osk_idx             = OSK_LOWERCASE_LATIN;
35880    p_rarch->video_driver_active = true;
35881    p_rarch->audio_driver_active = true;
35882 
35883    if (setjmp(p_rarch->error_sjlj_context) > 0)
35884    {
35885       RARCH_ERR("%s: \"%s\"\n",
35886             msg_hash_to_str(MSG_FATAL_ERROR_RECEIVED_IN), p_rarch->error_string);
35887       goto error;
35888    }
35889 
35890    p_rarch->rarch_error_on_init = true;
35891 
35892    /* Have to initialise non-file logging once at the start... */
35893    retro_main_log_file_init(NULL, false);
35894 
35895    verbosity_enabled = retroarch_parse_input_and_config(p_rarch, &p_rarch->g_extern, argc, argv);
35896 
35897 #ifdef HAVE_ACCESSIBILITY
35898    accessibility_enable                = settings->bools.accessibility_enable;
35899    accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
35900    /* State that the narrator is on, and also include the first menu
35901       item we're on at startup. */
35902    if (is_accessibility_enabled(
35903             accessibility_enable,
35904             p_rarch->accessibility_enabled))
35905       accessibility_speak_priority(p_rarch,
35906             accessibility_enable,
35907             accessibility_narrator_speech_speed,
35908             "RetroArch accessibility on.  Main Menu Load Core.",
35909             10);
35910 #endif
35911 
35912    if (verbosity_enabled)
35913    {
35914       {
35915          char str_output[256];
35916          const char *cpu_model  = NULL;
35917          str_output[0] = '\0';
35918 
35919          cpu_model     = frontend_driver_get_cpu_model_name();
35920 
35921          strlcpy(str_output,
35922                "=== Build =======================================\n",
35923                sizeof(str_output));
35924 
35925          if (!string_is_empty(cpu_model))
35926          {
35927             strlcat(str_output, FILE_PATH_LOG_INFO " CPU Model Name: ", sizeof(str_output));
35928             strlcat(str_output, cpu_model, sizeof(str_output));
35929             strlcat(str_output, "\n", sizeof(str_output));
35930          }
35931 
35932          RARCH_LOG_OUTPUT(str_output);
35933       }
35934       {
35935          char str_output[256];
35936          char str[128];
35937          str[0]        = '\0';
35938 
35939          retroarch_get_capabilities(RARCH_CAPABILITIES_CPU, str, sizeof(str));
35940 
35941 #ifdef HAVE_GIT_VERSION
35942          snprintf(str_output, sizeof(str_output),
35943                "%s: %s" "\n" FILE_PATH_LOG_INFO " Built: " __DATE__ "\n" FILE_PATH_LOG_INFO " Version: " PACKAGE_VERSION "\n" FILE_PATH_LOG_INFO " Git: %s" "\n" FILE_PATH_LOG_INFO " =================================================\n",
35944                msg_hash_to_str(MSG_CAPABILITIES),
35945                str,
35946                retroarch_git_version
35947                );
35948 #else
35949          snprintf(str_output, sizeof(str_output),
35950                "%s: %s" "\n" FILE_PATH_LOG_INFO " Built: " __DATE__ "\n" FILE_PATH_LOG_INFO " Version: " PACKAGE_VERSION "\n" FILE_PATH_LOG_INFO " =================================================\n",
35951                msg_hash_to_str(MSG_CAPABILITIES),
35952                str);
35953 #endif
35954          RARCH_LOG_OUTPUT(str_output);
35955       }
35956    }
35957 
35958 #if defined(DEBUG) && defined(HAVE_DRMINGW)
35959    RARCH_LOG_OUTPUT("Initializing Dr.MingW Exception handler\n");
35960    fill_str_dated_filename(log_file_name, "crash",
35961          "log", sizeof(log_file_name));
35962    ExcHndlInit();
35963    ExcHndlSetLogFileNameA(log_file_name);
35964 #endif
35965 
35966    retroarch_validate_cpu_features(p_rarch);
35967    retroarch_init_task_queue();
35968 
35969    {
35970       const char    *fullpath  = path_get(RARCH_PATH_CONTENT);
35971 
35972       if (!string_is_empty(fullpath))
35973       {
35974          enum rarch_content_type cont_type = path_is_media_type(fullpath);
35975 #ifdef HAVE_IMAGEVIEWER
35976          bool builtin_imageviewer          = settings->bools.multimedia_builtin_imageviewer_enable;
35977 #endif
35978          bool builtin_mediaplayer          = settings->bools.multimedia_builtin_mediaplayer_enable;
35979 
35980          switch (cont_type)
35981          {
35982             case RARCH_CONTENT_MOVIE:
35983             case RARCH_CONTENT_MUSIC:
35984                if (builtin_mediaplayer)
35985                {
35986                   /* TODO/FIXME - it needs to become possible to
35987                    * switch between FFmpeg and MPV at runtime */
35988 #if defined(HAVE_MPV)
35989                   retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
35990                   retroarch_set_current_core_type(CORE_TYPE_MPV, false);
35991 #elif defined(HAVE_FFMPEG)
35992                   retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
35993                   retroarch_set_current_core_type(CORE_TYPE_FFMPEG, false);
35994 #endif
35995                }
35996                break;
35997 #ifdef HAVE_IMAGEVIEWER
35998             case RARCH_CONTENT_IMAGE:
35999                if (builtin_imageviewer)
36000                {
36001                   retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
36002                   retroarch_set_current_core_type(CORE_TYPE_IMAGEVIEWER, false);
36003                }
36004                break;
36005 #endif
36006 #ifdef HAVE_GONG
36007             case RARCH_CONTENT_GONG:
36008                retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL);
36009                retroarch_set_current_core_type(CORE_TYPE_GONG, false);
36010                break;
36011 #endif
36012             default:
36013                break;
36014          }
36015       }
36016    }
36017 
36018    /* Pre-initialize all drivers
36019     * Attempts to find a default driver for
36020     * all driver types.
36021     */
36022    audio_driver_find_driver(p_rarch, settings,
36023          "audio driver", verbosity_enabled);
36024    video_driver_find_driver(p_rarch, settings,
36025          "video driver", verbosity_enabled);
36026    input_driver_find_driver(p_rarch, settings,
36027          "input driver", verbosity_enabled);
36028    camera_driver_find_driver(p_rarch, settings,
36029          "camera driver", verbosity_enabled);
36030    bluetooth_driver_ctl(RARCH_BLUETOOTH_CTL_FIND_DRIVER, NULL);
36031    wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL);
36032    location_driver_find_driver(p_rarch, settings,
36033          "location driver", verbosity_enabled);
36034 #ifdef HAVE_MENU
36035    if (!(p_rarch->menu_driver_ctx = menu_driver_find_driver(settings,
36036          "menu driver", verbosity_enabled)))
36037       retroarch_fail(p_rarch, 1, "menu_driver_find_driver()");
36038 #endif
36039    /* Enforce stored brightness if needed */
36040    if (frontend_driver_can_set_screen_brightness())
36041       frontend_driver_set_screen_brightness(settings->uints.screen_brightness);
36042 
36043    /* Attempt to initialize core */
36044    if (p_rarch->has_set_core)
36045    {
36046       p_rarch->has_set_core = false;
36047       if (!command_event(CMD_EVENT_CORE_INIT,
36048                &p_rarch->explicit_current_core_type))
36049          init_failed = true;
36050    }
36051    else if (!command_event(CMD_EVENT_CORE_INIT,
36052             &p_rarch->current_core_type))
36053       init_failed = true;
36054 
36055    /* Handle core initialization failure */
36056    if (init_failed)
36057    {
36058 #ifdef HAVE_DYNAMIC
36059       /* Check if menu was active prior to core initialization */
36060       if (   !global->launched_from_cli
36061           || global->cli_load_menu_on_error
36062 #ifdef HAVE_MENU
36063           || p_rarch->menu_driver_alive
36064 #endif
36065          )
36066 #endif
36067       {
36068          /* Attempt initializing dummy core */
36069          p_rarch->current_core_type = CORE_TYPE_DUMMY;
36070          if (!command_event(CMD_EVENT_CORE_INIT, &p_rarch->current_core_type))
36071             goto error;
36072       }
36073 #ifdef HAVE_DYNAMIC
36074       else /* Fall back to regular error handling */
36075          goto error;
36076 #endif
36077    }
36078 
36079 #ifdef HAVE_CHEATS
36080    cheat_manager_state_free();
36081    command_event_init_cheats(settings->bools.apply_cheats_after_load,
36082                              settings->paths.path_cheat_database,
36083                              p_rarch);
36084 #endif
36085    drivers_init(p_rarch, settings, DRIVERS_CMD_ALL, verbosity_enabled);
36086 #ifdef HAVE_COMMAND
36087    input_driver_deinit_command(p_rarch);
36088    input_driver_init_command(p_rarch, settings);
36089 #endif
36090 #ifdef HAVE_NETWORKGAMEPAD
36091    if (p_rarch->input_driver_remote)
36092       input_remote_free(p_rarch->input_driver_remote,
36093             p_rarch->input_driver_max_users);
36094    p_rarch->input_driver_remote    = NULL;
36095    if (settings->bools.network_remote_enable)
36096       p_rarch->input_driver_remote = input_driver_init_remote(
36097             settings,
36098             p_rarch->input_driver_max_users);
36099 #endif
36100    input_mapper_reset(&p_rarch->input_driver_mapper);
36101 #ifdef HAVE_REWIND
36102    command_event(CMD_EVENT_REWIND_INIT, NULL);
36103 #endif
36104    command_event(CMD_EVENT_CONTROLLER_INIT, NULL);
36105    if (!string_is_empty(global->record.path))
36106       command_event(CMD_EVENT_RECORD_INIT, NULL);
36107 
36108    path_init_savefile(p_rarch);
36109 
36110    command_event(CMD_EVENT_SET_PER_GAME_RESOLUTION, NULL);
36111 
36112    p_rarch->rarch_error_on_init     = false;
36113    p_rarch->rarch_is_inited         = true;
36114 
36115 #ifdef HAVE_DISCORD
36116    if (command_event(CMD_EVENT_DISCORD_INIT, NULL))
36117       discord_is_inited = true;
36118 
36119    if (discord_is_inited)
36120    {
36121       discord_userdata_t userdata;
36122       userdata.status = DISCORD_PRESENCE_MENU;
36123 
36124       command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
36125    }
36126 #endif
36127 
36128 #if defined(HAVE_AUDIOMIXER)
36129    audio_driver_load_system_sounds();
36130 #endif
36131 
36132    return true;
36133 
36134 error:
36135    command_event(CMD_EVENT_CORE_DEINIT, NULL);
36136    p_rarch->rarch_is_inited         = false;
36137 
36138    return false;
36139 }
36140 
36141 #if 0
36142 static bool retroarch_is_on_main_thread(struct rarch_state *p_rarch)
36143 {
36144 #ifdef HAVE_THREAD_STORAGE
36145    return sthread_tls_get(&p_rarch->rarch_tls) == MAGIC_POINTER;
36146 #else
36147    return true;
36148 #endif
36149 }
36150 #endif
36151 
36152 #ifdef HAVE_MENU
36153 /* This callback gets triggered by the keyboard whenever
36154  * we press or release a keyboard key. When a keyboard
36155  * key is being pressed down, 'down' will be true. If it
36156  * is being released, 'down' will be false.
36157  */
menu_input_key_event(bool down,unsigned keycode,uint32_t character,uint16_t mod)36158 static void menu_input_key_event(bool down, unsigned keycode,
36159       uint32_t character, uint16_t mod)
36160 {
36161    struct rarch_state *p_rarch = &rarch_st;
36162    enum retro_key          key = (enum retro_key)keycode;
36163 
36164    if (key == RETROK_UNKNOWN)
36165    {
36166       unsigned i;
36167 
36168       for (i = 0; i < RETROK_LAST; i++)
36169          p_rarch->menu_keyboard_key_state[i] =
36170             (p_rarch->menu_keyboard_key_state[(enum retro_key)i] & 1) << 1;
36171    }
36172    else
36173       p_rarch->menu_keyboard_key_state[key]  =
36174          ((p_rarch->menu_keyboard_key_state[key] & 1) << 1) | down;
36175 }
36176 
36177 /* Gets called when we want to toggle the menu.
36178  * If the menu is already running, it will be turned off.
36179  * If the menu is off, then the menu will be started.
36180  */
menu_driver_toggle(struct rarch_state * p_rarch,menu_handle_t * menu,settings_t * settings,retro_keyboard_event_t * key_event,retro_keyboard_event_t * frontend_key_event,bool on)36181 static void menu_driver_toggle(
36182       struct rarch_state *p_rarch,
36183       menu_handle_t *menu,
36184       settings_t *settings,
36185       retro_keyboard_event_t *key_event,
36186       retro_keyboard_event_t *frontend_key_event,
36187       bool on)
36188 {
36189    /* TODO/FIXME - retroarch_main_quit calls menu_driver_toggle -
36190     * we might have to redesign this to avoid EXXC_BAD_ACCESS errors
36191     * on OSX - for now we work around this by checking if the settings
36192     * struct is NULL
36193     */
36194    bool pause_libretro                        = settings ?
36195       settings->bools.menu_pause_libretro : false;
36196 #ifdef HAVE_AUDIOMIXER
36197    bool audio_enable_menu                     = settings ? settings->bools.audio_enable_menu : false;
36198 #if 0
36199    bool audio_enable_menu_bgm                 = settings ? settings->bools.audio_enable_menu_bgm : false;
36200 #endif
36201 #endif
36202    bool runloop_shutdown_initiated            = runloop_state.shutdown_initiated;
36203 
36204    if (menu->driver_ctx && menu->driver_ctx->toggle)
36205       menu->driver_ctx->toggle(menu->userdata, on);
36206 
36207    p_rarch->menu_driver_alive                 = on;
36208 
36209 #ifdef HAVE_LAKKA
36210    if (on)
36211       set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_MENU);
36212    else
36213       set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_CORE);
36214 #endif
36215 
36216    /* Apply any required menu pointer input inhibits
36217     * (i.e. prevent phantom input when using an overlay
36218     * to toggle the menu on) */
36219    menu_input_driver_toggle(
36220          &p_rarch->menu_input_state,
36221          settings->bools.input_overlay_hide_in_menu,
36222          settings->bools.input_overlay_enable,
36223 #ifdef HAVE_OVERLAY
36224          p_rarch->overlay_ptr &&
36225          p_rarch->overlay_ptr->alive,
36226 #else
36227          false,
36228 #endif
36229          on);
36230 
36231    if (p_rarch->menu_driver_alive)
36232    {
36233       bool refresh = false;
36234 
36235 #ifdef WIIU
36236       /* Enable burn-in protection menu is running */
36237       IMEnableDim();
36238 #endif
36239 
36240       menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
36241 
36242       /* Menu should always run with vsync on. */
36243       if (p_rarch->current_video->set_nonblock_state)
36244          p_rarch->current_video->set_nonblock_state(p_rarch->video_driver_data, false,
36245                video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
36246                settings->bools.video_adaptive_vsync,
36247                settings->uints.video_swap_interval
36248                );
36249       /* Stop all rumbling before entering the menu. */
36250       command_event(CMD_EVENT_RUMBLE_STOP, NULL);
36251 
36252       if (pause_libretro && !audio_enable_menu)
36253          command_event(CMD_EVENT_AUDIO_STOP, NULL);
36254 
36255 #if 0
36256      if (audio_enable_menu && audio_enable_menu_bgm)
36257          audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
36258 #endif
36259 
36260       /* Override keyboard callback to redirect to menu instead.
36261        * We'll use this later for something ... */
36262 
36263       if (key_event && frontend_key_event)
36264       {
36265          *frontend_key_event              = *key_event;
36266          *key_event                       = menu_input_key_event;
36267 
36268          runloop_state.frame_time_last = 0;
36269       }
36270    }
36271    else
36272    {
36273 #ifdef WIIU
36274       /* Disable burn-in protection while core is running; this is needed
36275        * because HID inputs don't count for the purpose of Wii U
36276        * power-saving. */
36277       IMDisableDim();
36278 #endif
36279 
36280       if (!runloop_shutdown_initiated)
36281          driver_set_nonblock_state();
36282 
36283       if (pause_libretro && !audio_enable_menu)
36284          command_event(CMD_EVENT_AUDIO_START, NULL);
36285 
36286 #if 0
36287       if (audio_enable_menu && audio_enable_menu_bgm)
36288          audio_driver_mixer_stop_stream(AUDIO_MIXER_SYSTEM_SLOT_BGM);
36289 #endif
36290 
36291       /* Restore libretro keyboard callback. */
36292       if (key_event && frontend_key_event)
36293          *key_event = *frontend_key_event;
36294    }
36295 }
36296 #endif
36297 
retroarch_menu_running(void)36298 void retroarch_menu_running(void)
36299 {
36300    struct rarch_state *p_rarch     = &rarch_st;
36301 #if defined(HAVE_MENU) || defined(HAVE_OVERLAY)
36302    settings_t *settings            = p_rarch->configuration_settings;
36303 #endif
36304 #ifdef HAVE_OVERLAY
36305    bool input_overlay_hide_in_menu = settings->bools.input_overlay_hide_in_menu;
36306 #endif
36307 #ifdef HAVE_AUDIOMIXER
36308    bool audio_enable_menu          = settings->bools.audio_enable_menu;
36309    bool audio_enable_menu_bgm      = settings->bools.audio_enable_menu_bgm;
36310 #endif
36311 
36312 #ifdef HAVE_MENU
36313    menu_handle_t *menu             = p_rarch->menu_driver_data;
36314    struct menu_state *menu_st      = &p_rarch->menu_driver_state;
36315    if (menu)
36316       menu_driver_toggle(p_rarch, menu, settings,
36317             &runloop_state.key_event,
36318             &runloop_state.frontend_key_event,
36319             true);
36320 
36321    /* Prevent stray input (for a single frame) */
36322    p_rarch->input_driver_flushing_input = 1;
36323 
36324 #ifdef HAVE_AUDIOMIXER
36325    if (audio_enable_menu && audio_enable_menu_bgm)
36326       audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
36327 #endif
36328 
36329    /* Ensure that game focus mode is disabled when
36330     * running the menu (note: it is not currently
36331     * possible for game focus to be enabled at this
36332     * point, but must safeguard against future changes) */
36333    if (p_rarch->game_focus_state.enabled)
36334    {
36335       enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_OFF;
36336       command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
36337    }
36338 
36339    /* Ensure that menu screensaver is disabled when
36340     * first switching to the menu */
36341    if (menu_st->screensaver_active)
36342    {
36343       menu_ctx_environment_t menu_environ;
36344       menu_environ.type           = MENU_ENVIRON_DISABLE_SCREENSAVER;
36345       menu_environ.data           = NULL;
36346       menu_st->screensaver_active = false;
36347       menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
36348    }
36349    menu_st->input_last_time_us = cpu_features_get_time_usec();
36350 #endif
36351 
36352 #ifdef HAVE_OVERLAY
36353    if (input_overlay_hide_in_menu)
36354       command_event(CMD_EVENT_OVERLAY_DEINIT, NULL);
36355 #endif
36356 }
36357 
retroarch_menu_running_finished(bool quit)36358 void retroarch_menu_running_finished(bool quit)
36359 {
36360    struct rarch_state *p_rarch          = &rarch_st;
36361 #if defined(HAVE_MENU) || defined(HAVE_OVERLAY)
36362    settings_t *settings                 = p_rarch->configuration_settings;
36363 #endif
36364 #ifdef HAVE_MENU
36365    menu_handle_t *menu                  = p_rarch->menu_driver_data;
36366    struct menu_state *menu_st           = &p_rarch->menu_driver_state;
36367    if (menu)
36368       menu_driver_toggle(p_rarch, menu, settings,
36369             &runloop_state.key_event,
36370             &runloop_state.frontend_key_event,
36371             false);
36372 
36373    /* Prevent stray input
36374     * (for a single frame) */
36375    p_rarch->input_driver_flushing_input = 1;
36376 
36377    if (!quit)
36378    {
36379 #ifdef HAVE_AUDIOMIXER
36380       /* Stop menu background music before we exit the menu */
36381       if (  settings &&
36382             settings->bools.audio_enable_menu &&
36383             settings->bools.audio_enable_menu_bgm
36384          )
36385          audio_driver_mixer_stop_stream(AUDIO_MIXER_SYSTEM_SLOT_BGM);
36386 #endif
36387 
36388       /* Enable game focus mode, if required */
36389       if (p_rarch->current_core_type != CORE_TYPE_DUMMY)
36390       {
36391          enum input_auto_game_focus_type auto_game_focus_type = settings ?
36392             (enum input_auto_game_focus_type)settings->uints.input_auto_game_focus :
36393             AUTO_GAME_FOCUS_OFF;
36394 
36395          if ((auto_game_focus_type == AUTO_GAME_FOCUS_ON) ||
36396                ((auto_game_focus_type == AUTO_GAME_FOCUS_DETECT) &&
36397                 p_rarch->game_focus_state.core_requested))
36398          {
36399             enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_ON;
36400             command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
36401          }
36402       }
36403    }
36404 
36405    /* Ensure that menu screensaver is disabled when
36406     * switching off the menu */
36407    if (menu_st->screensaver_active)
36408    {
36409       menu_ctx_environment_t menu_environ;
36410       menu_environ.type           = MENU_ENVIRON_DISABLE_SCREENSAVER;
36411       menu_environ.data           = NULL;
36412       menu_st->screensaver_active = false;
36413       menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
36414    }
36415 #endif
36416    video_driver_set_texture_enable(false, false);
36417 #ifdef HAVE_OVERLAY
36418    if (!quit)
36419       if (settings && settings->bools.input_overlay_hide_in_menu)
36420          retroarch_overlay_init(p_rarch);
36421 #endif
36422 }
36423 
36424 /**
36425  * rarch_game_specific_options:
36426  *
36427  * Returns: true (1) if a game specific core
36428  * options path has been found,
36429  * otherwise false (0).
36430  **/
rarch_game_specific_options(struct rarch_state * p_rarch,char ** output)36431 static bool rarch_game_specific_options(struct rarch_state *p_rarch,
36432       char **output)
36433 {
36434    char game_options_path[PATH_MAX_LENGTH];
36435    game_options_path[0] ='\0';
36436 
36437    if (!retroarch_validate_game_options(
36438             game_options_path,
36439             sizeof(game_options_path), false) ||
36440        !path_is_valid(game_options_path))
36441       return false;
36442 
36443    RARCH_LOG("%s %s\n",
36444          msg_hash_to_str(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT),
36445          game_options_path);
36446    *output = strdup(game_options_path);
36447    return true;
36448 }
36449 
36450 /**
36451  * rarch_folder_specific_options:
36452  *
36453  * Returns: true (1) if a folder specific core
36454  * options path has been found,
36455  * otherwise false (0).
36456  **/
rarch_folder_specific_options(struct rarch_state * p_rarch,char ** output)36457 static bool rarch_folder_specific_options(
36458       struct rarch_state *p_rarch,
36459       char **output)
36460 {
36461    char folder_options_path[PATH_MAX_LENGTH];
36462    folder_options_path[0] ='\0';
36463 
36464    if (!retroarch_validate_folder_options(
36465             folder_options_path,
36466             sizeof(folder_options_path), false) ||
36467        !path_is_valid(folder_options_path))
36468       return false;
36469 
36470    RARCH_LOG("%s %s\n",
36471          msg_hash_to_str(MSG_FOLDER_SPECIFIC_CORE_OPTIONS_FOUND_AT),
36472          folder_options_path);
36473    *output = strdup(folder_options_path);
36474    return true;
36475 }
36476 
runloop_task_msg_queue_push(retro_task_t * task,const char * msg,unsigned prio,unsigned duration,bool flush)36477 static void runloop_task_msg_queue_push(
36478       retro_task_t *task, const char *msg,
36479       unsigned prio, unsigned duration,
36480       bool flush)
36481 {
36482 #if defined(HAVE_GFX_WIDGETS)
36483    struct rarch_state *p_rarch = &rarch_st;
36484 #ifdef HAVE_ACCESSIBILITY
36485    settings_t *settings        = p_rarch->configuration_settings;
36486    bool accessibility_enable   = settings->bools.accessibility_enable;
36487    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
36488 #endif
36489    bool widgets_active         = p_rarch->widgets_active;
36490 
36491    if (widgets_active && task->title && !task->mute)
36492    {
36493       RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
36494       ui_companion_driver_msg_queue_push(p_rarch, msg,
36495             prio, task ? duration : duration * 60 / 1000, flush);
36496 #ifdef HAVE_ACCESSIBILITY
36497       if (is_accessibility_enabled(
36498             accessibility_enable,
36499             p_rarch->accessibility_enabled))
36500          accessibility_speak_priority(p_rarch,
36501                accessibility_enable,
36502                accessibility_narrator_speech_speed,
36503                (char*)msg, 0);
36504 #endif
36505       gfx_widgets_msg_queue_push(
36506             &p_rarch->dispwidget_st,
36507             task,
36508             msg,
36509             duration,
36510             NULL,
36511             (enum message_queue_icon)MESSAGE_QUEUE_CATEGORY_INFO,
36512             (enum message_queue_category)MESSAGE_QUEUE_ICON_DEFAULT,
36513             prio,
36514             flush,
36515 #ifdef HAVE_MENU
36516             p_rarch->menu_driver_alive
36517 #else
36518             false
36519 #endif
36520             );
36521       RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
36522    }
36523    else
36524 #endif
36525       runloop_msg_queue_push(msg, prio, duration, flush, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
36526 }
36527 
36528 /* Fetches core options path for current core/content
36529  * - path: path from which options should be read
36530  *   from/saved to
36531  * - src_path: in the event that 'path' file does not
36532  *   yet exist, provides source path from which initial
36533  *   options should be extracted
36534  *
36535  *   NOTE: caller must ensure
36536  *   path and src_path are NULL-terminated
36537  *  */
rarch_init_core_options_path(struct rarch_state * p_rarch,char * path,size_t len,char * src_path,size_t src_len)36538 static void rarch_init_core_options_path(
36539       struct rarch_state *p_rarch,
36540       char *path, size_t len,
36541       char *src_path, size_t src_len)
36542 {
36543    char *game_options_path        = NULL;
36544    char *folder_options_path      = NULL;
36545 
36546    settings_t *settings           = p_rarch->configuration_settings;
36547    bool game_specific_options     = settings->bools.game_specific_options;
36548 
36549    /* Check whether game-specific options exist */
36550    if (game_specific_options &&
36551        rarch_game_specific_options(p_rarch, &game_options_path))
36552    {
36553       /* Notify system that we have a valid core options
36554        * override */
36555       path_set(RARCH_PATH_CORE_OPTIONS, game_options_path);
36556       runloop_state.game_options_active   = true;
36557       runloop_state.folder_options_active = false;
36558 
36559       /* Copy options path */
36560       strlcpy(path, game_options_path, len);
36561 
36562       free(game_options_path);
36563    }
36564    /* Check whether folder-specific options exist */
36565    else if (game_specific_options &&
36566             rarch_folder_specific_options(p_rarch,
36567                &folder_options_path))
36568    {
36569       /* Notify system that we have a valid core options
36570        * override */
36571       path_set(RARCH_PATH_CORE_OPTIONS, folder_options_path);
36572       runloop_state.game_options_active   = false;
36573       runloop_state.folder_options_active = true;
36574 
36575       /* Copy options path */
36576       strlcpy(path, folder_options_path, len);
36577 
36578       free(folder_options_path);
36579    }
36580    else
36581    {
36582       char global_options_path[PATH_MAX_LENGTH];
36583       char per_core_options_path[PATH_MAX_LENGTH];
36584       bool per_core_options_exist   = false;
36585       bool per_core_options         = !settings->bools.global_core_options;
36586       const char *path_core_options = settings->paths.path_core_options;
36587 
36588       global_options_path[0]        = '\0';
36589       per_core_options_path[0]      = '\0';
36590 
36591       if (per_core_options)
36592       {
36593          const char *core_name      = runloop_state.system.info.library_name;
36594          /* Get core-specific options path
36595           * > if retroarch_validate_per_core_options() returns
36596           *   false, then per-core options are disabled (due to
36597           *   unknown system errors...) */
36598          per_core_options = retroarch_validate_per_core_options(
36599                per_core_options_path, sizeof(per_core_options_path), true,
36600                core_name, core_name);
36601 
36602          /* If we can use per-core options, check whether an options
36603           * file already exists */
36604          if (per_core_options)
36605             per_core_options_exist = path_is_valid(per_core_options_path);
36606       }
36607 
36608       /* If not using per-core options, or if a per-core options
36609        * file does not yet exist, must fetch 'global' options path */
36610       if (!per_core_options || !per_core_options_exist)
36611       {
36612          const char *options_path   = path_core_options;
36613 
36614          if (!string_is_empty(options_path))
36615             strlcpy(global_options_path,
36616                   options_path, sizeof(global_options_path));
36617          else if (!path_is_empty(RARCH_PATH_CONFIG))
36618             fill_pathname_resolve_relative(
36619                   global_options_path, path_get(RARCH_PATH_CONFIG),
36620                   FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(global_options_path));
36621       }
36622 
36623       /* Allocate correct path/src_path strings */
36624       if (per_core_options)
36625       {
36626          strlcpy(path, per_core_options_path, len);
36627 
36628          if (!per_core_options_exist)
36629             strlcpy(src_path, global_options_path, src_len);
36630       }
36631       else
36632          strlcpy(path, global_options_path, len);
36633 
36634       /* Notify system that we *do not* have a valid core options
36635        * options override */
36636       runloop_state.game_options_active   = false;
36637       runloop_state.folder_options_active = false;
36638    }
36639 }
36640 
rarch_init_core_options(struct rarch_state * p_rarch,const struct retro_core_option_definition * option_defs)36641 static void rarch_init_core_options(
36642       struct rarch_state *p_rarch,
36643       const struct retro_core_option_definition *option_defs)
36644 {
36645    char options_path[PATH_MAX_LENGTH];
36646    char src_options_path[PATH_MAX_LENGTH];
36647 
36648    /* Ensure these are NULL-terminated */
36649    options_path[0]                = '\0';
36650    src_options_path[0]            = '\0';
36651 
36652    /* Get core options file path */
36653    rarch_init_core_options_path(p_rarch,
36654       options_path, sizeof(options_path),
36655       src_options_path, sizeof(src_options_path));
36656 
36657    if (!string_is_empty(options_path))
36658       runloop_state.core_options =
36659             core_option_manager_new(options_path, src_options_path, option_defs);
36660 }
36661 
retroarch_init_task_queue(void)36662 void retroarch_init_task_queue(void)
36663 {
36664 #ifdef HAVE_THREADS
36665    struct rarch_state *p_rarch = &rarch_st;
36666    settings_t *settings        = p_rarch->configuration_settings;
36667    bool threaded_enable        = settings->bools.threaded_data_runloop_enable;
36668 #else
36669    bool threaded_enable        = false;
36670 #endif
36671 
36672    task_queue_deinit();
36673    task_queue_init(threaded_enable, runloop_task_msg_queue_push);
36674 }
36675 
rarch_ctl(enum rarch_ctl_state state,void * data)36676 bool rarch_ctl(enum rarch_ctl_state state, void *data)
36677 {
36678    struct rarch_state *p_rarch = &rarch_st;
36679 
36680    switch(state)
36681    {
36682       case RARCH_CTL_HAS_SET_SUBSYSTEMS:
36683          return (p_rarch->current_core.has_set_subsystems);
36684       case RARCH_CTL_CORE_IS_RUNNING:
36685          return runloop_state.core_running;
36686 #ifdef HAVE_BSV_MOVIE
36687       case RARCH_CTL_BSV_MOVIE_IS_INITED:
36688          return (p_rarch->bsv_movie_state_handle != NULL);
36689 #endif
36690 #ifdef HAVE_PATCH
36691       case RARCH_CTL_IS_PATCH_BLOCKED:
36692          return p_rarch->rarch_patch_blocked;
36693       case RARCH_CTL_IS_BPS_PREF:
36694          return p_rarch->rarch_bps_pref;
36695       case RARCH_CTL_UNSET_BPS_PREF:
36696          p_rarch->rarch_bps_pref = false;
36697          break;
36698       case RARCH_CTL_IS_UPS_PREF:
36699          return p_rarch->rarch_ups_pref;
36700       case RARCH_CTL_UNSET_UPS_PREF:
36701          p_rarch->rarch_ups_pref = false;
36702          break;
36703       case RARCH_CTL_IS_IPS_PREF:
36704          return p_rarch->rarch_ips_pref;
36705       case RARCH_CTL_UNSET_IPS_PREF:
36706          p_rarch->rarch_ips_pref = false;
36707          break;
36708 #endif
36709       case RARCH_CTL_IS_DUMMY_CORE:
36710          return (p_rarch->current_core_type == CORE_TYPE_DUMMY);
36711       case RARCH_CTL_IS_CORE_LOADED:
36712          {
36713             const char *core_path = (const char*)data;
36714             const char *core_file = path_basename_nocompression(core_path);
36715             if (!string_is_empty(core_file))
36716             {
36717                /* Get loaded core file name */
36718                const char *loaded_core_file = path_basename_nocompression(
36719                      path_get(RARCH_PATH_CORE));
36720                /* Check whether specified core and currently
36721                 * loaded core are the same */
36722                if (!string_is_empty(loaded_core_file))
36723                   if (string_is_equal(core_file, loaded_core_file))
36724                      return true;
36725             }
36726          }
36727          return false;
36728       case RARCH_CTL_HAS_SET_USERNAME:
36729          return p_rarch->has_set_username;
36730       case RARCH_CTL_IS_INITED:
36731          return p_rarch->rarch_is_inited;
36732       case RARCH_CTL_MAIN_DEINIT:
36733          if (!p_rarch->rarch_is_inited)
36734             return false;
36735          command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
36736 #ifdef HAVE_COMMAND
36737          input_driver_deinit_command(p_rarch);
36738 #endif
36739 #ifdef HAVE_NETWORKGAMEPAD
36740          if (p_rarch->input_driver_remote)
36741             input_remote_free(p_rarch->input_driver_remote,
36742                   p_rarch->input_driver_max_users);
36743          p_rarch->input_driver_remote = NULL;
36744 #endif
36745          input_mapper_reset(&p_rarch->input_driver_mapper);
36746 
36747 #ifdef HAVE_THREADS
36748          retroarch_autosave_deinit(p_rarch);
36749 #endif
36750 
36751          command_event(CMD_EVENT_RECORD_DEINIT, NULL);
36752 
36753          command_event(CMD_EVENT_SAVE_FILES, NULL);
36754 
36755 #ifdef HAVE_REWIND
36756          command_event(CMD_EVENT_REWIND_DEINIT, NULL);
36757 #endif
36758 #ifdef HAVE_CHEATS
36759          cheat_manager_state_free();
36760 #endif
36761 #ifdef HAVE_BSV_MOVIE
36762          bsv_movie_deinit(p_rarch);
36763 #endif
36764 
36765          command_event(CMD_EVENT_CORE_DEINIT, NULL);
36766 
36767          content_deinit();
36768 
36769          path_deinit_subsystem(p_rarch);
36770          path_deinit_savefile();
36771 
36772          p_rarch->rarch_is_inited         = false;
36773 
36774 #ifdef HAVE_THREAD_STORAGE
36775          sthread_tls_delete(&p_rarch->rarch_tls);
36776 #endif
36777          break;
36778 #ifdef HAVE_CONFIGFILE
36779       case RARCH_CTL_SET_BLOCK_CONFIG_READ:
36780          p_rarch->rarch_block_config_read = true;
36781          break;
36782       case RARCH_CTL_UNSET_BLOCK_CONFIG_READ:
36783          p_rarch->rarch_block_config_read = false;
36784          break;
36785 #endif
36786       case RARCH_CTL_GET_CORE_OPTION_SIZE:
36787          {
36788             unsigned *idx = (unsigned*)data;
36789             if (!idx)
36790                return false;
36791             if (runloop_state.core_options)
36792                *idx = (unsigned)runloop_state.core_options->size;
36793             else
36794                *idx = 0;
36795          }
36796          break;
36797       case RARCH_CTL_HAS_CORE_OPTIONS:
36798          return (runloop_state.core_options != NULL);
36799       case RARCH_CTL_CORE_OPTIONS_LIST_GET:
36800          {
36801             core_option_manager_t **coreopts = (core_option_manager_t**)data;
36802             if (!coreopts || !runloop_state.core_options)
36803                return false;
36804             *coreopts = runloop_state.core_options;
36805          }
36806          break;
36807 #ifdef HAVE_CONFIGFILE
36808       case RARCH_CTL_IS_OVERRIDES_ACTIVE:
36809          return runloop_state.overrides_active;
36810       case RARCH_CTL_SET_REMAPS_CORE_ACTIVE:
36811          runloop_state.remaps_core_active = true;
36812          break;
36813       case RARCH_CTL_IS_REMAPS_CORE_ACTIVE:
36814          return runloop_state.remaps_core_active;
36815       case RARCH_CTL_SET_REMAPS_GAME_ACTIVE:
36816          runloop_state.remaps_game_active = true;
36817          break;
36818       case RARCH_CTL_IS_REMAPS_GAME_ACTIVE:
36819          return runloop_state.remaps_game_active;
36820       case RARCH_CTL_SET_REMAPS_CONTENT_DIR_ACTIVE:
36821          runloop_state.remaps_content_dir_active = true;
36822          break;
36823       case RARCH_CTL_IS_REMAPS_CONTENT_DIR_ACTIVE:
36824          return runloop_state.remaps_content_dir_active;
36825 #endif
36826       case RARCH_CTL_SET_MISSING_BIOS:
36827          runloop_state.missing_bios = true;
36828          break;
36829       case RARCH_CTL_UNSET_MISSING_BIOS:
36830          runloop_state.missing_bios = false;
36831          break;
36832       case RARCH_CTL_IS_MISSING_BIOS:
36833          return runloop_state.missing_bios;
36834       case RARCH_CTL_IS_GAME_OPTIONS_ACTIVE:
36835          return runloop_state.game_options_active;
36836       case RARCH_CTL_IS_FOLDER_OPTIONS_ACTIVE:
36837          return runloop_state.folder_options_active;
36838       case RARCH_CTL_GET_PERFCNT:
36839          {
36840             bool **perfcnt = (bool**)data;
36841             if (!perfcnt)
36842                return false;
36843             *perfcnt = &runloop_state.perfcnt_enable;
36844          }
36845          break;
36846       case RARCH_CTL_SET_PERFCNT_ENABLE:
36847          runloop_state.perfcnt_enable = true;
36848          break;
36849       case RARCH_CTL_UNSET_PERFCNT_ENABLE:
36850          runloop_state.perfcnt_enable = false;
36851          break;
36852       case RARCH_CTL_IS_PERFCNT_ENABLE:
36853          return runloop_state.perfcnt_enable;
36854       case RARCH_CTL_SET_WINDOWED_SCALE:
36855          {
36856             unsigned *idx = (unsigned*)data;
36857             if (!idx)
36858                return false;
36859             runloop_state.pending_windowed_scale = *idx;
36860          }
36861          break;
36862       case RARCH_CTL_STATE_FREE:
36863          runloop_state.perfcnt_enable   = false;
36864          runloop_state.idle             = false;
36865          runloop_state.paused           = false;
36866          runloop_state.slowmotion       = false;
36867 #ifdef HAVE_CONFIGFILE
36868          runloop_state.overrides_active = false;
36869 #endif
36870          runloop_state.autosave         = false;
36871          retroarch_frame_time_free(p_rarch);
36872          retroarch_audio_buffer_status_free(p_rarch);
36873          retroarch_game_focus_free(p_rarch);
36874          retroarch_fastmotion_override_free(p_rarch, &runloop_state);
36875          memset(&p_rarch->input_driver_analog_requested, 0,
36876                sizeof(p_rarch->input_driver_analog_requested));
36877          break;
36878       case RARCH_CTL_IS_IDLE:
36879          return runloop_state.idle;
36880       case RARCH_CTL_SET_IDLE:
36881          {
36882             bool *ptr = (bool*)data;
36883             if (!ptr)
36884                return false;
36885             runloop_state.idle = *ptr;
36886          }
36887          break;
36888       case RARCH_CTL_SET_PAUSED:
36889          {
36890             bool *ptr = (bool*)data;
36891             if (!ptr)
36892                return false;
36893             runloop_state.paused = *ptr;
36894          }
36895          break;
36896       case RARCH_CTL_IS_PAUSED:
36897          return runloop_state.paused;
36898       case RARCH_CTL_SET_SHUTDOWN:
36899          runloop_state.shutdown_initiated = true;
36900          break;
36901       case RARCH_CTL_CORE_OPTION_PREV:
36902          /*
36903           * Get previous value for core option specified by @idx.
36904           * Options wrap around.
36905           */
36906          {
36907             unsigned *idx = (unsigned*)data;
36908             if (!idx || !runloop_state.core_options)
36909                return false;
36910             core_option_manager_adjust_val(runloop_state.core_options, *idx, -1);
36911          }
36912          break;
36913       case RARCH_CTL_CORE_OPTION_NEXT:
36914          /*
36915           * Get next value for core option specified by @idx.
36916           * Options wrap around.
36917           */
36918          {
36919             unsigned* idx = (unsigned*)data;
36920             if (!idx || !runloop_state.core_options)
36921                return false;
36922             core_option_manager_adjust_val(runloop_state.core_options, *idx, 1);
36923          }
36924          break;
36925 
36926 
36927       case RARCH_CTL_NONE:
36928       default:
36929          return false;
36930    }
36931 
36932    return true;
36933 }
36934 
retroarch_deinit_core_options(struct rarch_state * p_rarch,const char * path_core_options)36935 static void retroarch_deinit_core_options(struct rarch_state *p_rarch,
36936       const char *path_core_options)
36937 {
36938    /* Check whether game-specific options file is being used */
36939    if (!string_is_empty(path_core_options))
36940    {
36941       config_file_t *conf_tmp = NULL;
36942 
36943       /* We only need to save configuration settings for
36944        * the current core
36945        * > If game-specific options file exists, have
36946        *   to read it (to ensure file only gets written
36947        *   if config values change)
36948        * > Otherwise, create a new, empty config_file_t
36949        *   object */
36950       if (path_is_valid(path_core_options))
36951          conf_tmp = config_file_new_from_path_to_string(path_core_options);
36952 
36953       if (!conf_tmp)
36954          conf_tmp = config_file_new_alloc();
36955 
36956       if (conf_tmp)
36957       {
36958          core_option_manager_flush(
36959                conf_tmp,
36960                runloop_state.core_options);
36961          RARCH_LOG("[Core Options]: Saved %s-specific core options to \"%s\"\n",
36962                runloop_state.game_options_active ? "game" : "folder", path_core_options);
36963          config_file_write(conf_tmp, path_core_options, true);
36964          config_file_free(conf_tmp);
36965          conf_tmp = NULL;
36966       }
36967       path_clear(RARCH_PATH_CORE_OPTIONS);
36968    }
36969    else
36970    {
36971       const char *path = runloop_state.core_options->conf_path;
36972       core_option_manager_flush(
36973             runloop_state.core_options->conf,
36974             runloop_state.core_options);
36975       RARCH_LOG("[Core Options]: Saved core options file to \"%s\"\n", path);
36976       config_file_write(runloop_state.core_options->conf, path, true);
36977    }
36978 
36979    runloop_state.game_options_active   = false;
36980    runloop_state.folder_options_active = false;
36981 
36982    if (runloop_state.core_options)
36983       core_option_manager_free(runloop_state.core_options);
36984    runloop_state.core_options          = NULL;
36985 }
36986 
retroarch_init_core_variables(struct rarch_state * p_rarch,const struct retro_variable * vars)36987 static void retroarch_init_core_variables(
36988       struct rarch_state *p_rarch,
36989       const struct retro_variable *vars)
36990 {
36991    char options_path[PATH_MAX_LENGTH];
36992    char src_options_path[PATH_MAX_LENGTH];
36993 
36994    /* Ensure these are NULL-terminated */
36995    options_path[0]     = '\0';
36996    src_options_path[0] = '\0';
36997 
36998    /* Get core options file path */
36999    rarch_init_core_options_path(p_rarch,
37000          options_path, sizeof(options_path),
37001          src_options_path, sizeof(src_options_path));
37002 
37003    if (!string_is_empty(options_path))
37004       runloop_state.core_options =
37005          core_option_manager_new_vars(options_path, src_options_path, vars);
37006 }
37007 
retroarch_is_forced_fullscreen(void)37008 bool retroarch_is_forced_fullscreen(void)
37009 {
37010    struct rarch_state *p_rarch = &rarch_st;
37011    return p_rarch->rarch_force_fullscreen;
37012 }
37013 
retroarch_is_switching_display_mode(void)37014 bool retroarch_is_switching_display_mode(void)
37015 {
37016    struct rarch_state *p_rarch = &rarch_st;
37017    return p_rarch->rarch_is_switching_display_mode;
37018 }
37019 
37020 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
retroarch_load_shader_preset_internal(char * s,size_t len,const char * shader_directory,const char * core_name,const char * special_name)37021 static bool retroarch_load_shader_preset_internal(
37022       char *s,
37023       size_t len,
37024       const char *shader_directory,
37025       const char *core_name,
37026       const char *special_name)
37027 {
37028    unsigned i;
37029 
37030    static enum rarch_shader_type types[] =
37031    {
37032       /* Shader preset priority, highest to lowest
37033        * only important for video drivers with multiple shader backends */
37034       RARCH_SHADER_GLSL, RARCH_SHADER_SLANG, RARCH_SHADER_CG, RARCH_SHADER_HLSL
37035    };
37036 
37037    for (i = 0; i < ARRAY_SIZE(types); i++)
37038    {
37039       if (!video_shader_is_supported(types[i]))
37040          continue;
37041 
37042       /* Concatenate strings into full paths */
37043       if (!string_is_empty(core_name))
37044          fill_pathname_join_special_ext(s,
37045                shader_directory, core_name,
37046                special_name,
37047                video_shader_get_preset_extension(types[i]),
37048                len);
37049       else
37050       {
37051          if (string_is_empty(special_name))
37052             break;
37053 
37054          fill_pathname_join(s, shader_directory, special_name, len);
37055          strlcat(s, video_shader_get_preset_extension(types[i]), len);
37056       }
37057 
37058       if (path_is_valid(s))
37059          return true;
37060    }
37061 
37062    return false;
37063 }
37064 
37065 /**
37066  * retroarch_load_shader_preset:
37067  *
37068  * Tries to load a supported core-, game-, folder-specific or global
37069  * shader preset from its respective location:
37070  *
37071  * global:          $CONFIG_DIR/global.$PRESET_EXT
37072  * core-specific:   $CONFIG_DIR/$CORE_NAME/$CORE_NAME.$PRESET_EXT
37073  * folder-specific: $CONFIG_DIR/$CORE_NAME/$FOLDER_NAME.$PRESET_EXT
37074  * game-specific:   $CONFIG_DIR/$CORE_NAME/$GAME_NAME.$PRESET_EXT
37075  *
37076  * $CONFIG_DIR is expected to be Menu Config directory, or failing that, the
37077  * directory where retroarch.cfg is stored.
37078  *
37079  * For compatibility purposes with versions 1.8.7 and older, the presets
37080  * subdirectory on the Video Shader path is used as a fallback directory.
37081  *
37082  * Note: Uses video_shader_is_supported() which only works after
37083  *       context driver initialization.
37084  *
37085  * Returns: false if there was an error or no action was performed.
37086  */
retroarch_load_shader_preset(struct rarch_state * p_rarch,settings_t * settings)37087 static bool retroarch_load_shader_preset(struct rarch_state *p_rarch,
37088       settings_t *settings)
37089 {
37090    const char *video_shader_directory = settings->paths.directory_video_shader;
37091    const char *menu_config_directory  = settings->paths.directory_menu_config;
37092    const char *core_name              =
37093       runloop_state.system.info.library_name;
37094    const char *rarch_path_basename    = path_get(RARCH_PATH_BASENAME);
37095 
37096    const char *game_name              = path_basename(rarch_path_basename);
37097    const char *dirs[3]                = {0};
37098    size_t i                           = 0;
37099 
37100    char shader_path[PATH_MAX_LENGTH];
37101    char content_dir_name[PATH_MAX_LENGTH];
37102    char config_file_directory[PATH_MAX_LENGTH];
37103    char old_presets_directory[PATH_MAX_LENGTH];
37104 
37105    shader_path[0]                     = '\0';
37106    content_dir_name[0]                = '\0';
37107    config_file_directory[0]           = '\0';
37108    old_presets_directory[0]           = '\0';
37109 
37110    if (!string_is_empty(rarch_path_basename))
37111       fill_pathname_parent_dir_name(content_dir_name,
37112             rarch_path_basename, sizeof(content_dir_name));
37113 
37114    config_file_directory[0]           = '\0';
37115 
37116    if (!path_is_empty(RARCH_PATH_CONFIG))
37117       fill_pathname_basedir(config_file_directory,
37118             path_get(RARCH_PATH_CONFIG), sizeof(config_file_directory));
37119 
37120    old_presets_directory[0]           = '\0';
37121 
37122    if (!string_is_empty(video_shader_directory))
37123       fill_pathname_join(old_presets_directory,
37124          video_shader_directory, "presets", sizeof(old_presets_directory));
37125 
37126    dirs[0]                            = menu_config_directory;
37127    dirs[1]                            = config_file_directory;
37128    dirs[2]                            = old_presets_directory;
37129 
37130    for (i = 0; i < ARRAY_SIZE(dirs); i++)
37131    {
37132       if (string_is_empty(dirs[i]))
37133          continue;
37134       /* Game-specific shader preset found? */
37135       if (retroarch_load_shader_preset_internal(
37136                shader_path,
37137                sizeof(shader_path),
37138                dirs[i], core_name,
37139                game_name))
37140          goto success;
37141       /* Folder-specific shader preset found? */
37142       if (retroarch_load_shader_preset_internal(
37143                shader_path,
37144                sizeof(shader_path),
37145                dirs[i], core_name,
37146                content_dir_name))
37147          goto success;
37148       /* Core-specific shader preset found? */
37149       if (retroarch_load_shader_preset_internal(
37150                shader_path,
37151                sizeof(shader_path),
37152                dirs[i], core_name,
37153                core_name))
37154          goto success;
37155       /* Global shader preset found? */
37156       if (retroarch_load_shader_preset_internal(
37157                shader_path,
37158                sizeof(shader_path),
37159                dirs[i], NULL,
37160                "global"))
37161          goto success;
37162    }
37163    return false;
37164 
37165 success:
37166    /* Shader preset exists, load it. */
37167    RARCH_LOG("[Shaders]: Specific shader preset found at %s.\n",
37168          shader_path);
37169    strlcpy(
37170          p_rarch->runtime_shader_preset,
37171          shader_path,
37172          sizeof(p_rarch->runtime_shader_preset));
37173    return true;
37174 }
37175 #endif
37176 
37177 /* get the name of the current shader preset */
retroarch_get_shader_preset(void)37178 const char *retroarch_get_shader_preset(void)
37179 {
37180 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
37181    struct rarch_state *p_rarch = &rarch_st;
37182    settings_t *settings        = p_rarch->configuration_settings;
37183    const char *core_name       = runloop_state.system.info.library_name;
37184    bool video_shader_enable    = settings->bools.video_shader_enable;
37185    unsigned video_shader_delay = settings->uints.video_shader_delay;
37186    bool auto_shaders_enable    = settings->bools.auto_shaders_enable;
37187    bool cli_shader_disable     = p_rarch->cli_shader_disable;
37188 
37189    if (!video_shader_enable)
37190       return NULL;
37191 
37192    if (video_shader_delay && !p_rarch->shader_delay_timer.timer_end)
37193       return NULL;
37194 
37195    /* disallow loading auto-shaders when no core is loaded */
37196    if (string_is_empty(core_name))
37197       return NULL;
37198 
37199    if (!string_is_empty(p_rarch->runtime_shader_preset))
37200       return p_rarch->runtime_shader_preset;
37201 
37202    /* load auto-shader once, --set-shader works like a global auto-shader */
37203    if (p_rarch->shader_presets_need_reload && !cli_shader_disable)
37204    {
37205       p_rarch->shader_presets_need_reload = false;
37206       if (video_shader_is_supported(video_shader_parse_type(p_rarch->cli_shader)))
37207          strlcpy(p_rarch->runtime_shader_preset,
37208                p_rarch->cli_shader,
37209                sizeof(p_rarch->runtime_shader_preset));
37210       else
37211          if (auto_shaders_enable) /* sets runtime_shader_preset */
37212             retroarch_load_shader_preset(p_rarch, settings);
37213       return p_rarch->runtime_shader_preset;
37214    }
37215 #endif
37216 
37217    return NULL;
37218 }
37219 
retroarch_override_setting_is_set(enum rarch_override_setting enum_idx,void * data)37220 bool retroarch_override_setting_is_set(
37221       enum rarch_override_setting enum_idx, void *data)
37222 {
37223    struct rarch_state            *p_rarch = &rarch_st;
37224 
37225    switch (enum_idx)
37226    {
37227       case RARCH_OVERRIDE_SETTING_LIBRETRO_DEVICE:
37228          {
37229             unsigned *val = (unsigned*)data;
37230             if (val)
37231             {
37232                unsigned bit = *val;
37233                return BIT256_GET(p_rarch->has_set_libretro_device, bit);
37234             }
37235          }
37236          break;
37237       case RARCH_OVERRIDE_SETTING_VERBOSITY:
37238          return p_rarch->has_set_verbosity;
37239       case RARCH_OVERRIDE_SETTING_LIBRETRO:
37240          return p_rarch->has_set_libretro;
37241       case RARCH_OVERRIDE_SETTING_LIBRETRO_DIRECTORY:
37242          return p_rarch->has_set_libretro_directory;
37243       case RARCH_OVERRIDE_SETTING_SAVE_PATH:
37244          return p_rarch->has_set_save_path;
37245       case RARCH_OVERRIDE_SETTING_STATE_PATH:
37246          return p_rarch->has_set_state_path;
37247 #ifdef HAVE_NETWORKING
37248       case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
37249          return p_rarch->has_set_netplay_mode;
37250       case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
37251          return p_rarch->has_set_netplay_ip_address;
37252       case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
37253          return p_rarch->has_set_netplay_ip_port;
37254       case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
37255          return p_rarch->has_set_netplay_stateless_mode;
37256       case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
37257          return p_rarch->has_set_netplay_check_frames;
37258 #endif
37259 #ifdef HAVE_PATCH
37260       case RARCH_OVERRIDE_SETTING_UPS_PREF:
37261          return p_rarch->has_set_ups_pref;
37262       case RARCH_OVERRIDE_SETTING_BPS_PREF:
37263          return p_rarch->has_set_bps_pref;
37264       case RARCH_OVERRIDE_SETTING_IPS_PREF:
37265          return p_rarch->has_set_ips_pref;
37266 #endif
37267       case RARCH_OVERRIDE_SETTING_LOG_TO_FILE:
37268          return p_rarch->has_set_log_to_file;
37269       case RARCH_OVERRIDE_SETTING_NONE:
37270       default:
37271          break;
37272    }
37273 
37274    return false;
37275 }
37276 
retroarch_get_capabilities(enum rarch_capabilities type,char * s,size_t len)37277 int retroarch_get_capabilities(enum rarch_capabilities type,
37278       char *s, size_t len)
37279 {
37280    switch (type)
37281    {
37282       case RARCH_CAPABILITIES_CPU:
37283          {
37284             uint64_t cpu     = cpu_features_get();
37285 
37286             if (cpu & RETRO_SIMD_MMX)
37287                strlcat(s, " MMX", len);
37288             if (cpu & RETRO_SIMD_MMXEXT)
37289                strlcat(s, " MMXEXT", len);
37290             if (cpu & RETRO_SIMD_SSE)
37291                strlcat(s, " SSE", len);
37292             if (cpu & RETRO_SIMD_SSE2)
37293                strlcat(s, " SSE2", len);
37294             if (cpu & RETRO_SIMD_SSE3)
37295                strlcat(s, " SSE3", len);
37296             if (cpu & RETRO_SIMD_SSSE3)
37297                strlcat(s, " SSSE3", len);
37298             if (cpu & RETRO_SIMD_SSE4)
37299                strlcat(s, " SSE4", len);
37300             if (cpu & RETRO_SIMD_SSE42)
37301                strlcat(s, " SSE4.2", len);
37302             if (cpu & RETRO_SIMD_AES)
37303                strlcat(s, " AES", len);
37304             if (cpu & RETRO_SIMD_AVX)
37305                strlcat(s, " AVX", len);
37306             if (cpu & RETRO_SIMD_AVX2)
37307                strlcat(s, " AVX2", len);
37308             if (cpu & RETRO_SIMD_NEON)
37309                strlcat(s, " NEON", len);
37310             if (cpu & RETRO_SIMD_VFPV3)
37311                strlcat(s, " VFPv3", len);
37312             if (cpu & RETRO_SIMD_VFPV4)
37313                strlcat(s, " VFPv4", len);
37314             if (cpu & RETRO_SIMD_VMX)
37315                strlcat(s, " VMX", len);
37316             if (cpu & RETRO_SIMD_VMX128)
37317                strlcat(s, " VMX128", len);
37318             if (cpu & RETRO_SIMD_VFPU)
37319                strlcat(s, " VFPU", len);
37320             if (cpu & RETRO_SIMD_PS)
37321                strlcat(s, " PS", len);
37322             if (cpu & RETRO_SIMD_ASIMD)
37323                strlcat(s, " ASIMD", len);
37324          }
37325          break;
37326       case RARCH_CAPABILITIES_COMPILER:
37327 #if defined(_MSC_VER)
37328          snprintf(s, len, "%s: MSVC (%d) %u-bit",
37329                msg_hash_to_str(MSG_COMPILER),
37330                _MSC_VER, (unsigned)
37331                (CHAR_BIT * sizeof(size_t)));
37332 #elif defined(__SNC__)
37333          snprintf(s, len, "%s: SNC (%d) %u-bit",
37334                msg_hash_to_str(MSG_COMPILER),
37335                __SN_VER__, (unsigned)(CHAR_BIT * sizeof(size_t)));
37336 #elif defined(_WIN32) && defined(__GNUC__)
37337          snprintf(s, len, "%s: MinGW (%d.%d.%d) %u-bit",
37338                msg_hash_to_str(MSG_COMPILER),
37339                __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, (unsigned)
37340                (CHAR_BIT * sizeof(size_t)));
37341 #elif defined(__clang__)
37342          snprintf(s, len, "%s: Clang/LLVM (%s) %u-bit",
37343                msg_hash_to_str(MSG_COMPILER),
37344                __clang_version__, (unsigned)(CHAR_BIT * sizeof(size_t)));
37345 #elif defined(__GNUC__)
37346          snprintf(s, len, "%s: GCC (%d.%d.%d) %u-bit",
37347                msg_hash_to_str(MSG_COMPILER),
37348                __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, (unsigned)
37349                (CHAR_BIT * sizeof(size_t)));
37350 #else
37351          snprintf(s, len, "%s %u-bit",
37352                msg_hash_to_str(MSG_UNKNOWN_COMPILER),
37353                (unsigned)(CHAR_BIT * sizeof(size_t)));
37354 #endif
37355          break;
37356       default:
37357       case RARCH_CAPABILITIES_NONE:
37358          break;
37359    }
37360 
37361    return 0;
37362 }
37363 
retroarch_set_current_core_type(enum rarch_core_type type,bool explicitly_set)37364 void retroarch_set_current_core_type(
37365       enum rarch_core_type type, bool explicitly_set)
37366 {
37367    struct rarch_state *p_rarch = &rarch_st;
37368 
37369    if (p_rarch->has_set_core)
37370       return;
37371 
37372    if (explicitly_set)
37373    {
37374       p_rarch->has_set_core                = true;
37375       p_rarch->explicit_current_core_type  = type;
37376    }
37377    p_rarch->current_core_type              = type;
37378 }
37379 
37380 /**
37381  * retroarch_fail:
37382  * @error_code  : Error code.
37383  * @error       : Error message to show.
37384  *
37385  * Sanely kills the program.
37386  **/
retroarch_fail(struct rarch_state * p_rarch,int error_code,const char * error)37387 static void retroarch_fail(struct rarch_state *p_rarch,
37388       int error_code, const char *error)
37389 {
37390    /* We cannot longjmp unless we're in retroarch_main_init().
37391     * If not, something went very wrong, and we should
37392     * just exit right away. */
37393    retro_assert(p_rarch->rarch_error_on_init);
37394 
37395    strlcpy(p_rarch->error_string,
37396          error, sizeof(p_rarch->error_string));
37397    longjmp(p_rarch->error_sjlj_context, error_code);
37398 }
37399 
retroarch_main_quit(void)37400 bool retroarch_main_quit(void)
37401 {
37402    struct rarch_state *p_rarch = &rarch_st;
37403    global_t            *global = &p_rarch->g_extern;
37404 #ifdef HAVE_DISCORD
37405    discord_state_t *discord_st = &p_rarch->discord_st;
37406    if (discord_is_inited)
37407    {
37408       discord_userdata_t userdata;
37409       userdata.status = DISCORD_PRESENCE_SHUTDOWN;
37410       command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
37411    }
37412    if (discord_st->ready)
37413    {
37414       Discord_ClearPresence();
37415 #ifdef DISCORD_DISABLE_IO_THREAD
37416       Discord_UpdateConnection();
37417 #endif
37418       Discord_Shutdown();
37419       discord_st->ready       = false;
37420    }
37421    discord_is_inited          = false;
37422 #endif
37423 
37424    if (!runloop_state.shutdown_initiated)
37425    {
37426       command_event_save_auto_state(
37427             p_rarch->configuration_settings->bools.savestate_auto_save,
37428             global,
37429             p_rarch->current_core_type);
37430 
37431       /* If any save states are in progress, wait
37432        * until all tasks are complete (otherwise
37433        * save state file may be truncated) */
37434       content_wait_for_save_state_task();
37435 
37436 #ifdef HAVE_CONFIGFILE
37437       if (runloop_state.overrides_active)
37438          command_event_disable_overrides(p_rarch);
37439 #endif
37440 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
37441       p_rarch->runtime_shader_preset[0] = '\0';
37442 #endif
37443 
37444       if (     runloop_state.remaps_core_active
37445             || runloop_state.remaps_content_dir_active
37446             || runloop_state.remaps_game_active
37447          )
37448       {
37449          input_remapping_deinit();
37450          input_remapping_set_defaults(true);
37451       }
37452       else
37453          input_remapping_restore_global_config(true);
37454    }
37455 
37456    runloop_state.shutdown_initiated = true;
37457    retroarch_menu_running_finished(true);
37458 
37459    return true;
37460 }
37461 
runloop_msg_queue_push(const char * msg,unsigned prio,unsigned duration,bool flush,char * title,enum message_queue_icon icon,enum message_queue_category category)37462 void runloop_msg_queue_push(const char *msg,
37463       unsigned prio, unsigned duration,
37464       bool flush,
37465       char *title,
37466       enum message_queue_icon icon,
37467       enum message_queue_category category)
37468 {
37469    struct rarch_state *p_rarch = &rarch_st;
37470 #if defined(HAVE_GFX_WIDGETS)
37471    bool widgets_active         = p_rarch->widgets_active;
37472 #endif
37473 #ifdef HAVE_ACCESSIBILITY
37474    settings_t *settings        = p_rarch->configuration_settings;
37475    bool accessibility_enable   = settings->bools.accessibility_enable;
37476    unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
37477 #endif
37478 
37479    RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
37480 #ifdef HAVE_ACCESSIBILITY
37481    if (is_accessibility_enabled(
37482             accessibility_enable,
37483             p_rarch->accessibility_enabled))
37484       accessibility_speak_priority(p_rarch,
37485             accessibility_enable,
37486             accessibility_narrator_speech_speed,
37487             (char*) msg, 0);
37488 #endif
37489 #if defined(HAVE_GFX_WIDGETS)
37490    if (widgets_active)
37491    {
37492       gfx_widgets_msg_queue_push(
37493             &p_rarch->dispwidget_st,
37494             NULL,
37495             msg,
37496             roundf((float)duration / 60.0f * 1000.0f),
37497             title,
37498             icon,
37499             category,
37500             prio,
37501             flush,
37502 #ifdef HAVE_MENU
37503             p_rarch->menu_driver_alive
37504 #else
37505             false
37506 #endif
37507             );
37508       duration = duration * 60 / 1000;
37509    }
37510    else
37511 #endif
37512    {
37513       if (flush)
37514          msg_queue_clear(&runloop_state.msg_queue);
37515 
37516       msg_queue_push(&runloop_state.msg_queue, msg,
37517             prio, duration,
37518             title, icon, category);
37519 
37520       runloop_state.msg_queue_size = msg_queue_size(
37521             &runloop_state.msg_queue);
37522    }
37523 
37524    ui_companion_driver_msg_queue_push(p_rarch,
37525          msg,
37526          prio, duration, flush);
37527 
37528    RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
37529 }
37530 
runloop_get_status(bool * is_paused,bool * is_idle,bool * is_slowmotion,bool * is_perfcnt_enable)37531 void runloop_get_status(bool *is_paused, bool *is_idle,
37532       bool *is_slowmotion, bool *is_perfcnt_enable)
37533 {
37534    *is_paused                  = runloop_state.paused;
37535    *is_idle                    = runloop_state.idle;
37536    *is_slowmotion              = runloop_state.slowmotion;
37537    *is_perfcnt_enable          = runloop_state.perfcnt_enable;
37538 }
37539 
37540 #ifdef HAVE_MENU
input_driver_toggle_button_combo(unsigned mode,retro_time_t current_time,input_bits_t * p_input)37541 static bool input_driver_toggle_button_combo(
37542       unsigned mode,
37543       retro_time_t current_time,
37544       input_bits_t* p_input)
37545 {
37546    switch (mode)
37547    {
37548       case INPUT_TOGGLE_DOWN_Y_L_R:
37549          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_DOWN) &&
37550              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_Y) &&
37551              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L) &&
37552              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R))
37553             return true;
37554          break;
37555       case INPUT_TOGGLE_L3_R3:
37556          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L3) &&
37557              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R3))
37558             return true;
37559          break;
37560       case INPUT_TOGGLE_L1_R1_START_SELECT:
37561          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L) &&
37562              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R) &&
37563              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_START) &&
37564              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
37565             return true;
37566          break;
37567       case INPUT_TOGGLE_START_SELECT:
37568          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_START) &&
37569              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
37570             return true;
37571          break;
37572       case INPUT_TOGGLE_L3_R:
37573          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L3) &&
37574              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R))
37575             return true;
37576          break;
37577       case INPUT_TOGGLE_L_R:
37578          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L) &&
37579              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R))
37580             return true;
37581          break;
37582       case INPUT_TOGGLE_DOWN_SELECT:
37583          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_DOWN) &&
37584              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
37585             return true;
37586          break;
37587       case INPUT_TOGGLE_L2_R2:
37588          if (BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_L2) &&
37589              BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_R2))
37590             return true;
37591          break;
37592       case INPUT_TOGGLE_HOLD_START:
37593       {
37594          static rarch_timer_t timer = {0};
37595 
37596          if (!BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_START))
37597          {
37598             /* timer only runs while start is held down */
37599             RARCH_TIMER_END(timer);
37600             return false;
37601          }
37602 
37603          /* User started holding down the start button, start the timer */
37604          if (!timer.timer_begin)
37605          {
37606             uint64_t current_usec = cpu_features_get_time_usec();
37607             RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
37608                   current_usec,
37609                   HOLD_BTN_DELAY_SEC * 1000000);
37610             timer.timer_begin     = true;
37611             timer.timer_end       = false;
37612          }
37613 
37614          RARCH_TIMER_TICK(timer, current_time);
37615 
37616          if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
37617          {
37618             /* start has been held down long enough,
37619              * stop timer and enter menu */
37620             RARCH_TIMER_END(timer);
37621             return true;
37622          }
37623 
37624          return false;
37625       }
37626       case INPUT_TOGGLE_HOLD_SELECT:
37627       {
37628          static rarch_timer_t timer = {0};
37629 
37630          if (!BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_SELECT))
37631          {
37632             /* timer only runs while select is held down */
37633             RARCH_TIMER_END(timer);
37634             return false;
37635          }
37636 
37637          /* user started holding down the select button, start the timer */
37638          if (!timer.timer_begin)
37639          {
37640             uint64_t current_usec = cpu_features_get_time_usec();
37641             RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
37642                   current_usec,
37643                   HOLD_BTN_DELAY_SEC * 1000000);
37644             timer.timer_begin     = true;
37645             timer.timer_end       = false;
37646          }
37647 
37648          RARCH_TIMER_TICK(timer, current_time);
37649 
37650          if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
37651          {
37652             /* select has been held down long enough,
37653              * stop timer and enter menu */
37654             RARCH_TIMER_END(timer);
37655             return true;
37656          }
37657 
37658          return false;
37659       }
37660       default:
37661       case INPUT_TOGGLE_NONE:
37662          break;
37663    }
37664 
37665    return false;
37666 }
37667 
37668 /* Display the libretro core's framebuffer onscreen. */
menu_display_libretro(struct rarch_state * p_rarch,float slowmotion_ratio,bool libretro_running,retro_time_t current_time)37669 static bool menu_display_libretro(
37670       struct rarch_state *p_rarch,
37671       float slowmotion_ratio,
37672       bool libretro_running,
37673       retro_time_t current_time)
37674 {
37675    bool runloop_idle           = runloop_state.idle;
37676 
37677    if (  p_rarch->video_driver_poke &&
37678          p_rarch->video_driver_poke->set_texture_enable)
37679       p_rarch->video_driver_poke->set_texture_enable(
37680             p_rarch->video_driver_data,
37681             true, false);
37682 
37683    if (libretro_running)
37684    {
37685       if (!p_rarch->input_driver_block_libretro_input)
37686          p_rarch->input_driver_block_libretro_input = true;
37687 
37688       core_run();
37689       p_rarch->libretro_core_runtime_usec        +=
37690          rarch_core_runtime_tick(p_rarch, slowmotion_ratio, current_time);
37691       p_rarch->input_driver_block_libretro_input  = false;
37692 
37693       return false;
37694    }
37695 
37696    if (runloop_idle)
37697    {
37698 #ifdef HAVE_DISCORD
37699       discord_userdata_t userdata;
37700       userdata.status = DISCORD_PRESENCE_GAME_PAUSED;
37701 
37702       command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
37703 #endif
37704       return false;
37705    }
37706 
37707    return true;
37708 }
37709 #endif
37710 
runloop_check_state(struct rarch_state * p_rarch,settings_t * settings,retro_time_t current_time)37711 static enum runloop_state runloop_check_state(
37712       struct rarch_state *p_rarch,
37713       settings_t *settings,
37714       retro_time_t current_time)
37715 {
37716    input_bits_t current_bits;
37717 #ifdef HAVE_MENU
37718    static input_bits_t last_input      = {{0}};
37719 #endif
37720    static bool old_focus               = true;
37721    struct retro_callbacks *cbs         = &p_rarch->retro_ctx;
37722    bool is_focused                     = false;
37723    bool is_alive                       = false;
37724    uint64_t frame_count                = 0;
37725    bool focused                        = true;
37726    bool rarch_is_initialized           = p_rarch->rarch_is_inited;
37727    bool runloop_paused                 = runloop_state.paused;
37728    bool pause_nonactive                = settings->bools.pause_nonactive;
37729 #ifdef HAVE_MENU
37730    menu_handle_t *menu                 = p_rarch->menu_driver_data;
37731    unsigned menu_toggle_gamepad_combo  = settings->uints.input_menu_toggle_gamepad_combo;
37732    bool menu_driver_binding_state      = p_rarch->menu_driver_is_binding;
37733    bool menu_is_alive                  = p_rarch->menu_driver_alive;
37734    bool display_kb                     = menu_input_dialog_get_display_kb();
37735 #endif
37736 #if defined(HAVE_GFX_WIDGETS)
37737    bool widgets_active                 = p_rarch->widgets_active;
37738 #endif
37739 #ifdef HAVE_CHEEVOS
37740    bool cheevos_hardcore_active        = rcheevos_hardcore_active();
37741 #endif
37742 
37743 #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
37744    if (p_rarch->dispwidget_st.ai_service_overlay_state == 3)
37745    {
37746       command_event(CMD_EVENT_PAUSE, NULL);
37747       p_rarch->dispwidget_st.ai_service_overlay_state = 1;
37748    }
37749 #endif
37750 
37751 #ifdef HAVE_LIBNX
37752    /* Should be called once per frame */
37753    if (!appletMainLoop())
37754       return RUNLOOP_STATE_QUIT;
37755 #endif
37756 
37757 #ifdef _3DS
37758    /* Should be called once per frame */
37759    if (!aptMainLoop())
37760       return RUNLOOP_STATE_QUIT;
37761 #endif
37762 
37763 
37764    BIT256_CLEAR_ALL_PTR(&current_bits);
37765 
37766    p_rarch->input_driver_block_libretro_input   = false;
37767    p_rarch->input_driver_block_hotkey           = false;
37768 
37769    if (p_rarch->keyboard_mapping_blocked)
37770       p_rarch->input_driver_block_hotkey        = true;
37771 
37772    {
37773       rarch_joypad_info_t joypad_info;
37774       unsigned port                                = 0;
37775       int input_hotkey_block_delay                 = settings->uints.input_hotkey_block_delay;
37776       input_driver_t *current_input                = p_rarch->current_input;
37777       const struct retro_keybind *binds_norm       = &input_config_binds[port][RARCH_ENABLE_HOTKEY];
37778       const struct retro_keybind *binds_auto       = &input_autoconf_binds[port][RARCH_ENABLE_HOTKEY];
37779       const struct retro_keybind *binds            = input_config_binds[port];
37780       struct retro_keybind *auto_binds             = input_autoconf_binds[port];
37781       struct retro_keybind *general_binds          = input_config_binds[port];
37782 #ifdef HAVE_MENU
37783       bool menu_input_active                       = menu_is_alive && !(settings->bools.menu_unified_controls && !display_kb);
37784 #else
37785       bool menu_input_active                       = false;
37786 #endif
37787 #ifdef HAVE_MFI
37788    const input_device_driver_t
37789       *sec_joypad                                  = p_rarch->sec_joypad;
37790 #else
37791    const input_device_driver_t
37792       *sec_joypad                                  = NULL;
37793 #endif
37794 
37795       joypad_info.joy_idx                          = settings->uints.input_joypad_index[port];
37796       joypad_info.auto_binds                       = input_autoconf_binds[joypad_info.joy_idx];
37797       joypad_info.axis_threshold                   = p_rarch->input_driver_axis_threshold;
37798 
37799 #ifdef HAVE_MENU
37800       if (menu_input_active)
37801       {
37802          unsigned k;
37803          unsigned x_plus      =  RARCH_ANALOG_LEFT_X_PLUS;
37804          unsigned y_plus      =  RARCH_ANALOG_LEFT_Y_PLUS;
37805          unsigned x_minus     =  RARCH_ANALOG_LEFT_X_MINUS;
37806          unsigned y_minus     =  RARCH_ANALOG_LEFT_Y_MINUS;
37807 
37808          /* Push analog to D-Pad mappings to binds. */
37809 
37810          for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
37811          {
37812             (auto_binds)[k].orig_joyaxis    = (auto_binds)[k].joyaxis;
37813             (general_binds)[k].orig_joyaxis = (general_binds)[k].joyaxis;
37814          }
37815 
37816          if (!INHERIT_JOYAXIS(auto_binds))
37817          {
37818             unsigned j = x_plus + 3;
37819             /* Inherit joyaxis from analogs. */
37820             for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
37821                (auto_binds)[k].joyaxis = (auto_binds)[j--].joyaxis;
37822          }
37823          if (!INHERIT_JOYAXIS(general_binds))
37824          {
37825             unsigned j = x_plus + 3;
37826             /* Inherit joyaxis from analogs. */
37827             for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
37828                (general_binds)[k].joyaxis = (general_binds)[j--].joyaxis;
37829          }
37830       }
37831 #endif
37832 
37833       input_keys_pressed(port, menu_input_active, input_hotkey_block_delay, p_rarch,
37834             &current_bits, &binds, binds_norm, binds_auto,
37835             &joypad_info);
37836 
37837 #ifdef HAVE_MENU
37838       if (menu_input_active)
37839       {
37840          unsigned j;
37841 
37842          /* Restores analog D-pad binds temporarily overridden. */
37843 
37844          for (j = RETRO_DEVICE_ID_JOYPAD_UP; j <= RETRO_DEVICE_ID_JOYPAD_RIGHT; j++)
37845          {
37846             (auto_binds)[j].joyaxis    = (auto_binds)[j].orig_joyaxis;
37847             (general_binds)[j].joyaxis = (general_binds)[j].orig_joyaxis;
37848          }
37849 
37850          if (     !display_kb
37851                &&  current_input->input_state)
37852          {
37853             unsigned i;
37854             unsigned ids[][2] =
37855             {
37856                {RETROK_SPACE,     RETRO_DEVICE_ID_JOYPAD_START   },
37857                {RETROK_SLASH,     RETRO_DEVICE_ID_JOYPAD_X       },
37858                {RETROK_RSHIFT,    RETRO_DEVICE_ID_JOYPAD_SELECT  },
37859                {RETROK_RIGHT,     RETRO_DEVICE_ID_JOYPAD_RIGHT   },
37860                {RETROK_LEFT,      RETRO_DEVICE_ID_JOYPAD_LEFT    },
37861                {RETROK_DOWN,      RETRO_DEVICE_ID_JOYPAD_DOWN    },
37862                {RETROK_UP,        RETRO_DEVICE_ID_JOYPAD_UP      },
37863                {RETROK_PAGEUP,    RETRO_DEVICE_ID_JOYPAD_L       },
37864                {RETROK_PAGEDOWN,  RETRO_DEVICE_ID_JOYPAD_R       },
37865                {0,                RARCH_QUIT_KEY                 },
37866                {0,                RARCH_FULLSCREEN_TOGGLE_KEY    },
37867                {RETROK_BACKSPACE, RETRO_DEVICE_ID_JOYPAD_B      },
37868                {RETROK_RETURN,    RETRO_DEVICE_ID_JOYPAD_A      },
37869                {RETROK_DELETE,    RETRO_DEVICE_ID_JOYPAD_Y      },
37870                {0,                RARCH_UI_COMPANION_TOGGLE     },
37871                {0,                RARCH_FPS_TOGGLE              },
37872                {0,                RARCH_SEND_DEBUG_INFO         },
37873                {0,                RARCH_NETPLAY_HOST_TOGGLE     },
37874                {0,                RARCH_MENU_TOGGLE             },
37875             };
37876 
37877             ids[9][0]  = input_config_binds[port][RARCH_QUIT_KEY].key;
37878             ids[10][0] = input_config_binds[port][RARCH_FULLSCREEN_TOGGLE_KEY].key;
37879             ids[14][0] = input_config_binds[port][RARCH_UI_COMPANION_TOGGLE].key;
37880             ids[15][0] = input_config_binds[port][RARCH_FPS_TOGGLE].key;
37881             ids[16][0] = input_config_binds[port][RARCH_SEND_DEBUG_INFO].key;
37882             ids[17][0] = input_config_binds[port][RARCH_NETPLAY_HOST_TOGGLE].key;
37883             ids[18][0] = input_config_binds[port][RARCH_MENU_TOGGLE].key;
37884 
37885             if (settings->bools.input_menu_swap_ok_cancel_buttons)
37886             {
37887                ids[11][1] = RETRO_DEVICE_ID_JOYPAD_A;
37888                ids[12][1] = RETRO_DEVICE_ID_JOYPAD_B;
37889             }
37890 
37891             for (i = 0; i < ARRAY_SIZE(ids); i++)
37892             {
37893                if (current_input->input_state(
37894                         p_rarch->current_input_data,
37895                         p_rarch->joypad,
37896                         sec_joypad,
37897                         &joypad_info, &binds,
37898                         p_rarch->keyboard_mapping_blocked,
37899                         port,
37900                         RETRO_DEVICE_KEYBOARD, 0, ids[i][0]))
37901                   BIT256_SET_PTR(&current_bits, ids[i][1]);
37902             }
37903          }
37904       }
37905       else
37906 #endif
37907       {
37908 #ifdef HAVE_ACCESSIBILITY
37909 #ifdef HAVE_TRANSLATE
37910          if (settings->bools.ai_service_enable)
37911          {
37912             unsigned i;
37913 
37914             p_rarch->gamepad_input_override = 0;
37915 
37916             for (i = 0; i < MAX_USERS; i++)
37917             {
37918                /* Set gamepad input override */
37919                if (p_rarch->ai_gamepad_state[i] == 2)
37920                   p_rarch->gamepad_input_override |= (1 << i);
37921                p_rarch->ai_gamepad_state[i] = 0;
37922             }
37923          }
37924 #endif
37925 #endif
37926       }
37927    }
37928 
37929 #ifdef HAVE_MENU
37930    last_input                       = current_bits;
37931    if (
37932          ((menu_toggle_gamepad_combo != INPUT_TOGGLE_NONE) &&
37933           input_driver_toggle_button_combo(
37934              menu_toggle_gamepad_combo, current_time,
37935              &last_input)))
37936       BIT256_SET(current_bits, RARCH_MENU_TOGGLE);
37937 #endif
37938 
37939    if (p_rarch->input_driver_flushing_input > 0)
37940    {
37941       bool input_active = bits_any_set(current_bits.data, ARRAY_SIZE(current_bits.data));
37942 
37943       p_rarch->input_driver_flushing_input = input_active
37944          ? p_rarch->input_driver_flushing_input
37945          : (p_rarch->input_driver_flushing_input - 1);
37946 
37947       if (input_active || (p_rarch->input_driver_flushing_input > 0))
37948       {
37949          BIT256_CLEAR_ALL(current_bits);
37950          if (runloop_paused)
37951             BIT256_SET(current_bits, RARCH_PAUSE_TOGGLE);
37952       }
37953    }
37954 
37955    if (!VIDEO_DRIVER_IS_THREADED_INTERNAL())
37956    {
37957       const ui_application_t *application = p_rarch->ui_companion
37958          ? p_rarch->ui_companion->application
37959          : NULL;
37960       if (application)
37961          application->process_events();
37962    }
37963 
37964    frame_count = p_rarch->video_driver_frame_count;
37965    is_alive    = p_rarch->current_video
37966       ? p_rarch->current_video->alive(p_rarch->video_driver_data)
37967       : true;
37968    is_focused  = VIDEO_HAS_FOCUS(p_rarch);
37969 
37970 #ifdef HAVE_MENU
37971    if (menu_driver_binding_state)
37972       BIT256_CLEAR_ALL(current_bits);
37973 #endif
37974 
37975    /* Check fullscreen toggle */
37976    {
37977       bool fullscreen_toggled = !runloop_paused
37978 #ifdef HAVE_MENU
37979          || menu_is_alive;
37980 #else
37981       ;
37982 #endif
37983       HOTKEY_CHECK(RARCH_FULLSCREEN_TOGGLE_KEY, CMD_EVENT_FULLSCREEN_TOGGLE,
37984             fullscreen_toggled, NULL);
37985    }
37986 
37987    /* Check mouse grab toggle */
37988    HOTKEY_CHECK(RARCH_GRAB_MOUSE_TOGGLE, CMD_EVENT_GRAB_MOUSE_TOGGLE, true, NULL);
37989 
37990 #ifdef HAVE_OVERLAY
37991    if (settings->bools.input_overlay_enable)
37992    {
37993       static char prev_overlay_restore               = false;
37994       static unsigned last_width                     = 0;
37995       static unsigned last_height                    = 0;
37996       unsigned video_driver_width                    = p_rarch->video_driver_width;
37997       unsigned video_driver_height                   = p_rarch->video_driver_height;
37998       bool check_next_rotation                       = true;
37999       bool input_overlay_hide_in_menu                = settings->bools.input_overlay_hide_in_menu;
38000       bool input_overlay_hide_when_gamepad_connected = settings->bools.input_overlay_hide_when_gamepad_connected;
38001       bool input_overlay_auto_rotate                 = settings->bools.input_overlay_auto_rotate;
38002 
38003       /* Check whether overlay should be hidden
38004        * when a gamepad is connected */
38005       if (input_overlay_hide_when_gamepad_connected)
38006       {
38007          static bool last_controller_connected = false;
38008          bool controller_connected             = (input_config_get_device_name(0) != NULL);
38009 
38010          if (controller_connected != last_controller_connected)
38011          {
38012             if (controller_connected)
38013                retroarch_overlay_deinit(p_rarch);
38014             else
38015                retroarch_overlay_init(p_rarch);
38016 
38017             last_controller_connected = controller_connected;
38018          }
38019       }
38020 
38021       /* Check next overlay */
38022       HOTKEY_CHECK(RARCH_OVERLAY_NEXT, CMD_EVENT_OVERLAY_NEXT, true, &check_next_rotation);
38023 
38024       /* Ensure overlay is restored after displaying osk */
38025       if (p_rarch->input_driver_keyboard_linefeed_enable)
38026          prev_overlay_restore = true;
38027       else if (prev_overlay_restore)
38028       {
38029          if (!input_overlay_hide_in_menu)
38030             retroarch_overlay_init(p_rarch);
38031          prev_overlay_restore = false;
38032       }
38033 
38034       /* Check whether video aspect has changed */
38035       if ((video_driver_width  != last_width) ||
38036           (video_driver_height != last_height))
38037       {
38038          /* Update scaling/offset factors */
38039          command_event(CMD_EVENT_OVERLAY_SET_SCALE_FACTOR, NULL);
38040 
38041          /* Check overlay rotation, if required */
38042          if (input_overlay_auto_rotate)
38043             input_overlay_auto_rotate_(p_rarch,
38044                   settings->bools.input_overlay_enable,
38045                   p_rarch->overlay_ptr);
38046 
38047          last_width  = video_driver_width;
38048          last_height = video_driver_height;
38049       }
38050    }
38051 #endif
38052 
38053    /*
38054    * If the Aspect Ratio is FULL then update the aspect ratio to the
38055    * current video driver aspect ratio (The full window)
38056    *
38057    * TODO/FIXME
38058    *      Should possibly be refactored to have last width & driver width & height
38059    *      only be done once when we are using an overlay OR using aspect ratio
38060    *      full
38061    */
38062    if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_FULL)
38063    {
38064       static unsigned last_width                     = 0;
38065       static unsigned last_height                    = 0;
38066       unsigned video_driver_width                    = p_rarch->video_driver_width;
38067       unsigned video_driver_height                   = p_rarch->video_driver_height;
38068 
38069       /* Check whether video aspect has changed */
38070       if ((video_driver_width  != last_width) ||
38071           (video_driver_height != last_height))
38072       {
38073          /* Update set aspect ratio so the full matches the current video width & height */
38074          command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
38075 
38076          last_width  = video_driver_width;
38077          last_height = video_driver_height;
38078       }
38079    }
38080 
38081    /* Check quit key */
38082    {
38083       bool trig_quit_key, quit_press_twice;
38084       static bool quit_key     = false;
38085       static bool old_quit_key = false;
38086       static bool runloop_exec = false;
38087       quit_key                 = BIT256_GET(
38088             current_bits, RARCH_QUIT_KEY);
38089       trig_quit_key            = quit_key && !old_quit_key;
38090       old_quit_key             = quit_key;
38091       quit_press_twice         = settings->bools.quit_press_twice;
38092 
38093       /* Check double press if enabled */
38094       if (trig_quit_key && quit_press_twice)
38095       {
38096          static retro_time_t quit_key_time   = 0;
38097          retro_time_t cur_time               = current_time;
38098          trig_quit_key                       = (cur_time - quit_key_time < QUIT_DELAY_USEC);
38099          quit_key_time                       = cur_time;
38100 
38101          if (!trig_quit_key)
38102          {
38103             float target_hz = 0.0;
38104 
38105             rarch_environment_cb(
38106                   RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE, &target_hz);
38107 
38108             runloop_msg_queue_push(msg_hash_to_str(MSG_PRESS_AGAIN_TO_QUIT), 1,
38109                   QUIT_DELAY_USEC * target_hz / 1000000,
38110                   true, NULL,
38111                   MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
38112          }
38113       }
38114 
38115       if (TIME_TO_EXIT(trig_quit_key))
38116       {
38117          bool quit_runloop           = false;
38118 #ifdef HAVE_SCREENSHOTS
38119          unsigned runloop_max_frames = runloop_state.max_frames;
38120 
38121          if ((runloop_max_frames != 0)
38122                && (frame_count >= runloop_max_frames)
38123                && runloop_state.max_frames_screenshot)
38124          {
38125             const char *screenshot_path = NULL;
38126             bool fullpath               = false;
38127 
38128             if (string_is_empty(runloop_state.max_frames_screenshot_path))
38129                screenshot_path          = path_get(RARCH_PATH_BASENAME);
38130             else
38131             {
38132                fullpath                 = true;
38133                screenshot_path          = runloop_state.max_frames_screenshot_path;
38134             }
38135 
38136             RARCH_LOG("Taking a screenshot before exiting...\n");
38137 
38138             /* Take a screenshot before we exit. */
38139             if (!take_screenshot(settings->paths.directory_screenshot,
38140                      screenshot_path, false,
38141                      video_driver_cached_frame_has_valid_framebuffer(), fullpath, false))
38142             {
38143                RARCH_ERR("Could not take a screenshot before exiting.\n");
38144             }
38145          }
38146 #endif
38147 
38148          if (runloop_exec)
38149             runloop_exec = false;
38150 
38151          if (runloop_state.core_shutdown_initiated &&
38152                settings->bools.load_dummy_on_core_shutdown)
38153          {
38154             content_ctx_info_t content_info;
38155 
38156             content_info.argc               = 0;
38157             content_info.argv               = NULL;
38158             content_info.args               = NULL;
38159             content_info.environ_get        = NULL;
38160 
38161             if (task_push_start_dummy_core(&content_info))
38162             {
38163                /* Loads dummy core instead of exiting RetroArch completely.
38164                 * Aborts core shutdown if invoked. */
38165                runloop_state.shutdown_initiated      = false;
38166                runloop_state.core_shutdown_initiated = false;
38167             }
38168             else
38169                quit_runloop              = true;
38170          }
38171          else
38172             quit_runloop                 = true;
38173 
38174          runloop_state.core_running   = false;
38175 
38176          if (quit_runloop)
38177          {
38178             old_quit_key                 = quit_key;
38179             retroarch_main_quit();
38180             return RUNLOOP_STATE_QUIT;
38181          }
38182       }
38183    }
38184 
38185 #if defined(HAVE_MENU) || defined(HAVE_GFX_WIDGETS)
38186    gfx_animation_update(
38187          &p_rarch->anim,
38188          current_time,
38189          settings->bools.menu_timedate_enable,
38190          settings->floats.menu_ticker_speed,
38191          p_rarch->video_driver_width,
38192          p_rarch->video_driver_height);
38193 
38194 #if defined(HAVE_GFX_WIDGETS)
38195    if (widgets_active)
38196    {
38197       bool rarch_force_fullscreen = p_rarch->rarch_force_fullscreen;
38198       bool video_is_fullscreen    = settings->bools.video_fullscreen ||
38199             rarch_force_fullscreen;
38200 
38201       RUNLOOP_MSG_QUEUE_LOCK(runloop_state);
38202       gfx_widgets_iterate(
38203             &p_rarch->dispwidget_st,
38204             &p_rarch->dispgfx,
38205             settings,
38206             p_rarch->video_driver_width,
38207             p_rarch->video_driver_height,
38208             video_is_fullscreen,
38209             settings->paths.directory_assets,
38210             settings->paths.path_font,
38211             VIDEO_DRIVER_IS_THREADED_INTERNAL());
38212       RUNLOOP_MSG_QUEUE_UNLOCK(runloop_state);
38213    }
38214 #endif
38215 
38216 #ifdef HAVE_MENU
38217    if (menu_is_alive)
38218    {
38219       enum menu_action action;
38220       static input_bits_t old_input = {{0}};
38221       static enum menu_action
38222          old_action                 = MENU_ACTION_CANCEL;
38223       struct menu_state    *menu_st = &p_rarch->menu_driver_state;
38224       bool focused                  = false;
38225       input_bits_t trigger_input    = current_bits;
38226       global_t *global              = &p_rarch->g_extern;
38227       unsigned screensaver_timeout  = settings->uints.menu_screensaver_timeout;
38228 
38229       /* Get current time */
38230       menu_st->current_time_us       = current_time;
38231 
38232       cbs->poll_cb();
38233 
38234       bits_clear_bits(trigger_input.data, old_input.data,
38235             ARRAY_SIZE(trigger_input.data));
38236       action                    = (enum menu_action)menu_event(
38237             p_rarch, settings,
38238             &current_bits, &trigger_input, display_kb);
38239       focused                   = pause_nonactive ? is_focused : true;
38240       focused                   = focused &&
38241          !p_rarch->main_ui_companion_is_on_foreground;
38242 
38243       if (global)
38244       {
38245          if (action == old_action)
38246          {
38247             retro_time_t press_time           = current_time;
38248 
38249             if (action == MENU_ACTION_NOOP)
38250                global->menu.noop_press_time   = press_time - global->menu.noop_start_time;
38251             else
38252                global->menu.action_press_time = press_time - global->menu.action_start_time;
38253          }
38254          else
38255          {
38256             if (action == MENU_ACTION_NOOP)
38257             {
38258                global->menu.noop_start_time      = current_time;
38259                global->menu.noop_press_time      = 0;
38260 
38261                if (global->menu_prev_action == old_action)
38262                   global->menu.action_start_time = global->menu.prev_start_time;
38263                else
38264                   global->menu.action_start_time = current_time;
38265             }
38266             else
38267             {
38268                if (  global->menu_prev_action == action &&
38269                      global->menu.noop_press_time < 200000) /* 250ms */
38270                {
38271                   global->menu.action_start_time = global->menu.prev_start_time;
38272                   global->menu.action_press_time = current_time - global->menu.action_start_time;
38273                }
38274                else
38275                {
38276                   global->menu.prev_start_time   = current_time;
38277                   global->menu_prev_action       = action;
38278                   global->menu.action_press_time = 0;
38279                }
38280             }
38281          }
38282       }
38283 
38284       /* Check whether menu screensaver should be enabled */
38285       if ((screensaver_timeout > 0) &&
38286           menu_st->screensaver_supported &&
38287           !menu_st->screensaver_active &&
38288           ((menu_st->current_time_us - menu_st->input_last_time_us) >
38289                ((retro_time_t)screensaver_timeout * 1000000)))
38290       {
38291          menu_ctx_environment_t menu_environ;
38292          menu_environ.type           = MENU_ENVIRON_ENABLE_SCREENSAVER;
38293          menu_environ.data           = NULL;
38294          menu_st->screensaver_active = true;
38295          menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
38296       }
38297 
38298       /* Iterate the menu driver for one frame. */
38299 
38300       if (menu_st->pending_quick_menu)
38301       {
38302          /* If the user had requested that the Quick Menu
38303           * be spawned during the previous frame, do this now
38304           * and exit the function to go to the next frame.
38305           */
38306          menu_entries_flush_stack(NULL, MENU_SETTINGS);
38307          gfx_display_set_msg_force(true);
38308 
38309          generic_action_ok_displaylist_push("", NULL,
38310                "", 0, 0, 0, ACTION_OK_DL_CONTENT_SETTINGS);
38311 
38312          menu_st->selection_ptr      = 0;
38313          menu_st->pending_quick_menu = false;
38314       }
38315       else if (!menu_driver_iterate(p_rarch,
38316                menu_st,
38317                &p_rarch->dispgfx,
38318                &p_rarch->anim,
38319                settings,
38320                action, current_time))
38321       {
38322          if (p_rarch->rarch_error_on_init)
38323          {
38324             content_ctx_info_t content_info = {0};
38325             task_push_start_dummy_core(&content_info);
38326          }
38327          else
38328             retroarch_menu_running_finished(false);
38329       }
38330 
38331       if (focused || !runloop_state.idle)
38332       {
38333          bool rarch_is_inited        = p_rarch->rarch_is_inited;
38334          bool menu_pause_libretro    = settings->bools.menu_pause_libretro;
38335          bool libretro_running       = !menu_pause_libretro
38336             && rarch_is_inited
38337             && (p_rarch->current_core_type != CORE_TYPE_DUMMY);
38338 
38339          if (menu)
38340          {
38341             if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER)
38342                   != BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX))
38343                BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
38344 
38345             if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER))
38346                p_rarch->dispgfx.framebuf_dirty = true;
38347 
38348             if (BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX)
38349                   && !string_is_empty(menu->menu_state_msg))
38350             {
38351                if (menu->driver_ctx->render_messagebox)
38352                   menu->driver_ctx->render_messagebox(
38353                         menu->userdata,
38354                         menu->menu_state_msg);
38355 
38356                if (p_rarch->main_ui_companion_is_on_foreground)
38357                {
38358                   if (  p_rarch->ui_companion &&
38359                         p_rarch->ui_companion->render_messagebox)
38360                      p_rarch->ui_companion->render_messagebox(menu->menu_state_msg);
38361                }
38362             }
38363 
38364             if (BIT64_GET(menu->state, MENU_STATE_BLIT))
38365             {
38366                if (menu->driver_ctx->render)
38367                   menu->driver_ctx->render(
38368                         menu->userdata,
38369                         p_rarch->video_driver_width,
38370                         p_rarch->video_driver_height,
38371                         runloop_state.idle);
38372             }
38373 
38374             if (p_rarch->menu_driver_alive && !runloop_state.idle)
38375                if (menu_display_libretro(p_rarch,
38376                         settings->floats.slowmotion_ratio,
38377                         libretro_running, current_time))
38378                   video_driver_cached_frame();
38379 
38380             if (menu->driver_ctx->set_texture)
38381                menu->driver_ctx->set_texture(menu->userdata);
38382 
38383             menu->state               = 0;
38384          }
38385 
38386          if (settings->bools.audio_enable_menu &&
38387                !libretro_running)
38388             audio_driver_menu_sample();
38389       }
38390 
38391       old_input                 = current_bits;
38392       old_action                = action;
38393 
38394       if (!focused || runloop_state.idle)
38395          return RUNLOOP_STATE_POLLED_AND_SLEEP;
38396    }
38397    else
38398 #endif
38399 #endif
38400    {
38401       if (runloop_state.idle)
38402       {
38403          cbs->poll_cb();
38404          return RUNLOOP_STATE_POLLED_AND_SLEEP;
38405       }
38406    }
38407 
38408    /* Check game focus toggle */
38409    {
38410       enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_TOGGLE;
38411       HOTKEY_CHECK(RARCH_GAME_FOCUS_TOGGLE, CMD_EVENT_GAME_FOCUS_TOGGLE, true, &game_focus_cmd);
38412    }
38413    /* Check if we have pressed the UI companion toggle button */
38414    HOTKEY_CHECK(RARCH_UI_COMPANION_TOGGLE, CMD_EVENT_UI_COMPANION_TOGGLE, true, NULL);
38415    /* Check close content key */
38416    HOTKEY_CHECK(RARCH_CLOSE_CONTENT_KEY, CMD_EVENT_CLOSE_CONTENT, true, NULL);
38417 
38418 #ifdef HAVE_MENU
38419    /* Check if we have pressed the menu toggle button */
38420    {
38421       static bool old_pressed = false;
38422       char *menu_driver       = settings->arrays.menu_driver;
38423       bool pressed            = BIT256_GET(
38424             current_bits, RARCH_MENU_TOGGLE) &&
38425          !string_is_equal(menu_driver, "null");
38426       bool core_type_is_dummy = p_rarch->current_core_type == CORE_TYPE_DUMMY;
38427 
38428       if (p_rarch->menu_keyboard_key_state[RETROK_F1] == 1)
38429       {
38430          if (p_rarch->menu_driver_alive)
38431          {
38432             if (rarch_is_initialized && !core_type_is_dummy)
38433             {
38434                retroarch_menu_running_finished(false);
38435                p_rarch->menu_keyboard_key_state[RETROK_F1] =
38436                   ((p_rarch->menu_keyboard_key_state[RETROK_F1] & 1) << 1) | false;
38437             }
38438          }
38439       }
38440       else if ((!p_rarch->menu_keyboard_key_state[RETROK_F1] &&
38441                (pressed && !old_pressed)) ||
38442             core_type_is_dummy)
38443       {
38444          if (p_rarch->menu_driver_alive)
38445          {
38446             if (rarch_is_initialized && !core_type_is_dummy)
38447                retroarch_menu_running_finished(false);
38448          }
38449          else
38450          {
38451             retroarch_menu_running();
38452          }
38453       }
38454       else
38455          p_rarch->menu_keyboard_key_state[RETROK_F1] =
38456             ((p_rarch->menu_keyboard_key_state[RETROK_F1] & 1) << 1) | false;
38457 
38458       old_pressed             = pressed;
38459    }
38460 
38461    /* Check if we have pressed the FPS toggle button */
38462    HOTKEY_CHECK(RARCH_FPS_TOGGLE, CMD_EVENT_FPS_TOGGLE, true, NULL);
38463 
38464    /* Check if we have pressed the netplay host toggle button */
38465    HOTKEY_CHECK(RARCH_NETPLAY_HOST_TOGGLE, CMD_EVENT_NETPLAY_HOST_TOGGLE, true, NULL);
38466 
38467    if (p_rarch->menu_driver_alive)
38468    {
38469       float fastforward_ratio = retroarch_get_runloop_fastforward_ratio(
38470             settings, &runloop_state);
38471 
38472       if (!settings->bools.menu_throttle_framerate && !fastforward_ratio)
38473          return RUNLOOP_STATE_MENU_ITERATE;
38474 
38475       return RUNLOOP_STATE_END;
38476    }
38477 #endif
38478 
38479    if (pause_nonactive)
38480       focused                = is_focused;
38481 
38482 #ifdef HAVE_SCREENSHOTS
38483    /* Check if we have pressed the screenshot toggle button */
38484    HOTKEY_CHECK(RARCH_SCREENSHOT, CMD_EVENT_TAKE_SCREENSHOT, true, NULL);
38485 #endif
38486 
38487    /* Check if we have pressed the audio mute toggle button */
38488    HOTKEY_CHECK(RARCH_MUTE, CMD_EVENT_AUDIO_MUTE_TOGGLE, true, NULL);
38489 
38490    /* Check if we have pressed the OSK toggle button */
38491    HOTKEY_CHECK(RARCH_OSK, CMD_EVENT_OSK_TOGGLE, true, NULL);
38492 
38493    /* Check if we have pressed the recording toggle button */
38494    HOTKEY_CHECK(RARCH_RECORDING_TOGGLE, CMD_EVENT_RECORDING_TOGGLE, true, NULL);
38495 
38496    /* Check if we have pressed the streaming toggle button */
38497    HOTKEY_CHECK(RARCH_STREAMING_TOGGLE, CMD_EVENT_STREAMING_TOGGLE, true, NULL);
38498 
38499    /* Check if we have pressed the Run-Ahead toggle button */
38500    HOTKEY_CHECK(RARCH_RUNAHEAD_TOGGLE, CMD_EVENT_RUNAHEAD_TOGGLE, true, NULL);
38501 
38502    /* Check if we have pressed the AI Service toggle button */
38503    HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
38504 
38505    if (BIT256_GET(current_bits, RARCH_VOLUME_UP))
38506       command_event(CMD_EVENT_VOLUME_UP, NULL);
38507    else if (BIT256_GET(current_bits, RARCH_VOLUME_DOWN))
38508       command_event(CMD_EVENT_VOLUME_DOWN, NULL);
38509 
38510 #ifdef HAVE_NETWORKING
38511    /* Check Netplay */
38512    HOTKEY_CHECK(RARCH_NETPLAY_GAME_WATCH, CMD_EVENT_NETPLAY_GAME_WATCH, true, NULL);
38513 #endif
38514 
38515    /* Check if we have pressed the pause button */
38516    {
38517       static bool old_frameadvance  = false;
38518       static bool old_pause_pressed = false;
38519       bool frameadvance_pressed     = false;
38520       bool trig_frameadvance        = false;
38521       bool pause_pressed            = BIT256_GET(current_bits, RARCH_PAUSE_TOGGLE);
38522 #ifdef HAVE_CHEEVOS
38523       if (cheevos_hardcore_active)
38524       {
38525          static int unpaused_frames = 0;
38526 
38527          /* Frame advance is not allowed when achievement hardcore is active */
38528          if (!runloop_state.paused)
38529          {
38530             /* Limit pause to approximately three times per second (depending on core framerate) */
38531             if (unpaused_frames < 20)
38532             {
38533                ++unpaused_frames;
38534                pause_pressed        = false;
38535             }
38536          }
38537          else
38538             unpaused_frames         = 0;
38539       }
38540       else
38541 #endif
38542       {
38543          frameadvance_pressed = BIT256_GET(current_bits, RARCH_FRAMEADVANCE);
38544          trig_frameadvance    = frameadvance_pressed && !old_frameadvance;
38545 
38546          /* FRAMEADVANCE will set us into pause mode. */
38547          pause_pressed       |= !runloop_state.paused
38548             && trig_frameadvance;
38549       }
38550 
38551       /* Check if libretro pause key was pressed. If so, pause or
38552        * unpause the libretro core. */
38553 
38554       if (focused)
38555       {
38556          if (pause_pressed && !old_pause_pressed)
38557             command_event(CMD_EVENT_PAUSE_TOGGLE, NULL);
38558          else if (!old_focus)
38559             command_event(CMD_EVENT_UNPAUSE, NULL);
38560       }
38561       else if (old_focus)
38562          command_event(CMD_EVENT_PAUSE, NULL);
38563 
38564       old_focus           = focused;
38565       old_pause_pressed   = pause_pressed;
38566       old_frameadvance    = frameadvance_pressed;
38567 
38568       if (runloop_state.paused)
38569       {
38570          bool toggle = !runloop_state.idle ? true : false;
38571 
38572          HOTKEY_CHECK(RARCH_FULLSCREEN_TOGGLE_KEY,
38573                CMD_EVENT_FULLSCREEN_TOGGLE, true, &toggle);
38574 
38575          /* Check if it's not oneshot */
38576 #ifdef HAVE_REWIND
38577          if (!(trig_frameadvance || BIT256_GET(current_bits, RARCH_REWIND)))
38578 #else
38579          if (!trig_frameadvance)
38580 #endif
38581             focused = false;
38582       }
38583    }
38584 
38585 #ifdef HAVE_ACCESSIBILITY
38586 #ifdef HAVE_TRANSLATE
38587    /* Copy over the retropad state to a buffer for the translate service
38588       to send off if it's run. */
38589    if (settings->bools.ai_service_enable)
38590    {
38591       p_rarch->ai_gamepad_state[0]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_B);
38592       p_rarch->ai_gamepad_state[1]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_Y);
38593       p_rarch->ai_gamepad_state[2]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_SELECT);
38594       p_rarch->ai_gamepad_state[3]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_START);
38595 
38596       p_rarch->ai_gamepad_state[4]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_UP);
38597       p_rarch->ai_gamepad_state[5]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_DOWN);
38598       p_rarch->ai_gamepad_state[6]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_LEFT);
38599       p_rarch->ai_gamepad_state[7]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_RIGHT);
38600 
38601       p_rarch->ai_gamepad_state[8]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_A);
38602       p_rarch->ai_gamepad_state[9]  = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_X);
38603       p_rarch->ai_gamepad_state[10] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L);
38604       p_rarch->ai_gamepad_state[11] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R);
38605 
38606       p_rarch->ai_gamepad_state[12] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L2);
38607       p_rarch->ai_gamepad_state[13] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R2);
38608       p_rarch->ai_gamepad_state[14] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L3);
38609       p_rarch->ai_gamepad_state[15] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R3);
38610    }
38611 #endif
38612 #endif
38613 
38614    if (!focused)
38615    {
38616       cbs->poll_cb();
38617       return RUNLOOP_STATE_POLLED_AND_SLEEP;
38618    }
38619 
38620    /* Check if we have pressed the fast forward button */
38621    /* To avoid continuous switching if we hold the button down, we require
38622     * that the button must go from pressed to unpressed back to pressed
38623     * to be able to toggle between them.
38624     */
38625    if (!runloop_state.fastmotion_override.inhibit_toggle)
38626    {
38627       static bool old_button_state            = false;
38628       static bool old_hold_button_state       = false;
38629       bool new_button_state                   = BIT256_GET(
38630             current_bits, RARCH_FAST_FORWARD_KEY);
38631       bool new_hold_button_state              = BIT256_GET(
38632             current_bits, RARCH_FAST_FORWARD_HOLD_KEY);
38633       bool check2                             = new_button_state && !old_button_state;
38634 
38635       if (!check2)
38636          check2                               = old_hold_button_state != new_hold_button_state;
38637 
38638       if (check2)
38639       {
38640          bool check1                          = p_rarch->input_driver_nonblock_state;
38641          p_rarch->input_driver_nonblock_state = !check1;
38642          runloop_state.fastmotion             = !check1;
38643          if (check1)
38644             p_rarch->fastforward_after_frames = 1;
38645          driver_set_nonblock_state();
38646 
38647          /* Reset frame time counter when toggling
38648           * fast-forward off, if required */
38649          if (!runloop_state.fastmotion &&
38650              settings->bools.frame_time_counter_reset_after_fastforwarding)
38651             p_rarch->video_driver_frame_time_count = 0;
38652       }
38653 
38654       old_button_state                  = new_button_state;
38655       old_hold_button_state             = new_hold_button_state;
38656    }
38657 
38658    /* Display fast-forward notification, unless
38659     * disabled via override */
38660    if (!runloop_state.fastmotion_override.fastforward ||
38661        runloop_state.fastmotion_override.notification)
38662    {
38663       /* > Use widgets, if enabled */
38664 #if defined(HAVE_GFX_WIDGETS)
38665       if (widgets_active)
38666          p_rarch->gfx_widgets_fast_forward =
38667                settings->bools.notification_show_fast_forward ?
38668                      runloop_state.fastmotion : false;
38669       else
38670 #endif
38671       {
38672          /* > If widgets are disabled, display fast-forward
38673           *   status via OSD text for 1 frame every frame */
38674          if (runloop_state.fastmotion &&
38675              settings->bools.notification_show_fast_forward)
38676             runloop_msg_queue_push(
38677                msg_hash_to_str(MSG_FAST_FORWARD), 1, 1, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
38678       }
38679    }
38680 #if defined(HAVE_GFX_WIDGETS)
38681    else
38682       p_rarch->gfx_widgets_fast_forward = false;
38683 #endif
38684 
38685    /* Check if we have pressed any of the state slot buttons */
38686    {
38687       static bool old_should_slot_increase = false;
38688       static bool old_should_slot_decrease = false;
38689       bool should_slot_increase            = BIT256_GET(
38690             current_bits, RARCH_STATE_SLOT_PLUS);
38691       bool should_slot_decrease            = BIT256_GET(
38692             current_bits, RARCH_STATE_SLOT_MINUS);
38693       bool check1                          = true;
38694       bool check2                          = should_slot_increase && !old_should_slot_increase;
38695       int addition                         = 1;
38696       int state_slot                       = settings->ints.state_slot;
38697 
38698       if (!check2)
38699       {
38700          check2                            = should_slot_decrease && !old_should_slot_decrease;
38701          check1                            = state_slot > 0;
38702          addition                          = -1;
38703       }
38704 
38705       /* Checks if the state increase/decrease keys have been pressed
38706        * for this frame. */
38707       if (check2)
38708       {
38709          char msg[128];
38710          int cur_state_slot                = state_slot;
38711          if (check1)
38712             configuration_set_int(settings, settings->ints.state_slot,
38713                   cur_state_slot + addition);
38714          msg[0] = '\0';
38715          snprintf(msg, sizeof(msg), "%s: %d",
38716                msg_hash_to_str(MSG_STATE_SLOT),
38717                settings->ints.state_slot);
38718          runloop_msg_queue_push(msg, 2, 180, true, NULL,
38719                MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
38720          RARCH_LOG("%s\n", msg);
38721       }
38722 
38723       old_should_slot_increase = should_slot_increase;
38724       old_should_slot_decrease = should_slot_decrease;
38725    }
38726 
38727    /* Check if we have pressed any of the savestate buttons */
38728    HOTKEY_CHECK(RARCH_SAVE_STATE_KEY, CMD_EVENT_SAVE_STATE, true, NULL);
38729    HOTKEY_CHECK(RARCH_LOAD_STATE_KEY, CMD_EVENT_LOAD_STATE, true, NULL);
38730 
38731 #ifdef HAVE_CHEEVOS
38732    if (!cheevos_hardcore_active)
38733 #endif
38734    {
38735       /* Check if rewind toggle was being held. */
38736       {
38737 #ifdef HAVE_REWIND
38738          char s[128];
38739          bool rewinding = false;
38740          unsigned t     = 0;
38741 
38742          s[0]           = '\0';
38743 
38744          rewinding      = state_manager_check_rewind(
38745                &p_rarch->rewind_st,
38746                BIT256_GET(current_bits, RARCH_REWIND),
38747                settings->uints.rewind_granularity,
38748                runloop_state.paused,
38749                s, sizeof(s), &t);
38750 
38751 #if defined(HAVE_GFX_WIDGETS)
38752          if (widgets_active)
38753             p_rarch->gfx_widgets_rewinding = rewinding;
38754          else
38755 #endif
38756          {
38757             if (rewinding)
38758                runloop_msg_queue_push(s, 0, t, true, NULL,
38759                      MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
38760          }
38761 #endif
38762       }
38763 
38764       {
38765          /* Checks if slowmotion toggle/hold was being pressed and/or held. */
38766          static bool old_slowmotion_button_state      = false;
38767          static bool old_slowmotion_hold_button_state = false;
38768          bool new_slowmotion_button_state             = BIT256_GET(
38769                current_bits, RARCH_SLOWMOTION_KEY);
38770          bool new_slowmotion_hold_button_state        = BIT256_GET(
38771                current_bits, RARCH_SLOWMOTION_HOLD_KEY);
38772 
38773          if (new_slowmotion_button_state && !old_slowmotion_button_state)
38774             runloop_state.slowmotion = !runloop_state.slowmotion;
38775          else if (old_slowmotion_hold_button_state != new_slowmotion_hold_button_state)
38776             runloop_state.slowmotion = new_slowmotion_hold_button_state;
38777 
38778          if (runloop_state.slowmotion)
38779          {
38780             if (settings->uints.video_black_frame_insertion)
38781                if (!runloop_state.idle)
38782                   video_driver_cached_frame();
38783 
38784 #if defined(HAVE_GFX_WIDGETS)
38785             if (!widgets_active)
38786 #endif
38787             {
38788 #ifdef HAVE_REWIND
38789                struct state_manager_rewind_state
38790                   *rewind_st = &p_rarch->rewind_st;
38791                if (rewind_st->frame_is_reversed)
38792                   runloop_msg_queue_push(
38793                         msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 1, 1, false, NULL,
38794                         MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
38795                else
38796 #endif
38797                   runloop_msg_queue_push(
38798                         msg_hash_to_str(MSG_SLOW_MOTION), 1, 1, false,
38799                         NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
38800             }
38801          }
38802 
38803          old_slowmotion_button_state                  = new_slowmotion_button_state;
38804          old_slowmotion_hold_button_state             = new_slowmotion_hold_button_state;
38805       }
38806    }
38807 
38808    /* Check movie record toggle */
38809    HOTKEY_CHECK(RARCH_BSV_RECORD_TOGGLE, CMD_EVENT_BSV_RECORDING_TOGGLE, true, NULL);
38810 
38811    /* Check shader prev/next */
38812    HOTKEY_CHECK(RARCH_SHADER_NEXT, CMD_EVENT_SHADER_NEXT, true, NULL);
38813    HOTKEY_CHECK(RARCH_SHADER_PREV, CMD_EVENT_SHADER_PREV, true, NULL);
38814 
38815    /* Check if we have pressed any of the disk buttons */
38816    HOTKEY_CHECK3(
38817          RARCH_DISK_EJECT_TOGGLE, CMD_EVENT_DISK_EJECT_TOGGLE,
38818          RARCH_DISK_NEXT,         CMD_EVENT_DISK_NEXT,
38819          RARCH_DISK_PREV,         CMD_EVENT_DISK_PREV);
38820 
38821    /* Check if we have pressed the reset button */
38822    HOTKEY_CHECK(RARCH_RESET, CMD_EVENT_RESET, true, NULL);
38823 
38824    /* Check cheats */
38825    HOTKEY_CHECK3(
38826          RARCH_CHEAT_INDEX_PLUS,  CMD_EVENT_CHEAT_INDEX_PLUS,
38827          RARCH_CHEAT_INDEX_MINUS, CMD_EVENT_CHEAT_INDEX_MINUS,
38828          RARCH_CHEAT_TOGGLE,      CMD_EVENT_CHEAT_TOGGLE);
38829 
38830 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
38831    if (settings->bools.video_shader_watch_files)
38832    {
38833       static rarch_timer_t timer = {0};
38834       static bool need_to_apply  = false;
38835 
38836       if (video_shader_check_for_changes())
38837       {
38838          need_to_apply = true;
38839 
38840          if (!timer.timer_begin)
38841          {
38842             uint64_t current_usec = cpu_features_get_time_usec();
38843             RARCH_TIMER_BEGIN_NEW_TIME_USEC(timer,
38844                   current_usec,
38845                   SHADER_FILE_WATCH_DELAY_MSEC * 1000);
38846             timer.timer_begin = true;
38847             timer.timer_end   = false;
38848          }
38849       }
38850 
38851       /* If a file is modified atomically (moved/renamed from a different file),
38852        * we have no idea how long that might take.
38853        * If we're trying to re-apply shaders immediately after changes are made
38854        * to the original file(s), the filesystem might be in an in-between
38855        * state where the new file hasn't been moved over yet and the original
38856        * file was already deleted. This leaves us no choice but to wait an
38857        * arbitrary amount of time and hope for the best.
38858        */
38859       if (need_to_apply)
38860       {
38861          RARCH_TIMER_TICK(timer, current_time);
38862 
38863          if (!timer.timer_end && RARCH_TIMER_HAS_EXPIRED(timer))
38864          {
38865             RARCH_TIMER_END(timer);
38866             need_to_apply = false;
38867             command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
38868          }
38869       }
38870    }
38871 
38872    if (   settings->uints.video_shader_delay &&
38873          !p_rarch->shader_delay_timer.timer_end)
38874    {
38875       if (!p_rarch->shader_delay_timer.timer_begin)
38876       {
38877          uint64_t current_usec = cpu_features_get_time_usec();
38878          RARCH_TIMER_BEGIN_NEW_TIME_USEC(
38879                p_rarch->shader_delay_timer,
38880                current_usec,
38881                settings->uints.video_shader_delay * 1000);
38882          p_rarch->shader_delay_timer.timer_begin = true;
38883          p_rarch->shader_delay_timer.timer_end   = false;
38884       }
38885       else
38886       {
38887          RARCH_TIMER_TICK(p_rarch->shader_delay_timer, current_time);
38888 
38889          if (RARCH_TIMER_HAS_EXPIRED(p_rarch->shader_delay_timer))
38890          {
38891             RARCH_TIMER_END(p_rarch->shader_delay_timer);
38892 
38893             {
38894                const char *preset = retroarch_get_shader_preset();
38895                enum rarch_shader_type type = video_shader_parse_type(preset);
38896                retroarch_apply_shader(p_rarch, settings, type, preset, false);
38897             }
38898          }
38899       }
38900    }
38901 #endif
38902 
38903    return RUNLOOP_STATE_ITERATE;
38904 }
38905 
38906 /**
38907  * runloop_iterate:
38908  *
38909  * Run Libretro core in RetroArch for one frame.
38910  *
38911  * Returns: 0 on success, 1 if we have to wait until
38912  * button input in order to wake up the loop,
38913  * -1 if we forcibly quit out of the RetroArch iteration loop.
38914  **/
runloop_iterate(void)38915 int runloop_iterate(void)
38916 {
38917    unsigned i;
38918    enum analog_dpad_mode dpad_mode[MAX_USERS];
38919    struct rarch_state                  *p_rarch = &rarch_st;
38920    settings_t *settings                         = p_rarch->configuration_settings;
38921    unsigned video_frame_delay                   = settings->uints.video_frame_delay;
38922    bool vrr_runloop_enable                      = settings->bools.vrr_runloop_enable;
38923    unsigned max_users                           = p_rarch->input_driver_max_users;
38924    retro_time_t current_time                    = cpu_features_get_time_usec();
38925 #ifdef HAVE_MENU
38926    bool menu_pause_libretro                     = settings->bools.menu_pause_libretro;
38927    bool core_paused                             = runloop_state.paused || (menu_pause_libretro && p_rarch->menu_driver_alive);
38928 #else
38929    bool core_paused                             = runloop_state.paused;
38930 #endif
38931    float slowmotion_ratio                       = settings->floats.slowmotion_ratio;
38932 #ifdef HAVE_CHEEVOS
38933    bool cheevos_enable                          = settings->bools.cheevos_enable;
38934 #endif
38935    bool audio_sync                              = settings->bools.audio_sync;
38936 
38937 
38938 #ifdef HAVE_DISCORD
38939    discord_state_t *discord_st                  = &p_rarch->discord_st;
38940 
38941    if (discord_is_inited)
38942    {
38943       Discord_RunCallbacks();
38944 #ifdef DISCORD_DISABLE_IO_THREAD
38945       Discord_UpdateConnection();
38946 #endif
38947    }
38948 #endif
38949 
38950    if (runloop_state.frame_time.callback)
38951    {
38952       /* Updates frame timing if frame timing callback is in use by the core.
38953        * Limits frame time if fast forward ratio throttle is enabled. */
38954       retro_usec_t runloop_last_frame_time = runloop_state.frame_time_last;
38955       retro_time_t current                 = current_time;
38956       bool is_locked_fps                   = (runloop_state.paused
38957             || p_rarch->input_driver_nonblock_state)
38958             | !!p_rarch->recording_data;
38959       retro_time_t delta                   = (!runloop_last_frame_time || is_locked_fps)
38960          ? runloop_state.frame_time.reference
38961          : (current - runloop_last_frame_time);
38962 
38963       if (is_locked_fps)
38964          runloop_state.frame_time_last  = 0;
38965       else
38966       {
38967          runloop_state.frame_time_last  = current;
38968 
38969          if (runloop_state.slowmotion)
38970             delta /= slowmotion_ratio;
38971       }
38972 
38973       if (!core_paused)
38974          runloop_state.frame_time.callback(delta);
38975    }
38976 
38977    /* Update audio buffer occupancy if buffer status
38978     * callback is in use by the core */
38979    if (runloop_state.audio_buffer_status.callback)
38980    {
38981       bool audio_buf_active        = false;
38982       unsigned audio_buf_occupancy = 0;
38983       bool audio_buf_underrun      = false;
38984 
38985       if (!(runloop_state.paused       ||
38986             !p_rarch->audio_driver_active ||
38987             !p_rarch->audio_driver_output_samples_buf) &&
38988           p_rarch->current_audio->write_avail &&
38989           p_rarch->audio_driver_context_audio_data &&
38990           p_rarch->audio_driver_buffer_size)
38991       {
38992          size_t audio_buf_avail;
38993 
38994          if ((audio_buf_avail = p_rarch->current_audio->write_avail(
38995                p_rarch->audio_driver_context_audio_data)) > p_rarch->audio_driver_buffer_size)
38996             audio_buf_avail = p_rarch->audio_driver_buffer_size;
38997 
38998          audio_buf_occupancy = (unsigned)(100 - (audio_buf_avail * 100) /
38999                p_rarch->audio_driver_buffer_size);
39000 
39001          /* Elsewhere, we standardise on a 'low water mark'
39002           * of 25% of the total audio buffer size - use
39003           * the same metric here (can be made more sophisticated
39004           * if required - i.e. determine buffer occupancy in
39005           * terms of usec, and weigh this against the expected
39006           * frame time) */
39007          audio_buf_underrun  = audio_buf_occupancy < 25;
39008 
39009          audio_buf_active    = true;
39010       }
39011 
39012       if (!core_paused)
39013          runloop_state.audio_buffer_status.callback(
39014                audio_buf_active, audio_buf_occupancy, audio_buf_underrun);
39015    }
39016 
39017    switch ((enum runloop_state)runloop_check_state(p_rarch,
39018             settings, current_time))
39019    {
39020       case RUNLOOP_STATE_QUIT:
39021          p_rarch->frame_limit_last_time = 0.0;
39022          runloop_state.core_running  = false;
39023          command_event(CMD_EVENT_QUIT, NULL);
39024          return -1;
39025       case RUNLOOP_STATE_POLLED_AND_SLEEP:
39026 #ifdef HAVE_NETWORKING
39027          /* FIXME: This is an ugly way to tell Netplay this... */
39028          netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
39029 #endif
39030 #if defined(HAVE_COCOATOUCH)
39031          if (!p_rarch->main_ui_companion_is_on_foreground)
39032 #endif
39033             retro_sleep(10);
39034          return 1;
39035       case RUNLOOP_STATE_END:
39036 #ifdef HAVE_NETWORKING
39037 #ifdef HAVE_MENU
39038          /* FIXME: This is an ugly way to tell Netplay this... */
39039          if (menu_pause_libretro &&
39040                netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)
39041             )
39042             netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
39043 #endif
39044 #endif
39045          goto end;
39046       case RUNLOOP_STATE_MENU_ITERATE:
39047 #ifdef HAVE_NETWORKING
39048          /* FIXME: This is an ugly way to tell Netplay this... */
39049          netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
39050 #endif
39051          return 0;
39052       case RUNLOOP_STATE_ITERATE:
39053          runloop_state.core_running = true;
39054          break;
39055    }
39056 
39057 #ifdef HAVE_THREADS
39058    if (runloop_state.autosave)
39059       autosave_lock();
39060 #endif
39061 
39062 #ifdef HAVE_BSV_MOVIE
39063    /* Used for rewinding while playback/record. */
39064    if (p_rarch->bsv_movie_state_handle)
39065       p_rarch->bsv_movie_state_handle->frame_pos[p_rarch->bsv_movie_state_handle->frame_ptr]
39066          = intfstream_tell(p_rarch->bsv_movie_state_handle->file);
39067 #endif
39068 
39069    if (  p_rarch->camera_cb.caps &&
39070          p_rarch->camera_driver  &&
39071          p_rarch->camera_driver->poll &&
39072          p_rarch->camera_data)
39073       p_rarch->camera_driver->poll(p_rarch->camera_data,
39074             p_rarch->camera_cb.frame_raw_framebuffer,
39075             p_rarch->camera_cb.frame_opengl_texture);
39076 
39077    /* Update binds for analog dpad modes. */
39078    for (i = 0; i < max_users; i++)
39079    {
39080       dpad_mode[i] = (enum analog_dpad_mode)
39081             settings->uints.input_analog_dpad_mode[i];
39082 
39083       switch (dpad_mode[i])
39084       {
39085          case ANALOG_DPAD_LSTICK:
39086          case ANALOG_DPAD_RSTICK:
39087             {
39088                unsigned mapped_port = settings->uints.input_remap_ports[i];
39089 
39090                if (p_rarch->input_driver_analog_requested[mapped_port])
39091                   dpad_mode[i] = ANALOG_DPAD_NONE;
39092             }
39093             break;
39094          case ANALOG_DPAD_LSTICK_FORCED:
39095             dpad_mode[i] = ANALOG_DPAD_LSTICK;
39096             break;
39097          case ANALOG_DPAD_RSTICK_FORCED:
39098             dpad_mode[i] = ANALOG_DPAD_RSTICK;
39099             break;
39100          default:
39101             break;
39102       }
39103 
39104       /* Push analog to D-Pad mappings to binds. */
39105       if (dpad_mode[i] != ANALOG_DPAD_NONE)
39106       {
39107          unsigned k;
39108          unsigned joy_idx                    = settings->uints.input_joypad_index[i];
39109          struct retro_keybind *general_binds = input_config_binds[joy_idx];
39110          struct retro_keybind *auto_binds    = input_autoconf_binds[joy_idx];
39111          unsigned x_plus                     = RARCH_ANALOG_RIGHT_X_PLUS;
39112          unsigned y_plus                     = RARCH_ANALOG_RIGHT_Y_PLUS;
39113          unsigned x_minus                    = RARCH_ANALOG_RIGHT_X_MINUS;
39114          unsigned y_minus                    = RARCH_ANALOG_RIGHT_Y_MINUS;
39115 
39116          if (dpad_mode[i] == ANALOG_DPAD_LSTICK)
39117          {
39118             x_plus            =  RARCH_ANALOG_LEFT_X_PLUS;
39119             y_plus            =  RARCH_ANALOG_LEFT_Y_PLUS;
39120             x_minus           =  RARCH_ANALOG_LEFT_X_MINUS;
39121             y_minus           =  RARCH_ANALOG_LEFT_Y_MINUS;
39122          }
39123 
39124          for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
39125          {
39126             (auto_binds)[k].orig_joyaxis    = (auto_binds)[k].joyaxis;
39127             (general_binds)[k].orig_joyaxis = (general_binds)[k].joyaxis;
39128          }
39129 
39130          if (!INHERIT_JOYAXIS(auto_binds))
39131          {
39132             unsigned j = x_plus + 3;
39133             /* Inherit joyaxis from analogs. */
39134             for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
39135                (auto_binds)[k].joyaxis = (auto_binds)[j--].joyaxis;
39136          }
39137 
39138          if (!INHERIT_JOYAXIS(general_binds))
39139          {
39140             unsigned j = x_plus + 3;
39141             /* Inherit joyaxis from analogs. */
39142             for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
39143                (general_binds)[k].joyaxis = (general_binds)[j--].joyaxis;
39144          }
39145       }
39146    }
39147 
39148    if ((video_frame_delay > 0) && !p_rarch->input_driver_nonblock_state)
39149       retro_sleep(video_frame_delay);
39150 
39151    {
39152 #ifdef HAVE_RUNAHEAD
39153       bool run_ahead_enabled            = settings->bools.run_ahead_enabled;
39154       unsigned run_ahead_num_frames     = settings->uints.run_ahead_frames;
39155       bool run_ahead_hide_warnings      = settings->bools.run_ahead_hide_warnings;
39156       bool run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance;
39157       /* Run Ahead Feature replaces the call to core_run in this loop */
39158       bool want_runahead                = run_ahead_enabled && run_ahead_num_frames > 0;
39159 #ifdef HAVE_NETWORKING
39160       want_runahead                     = want_runahead && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL);
39161 #endif
39162 
39163       if (want_runahead)
39164          do_runahead(
39165                p_rarch,
39166                run_ahead_num_frames,
39167                run_ahead_hide_warnings,
39168                run_ahead_secondary_instance);
39169       else
39170 #endif
39171          core_run();
39172    }
39173 
39174    /* Increment runtime tick counter after each call to
39175     * core_run() or run_ahead() */
39176    p_rarch->libretro_core_runtime_usec += rarch_core_runtime_tick(
39177          p_rarch,
39178          slowmotion_ratio,
39179          current_time);
39180 
39181 #ifdef HAVE_CHEEVOS
39182    if (cheevos_enable)
39183       rcheevos_test();
39184 #endif
39185 #ifdef HAVE_CHEATS
39186    cheat_manager_apply_retro_cheats();
39187 #endif
39188 #ifdef HAVE_DISCORD
39189    if (discord_is_inited && discord_st->ready)
39190       discord_update(DISCORD_PRESENCE_GAME);
39191 #endif
39192 
39193    /* Restores analog D-pad binds temporarily overridden. */
39194    for (i = 0; i < max_users; i++)
39195    {
39196       if (dpad_mode[i] != ANALOG_DPAD_NONE)
39197       {
39198          unsigned j;
39199          unsigned joy_idx                    = settings->uints.input_joypad_index[i];
39200          struct retro_keybind *general_binds = input_config_binds[joy_idx];
39201          struct retro_keybind *auto_binds    = input_autoconf_binds[joy_idx];
39202 
39203          for (j = RETRO_DEVICE_ID_JOYPAD_UP; j <= RETRO_DEVICE_ID_JOYPAD_RIGHT; j++)
39204          {
39205             (auto_binds)[j].joyaxis    = (auto_binds)[j].orig_joyaxis;
39206             (general_binds)[j].joyaxis = (general_binds)[j].orig_joyaxis;
39207          }
39208       }
39209    }
39210 
39211 #ifdef HAVE_BSV_MOVIE
39212    if (p_rarch->bsv_movie_state_handle)
39213    {
39214       p_rarch->bsv_movie_state_handle->frame_ptr    =
39215          (p_rarch->bsv_movie_state_handle->frame_ptr + 1)
39216          & p_rarch->bsv_movie_state_handle->frame_mask;
39217 
39218       p_rarch->bsv_movie_state_handle->first_rewind =
39219          !p_rarch->bsv_movie_state_handle->did_rewind;
39220       p_rarch->bsv_movie_state_handle->did_rewind   = false;
39221    }
39222 #endif
39223 
39224 #ifdef HAVE_THREADS
39225    if (runloop_state.autosave)
39226       autosave_unlock();
39227 #endif
39228 
39229 end:
39230    if (vrr_runloop_enable)
39231    {
39232       /* Sync on video only, block audio later. */
39233       if (p_rarch->fastforward_after_frames && audio_sync)
39234       {
39235          if (p_rarch->fastforward_after_frames == 1)
39236          {
39237             /* Nonblocking audio */
39238             if (p_rarch->audio_driver_active &&
39239                   p_rarch->audio_driver_context_audio_data)
39240                p_rarch->current_audio->set_nonblock_state(
39241                      p_rarch->audio_driver_context_audio_data, true);
39242             p_rarch->audio_driver_chunk_size =
39243                p_rarch->audio_driver_chunk_nonblock_size;
39244          }
39245 
39246          p_rarch->fastforward_after_frames++;
39247 
39248          if (p_rarch->fastforward_after_frames == 6)
39249          {
39250             /* Blocking audio */
39251             if (p_rarch->audio_driver_active &&
39252                   p_rarch->audio_driver_context_audio_data)
39253                p_rarch->current_audio->set_nonblock_state(
39254                      p_rarch->audio_driver_context_audio_data,
39255                      audio_sync ? false : true);
39256 
39257             p_rarch->audio_driver_chunk_size  =
39258                p_rarch->audio_driver_chunk_block_size;
39259             p_rarch->fastforward_after_frames = 0;
39260          }
39261       }
39262 
39263       if (runloop_state.fastmotion)
39264          retroarch_set_frame_limit(p_rarch,
39265                retroarch_get_runloop_fastforward_ratio(
39266                      settings, &runloop_state));
39267       else
39268          retroarch_set_frame_limit(p_rarch, 1.0f);
39269    }
39270 
39271    /* if there's a fast forward limit, inject sleeps to keep from going too fast. */
39272    if (p_rarch->frame_limit_minimum_time)
39273    {
39274       const retro_time_t end_frame_time = cpu_features_get_time_usec();
39275       const retro_time_t to_sleep_ms = (
39276             (p_rarch->frame_limit_last_time + p_rarch->frame_limit_minimum_time)
39277             - end_frame_time) / 1000;
39278 
39279       if (to_sleep_ms > 0)
39280       {
39281          unsigned               sleep_ms = (unsigned)to_sleep_ms;
39282 
39283          /* Combat jitter a bit. */
39284          p_rarch->frame_limit_last_time += p_rarch->frame_limit_minimum_time;
39285 
39286          if (sleep_ms > 0)
39287          {
39288 #if defined(HAVE_COCOATOUCH)
39289             if (!p_rarch->main_ui_companion_is_on_foreground)
39290 #endif
39291                retro_sleep(sleep_ms);
39292          }
39293 
39294          return 1;
39295       }
39296 
39297       p_rarch->frame_limit_last_time = end_frame_time;
39298    }
39299 
39300    return 0;
39301 }
39302 
runloop_get_system_info(void)39303 rarch_system_info_t *runloop_get_system_info(void)
39304 {
39305    return &runloop_state.system;
39306 }
39307 
runloop_get_libretro_system_info(void)39308 struct retro_system_info *runloop_get_libretro_system_info(void)
39309 {
39310    return &runloop_state.system.info;
39311 }
39312 
retroarch_force_video_driver_fallback(const char * driver)39313 void retroarch_force_video_driver_fallback(const char *driver)
39314 {
39315    struct rarch_state *p_rarch = &rarch_st;
39316    settings_t *settings        = p_rarch->configuration_settings;
39317    ui_msg_window_t *msg_window = NULL;
39318 
39319    configuration_set_string(settings,
39320          settings->arrays.video_driver,
39321          driver);
39322 
39323    command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL);
39324 
39325 #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) && !defined(WINAPI_FAMILY)
39326    /* UI companion driver is not inited yet, just call into it directly */
39327    msg_window = &ui_msg_window_win32;
39328 #endif
39329 
39330    if (msg_window)
39331    {
39332       char text[PATH_MAX_LENGTH];
39333       ui_msg_window_state window_state;
39334       char *title          = strdup(msg_hash_to_str(MSG_ERROR));
39335 
39336       text[0]              = '\0';
39337 
39338       snprintf(text, sizeof(text),
39339             msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER_FALLBACK),
39340             driver);
39341 
39342       window_state.buttons = UI_MSG_WINDOW_OK;
39343       window_state.text    = strdup(text);
39344       window_state.title   = title;
39345       window_state.window  = NULL;
39346 
39347       msg_window->error(&window_state);
39348 
39349       free(title);
39350    }
39351    exit(1);
39352 }
39353 
rarch_get_language_from_iso(const char * iso639)39354 enum retro_language rarch_get_language_from_iso(const char *iso639)
39355 {
39356    unsigned i;
39357    enum retro_language lang = RETRO_LANGUAGE_ENGLISH;
39358 
39359    struct lang_pair
39360    {
39361       const char *iso639;
39362       enum retro_language lang;
39363    };
39364 
39365    const struct lang_pair pairs[] =
39366    {
39367       {"en", RETRO_LANGUAGE_ENGLISH},
39368       {"ja", RETRO_LANGUAGE_JAPANESE},
39369       {"fr", RETRO_LANGUAGE_FRENCH},
39370       {"es", RETRO_LANGUAGE_SPANISH},
39371       {"de", RETRO_LANGUAGE_GERMAN},
39372       {"it", RETRO_LANGUAGE_ITALIAN},
39373       {"nl", RETRO_LANGUAGE_DUTCH},
39374       {"pt_BR", RETRO_LANGUAGE_PORTUGUESE_BRAZIL},
39375       {"pt_PT", RETRO_LANGUAGE_PORTUGUESE_PORTUGAL},
39376       {"pt", RETRO_LANGUAGE_PORTUGUESE_PORTUGAL},
39377       {"ru", RETRO_LANGUAGE_RUSSIAN},
39378       {"ko", RETRO_LANGUAGE_KOREAN},
39379       {"zh_CN", RETRO_LANGUAGE_CHINESE_SIMPLIFIED},
39380       {"zh_SG", RETRO_LANGUAGE_CHINESE_SIMPLIFIED},
39381       {"zh_HK", RETRO_LANGUAGE_CHINESE_TRADITIONAL},
39382       {"zh_TW", RETRO_LANGUAGE_CHINESE_TRADITIONAL},
39383       {"zh", RETRO_LANGUAGE_CHINESE_SIMPLIFIED},
39384       {"eo", RETRO_LANGUAGE_ESPERANTO},
39385       {"pl", RETRO_LANGUAGE_POLISH},
39386       {"vi", RETRO_LANGUAGE_VIETNAMESE},
39387       {"ar", RETRO_LANGUAGE_ARABIC},
39388       {"el", RETRO_LANGUAGE_GREEK},
39389       {"tr", RETRO_LANGUAGE_TURKISH},
39390       {"sk", RETRO_LANGUAGE_SLOVAK},
39391       {"fa", RETRO_LANGUAGE_PERSIAN},
39392       {"he", RETRO_LANGUAGE_HEBREW},
39393       {"ast", RETRO_LANGUAGE_ASTURIAN},
39394       {"fi", RETRO_LANGUAGE_FINNISH},
39395    };
39396 
39397    if (string_is_empty(iso639))
39398       return lang;
39399 
39400    for (i = 0; i < ARRAY_SIZE(pairs); i++)
39401    {
39402       if (strcasestr(iso639, pairs[i].iso639))
39403       {
39404          lang = pairs[i].lang;
39405          break;
39406       }
39407    }
39408 
39409    return lang;
39410 }
39411 
rarch_favorites_init(void)39412 void rarch_favorites_init(void)
39413 {
39414    struct rarch_state *p_rarch         = &rarch_st;
39415    settings_t *settings                = p_rarch->configuration_settings;
39416    int content_favorites_size          = settings ? settings->ints.content_favorites_size : 0;
39417    const char *path_content_favorites  = settings ? settings->paths.path_content_favorites : NULL;
39418    bool playlist_sort_alphabetical     = settings ? settings->bools.playlist_sort_alphabetical : false;
39419    playlist_config_t playlist_config;
39420    enum playlist_sort_mode current_sort_mode;
39421 
39422    playlist_config.capacity            = COLLECTION_SIZE;
39423    playlist_config.old_format          = settings ? settings->bools.playlist_use_old_format : false;
39424    playlist_config.compress            = settings ? settings->bools.playlist_compression : false;
39425    playlist_config.fuzzy_archive_match = settings ? settings->bools.playlist_fuzzy_archive_match : false;
39426    playlist_config_set_base_content_directory(&playlist_config, NULL);
39427 
39428    if (!settings)
39429       return;
39430 
39431    if (content_favorites_size >= 0)
39432       playlist_config.capacity = (size_t)content_favorites_size;
39433 
39434    rarch_favorites_deinit();
39435 
39436    RARCH_LOG("[Playlist]: %s: [%s].\n",
39437          msg_hash_to_str(MSG_LOADING_FAVORITES_FILE),
39438          path_content_favorites);
39439    playlist_config_set_path(&playlist_config, path_content_favorites);
39440    g_defaults.content_favorites = playlist_init(&playlist_config);
39441 
39442    /* Get current per-playlist sort mode */
39443    current_sort_mode = playlist_get_sort_mode(g_defaults.content_favorites);
39444 
39445    /* Ensure that playlist is sorted alphabetically,
39446     * if required */
39447    if ((playlist_sort_alphabetical && (current_sort_mode == PLAYLIST_SORT_MODE_DEFAULT)) ||
39448        (current_sort_mode == PLAYLIST_SORT_MODE_ALPHABETICAL))
39449       playlist_qsort(g_defaults.content_favorites);
39450 }
39451 
rarch_favorites_deinit(void)39452 void rarch_favorites_deinit(void)
39453 {
39454    if (!g_defaults.content_favorites)
39455       return;
39456 
39457    playlist_write_file(g_defaults.content_favorites);
39458    playlist_free(g_defaults.content_favorites);
39459    g_defaults.content_favorites = NULL;
39460 }
39461 
39462 /* Libretro core loader */
39463 
retro_run_null(void)39464 static void retro_run_null(void) { }
retro_frame_null(const void * data,unsigned width,unsigned height,size_t pitch)39465 static void retro_frame_null(const void *data, unsigned width,
39466       unsigned height, size_t pitch) { }
retro_input_poll_null(void)39467 static void retro_input_poll_null(void) { }
39468 
core_input_state_poll_late(unsigned port,unsigned device,unsigned idx,unsigned id)39469 static int16_t core_input_state_poll_late(unsigned port,
39470       unsigned device, unsigned idx, unsigned id)
39471 {
39472    struct rarch_state *p_rarch = &rarch_st;
39473    if (!p_rarch->current_core.input_polled)
39474       input_driver_poll();
39475    p_rarch->current_core.input_polled = true;
39476 
39477    return input_state(port, device, idx, id);
39478 }
39479 
core_input_state_poll_return_cb(void)39480 static retro_input_state_t core_input_state_poll_return_cb(void)
39481 {
39482    struct rarch_state *p_rarch = &rarch_st;
39483    const enum poll_type_override_t
39484       core_poll_type_override  = p_rarch->core_poll_type_override;
39485    unsigned new_poll_type      = (core_poll_type_override > POLL_TYPE_OVERRIDE_DONTCARE)
39486       ? (core_poll_type_override - 1)
39487       : p_rarch->current_core.poll_type;
39488    if (new_poll_type == POLL_TYPE_LATE)
39489       return core_input_state_poll_late;
39490    return input_state;
39491 }
39492 
core_input_state_poll_maybe(void)39493 static void core_input_state_poll_maybe(void)
39494 {
39495    struct rarch_state *p_rarch = &rarch_st;
39496    const enum poll_type_override_t
39497       core_poll_type_override  = p_rarch->core_poll_type_override;
39498    unsigned new_poll_type      = (core_poll_type_override > POLL_TYPE_OVERRIDE_DONTCARE)
39499       ? (core_poll_type_override - 1)
39500       : p_rarch->current_core.poll_type;
39501    if (new_poll_type == POLL_TYPE_NORMAL)
39502       input_driver_poll();
39503 }
39504 
39505 /**
39506  * core_init_libretro_cbs:
39507  * @data           : pointer to retro_callbacks object
39508  *
39509  * Initializes libretro callbacks, and binds the libretro callbacks
39510  * to default callback functions.
39511  **/
core_init_libretro_cbs(struct rarch_state * p_rarch,struct retro_callbacks * cbs)39512 static bool core_init_libretro_cbs(
39513       struct rarch_state *p_rarch,
39514       struct retro_callbacks *cbs)
39515 {
39516    retro_input_state_t state_cb = core_input_state_poll_return_cb();
39517 
39518    p_rarch->current_core.retro_set_video_refresh(video_driver_frame);
39519    p_rarch->current_core.retro_set_audio_sample(audio_driver_sample);
39520    p_rarch->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch);
39521    p_rarch->current_core.retro_set_input_state(state_cb);
39522    p_rarch->current_core.retro_set_input_poll(core_input_state_poll_maybe);
39523 
39524    core_set_default_callbacks(cbs);
39525 
39526 #ifdef HAVE_NETWORKING
39527    if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
39528       return true;
39529 
39530    core_set_netplay_callbacks();
39531 #endif
39532 
39533    return true;
39534 }
39535 
39536 /**
39537  * core_set_default_callbacks:
39538  * @data           : pointer to retro_callbacks object
39539  *
39540  * Binds the libretro callbacks to default callback functions.
39541  **/
core_set_default_callbacks(struct retro_callbacks * cbs)39542 static bool core_set_default_callbacks(struct retro_callbacks *cbs)
39543 {
39544    retro_input_state_t state_cb = core_input_state_poll_return_cb();
39545 
39546    cbs->frame_cb        = video_driver_frame;
39547    cbs->sample_cb       = audio_driver_sample;
39548    cbs->sample_batch_cb = audio_driver_sample_batch;
39549    cbs->state_cb        = state_cb;
39550    cbs->poll_cb         = input_driver_poll;
39551 
39552    return true;
39553 }
39554 
39555 
39556 
39557 #ifdef HAVE_REWIND
39558 /**
39559  * core_set_rewind_callbacks:
39560  *
39561  * Sets the audio sampling callbacks based on whether or not
39562  * rewinding is currently activated.
39563  **/
core_set_rewind_callbacks(void)39564 bool core_set_rewind_callbacks(void)
39565 {
39566    struct rarch_state *p_rarch  = &rarch_st;
39567    struct state_manager_rewind_state
39568       *rewind_st                = &p_rarch->rewind_st;
39569 
39570    if (rewind_st->frame_is_reversed)
39571    {
39572       p_rarch->current_core.retro_set_audio_sample(audio_driver_sample_rewind);
39573       p_rarch->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch_rewind);
39574    }
39575    else
39576    {
39577       p_rarch->current_core.retro_set_audio_sample(audio_driver_sample);
39578       p_rarch->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch);
39579    }
39580    return true;
39581 }
39582 #endif
39583 
39584 #ifdef HAVE_NETWORKING
39585 /**
39586  * core_set_netplay_callbacks:
39587  *
39588  * Set the I/O callbacks to use netplay's interceding callback system. Should
39589  * only be called while initializing netplay.
39590  **/
core_set_netplay_callbacks(void)39591 bool core_set_netplay_callbacks(void)
39592 {
39593    struct rarch_state *p_rarch  = &rarch_st;
39594 
39595    /* Force normal poll type for netplay. */
39596    p_rarch->current_core.poll_type = POLL_TYPE_NORMAL;
39597 
39598    /* And use netplay's interceding callbacks */
39599    p_rarch->current_core.retro_set_video_refresh(video_frame_net);
39600    p_rarch->current_core.retro_set_audio_sample(audio_sample_net);
39601    p_rarch->current_core.retro_set_audio_sample_batch(audio_sample_batch_net);
39602    p_rarch->current_core.retro_set_input_state(input_state_net);
39603 
39604    return true;
39605 }
39606 
39607 /**
39608  * core_unset_netplay_callbacks
39609  *
39610  * Unset the I/O callbacks from having used netplay's interceding callback
39611  * system. Should only be called while uninitializing netplay.
39612  */
core_unset_netplay_callbacks(void)39613 bool core_unset_netplay_callbacks(void)
39614 {
39615    struct retro_callbacks cbs;
39616    struct rarch_state *p_rarch  = &rarch_st;
39617 
39618    if (!core_set_default_callbacks(&cbs))
39619       return false;
39620 
39621    p_rarch->current_core.retro_set_video_refresh(cbs.frame_cb);
39622    p_rarch->current_core.retro_set_audio_sample(cbs.sample_cb);
39623    p_rarch->current_core.retro_set_audio_sample_batch(cbs.sample_batch_cb);
39624    p_rarch->current_core.retro_set_input_state(cbs.state_cb);
39625 
39626    return true;
39627 }
39628 #endif
39629 
core_set_cheat(retro_ctx_cheat_info_t * info)39630 bool core_set_cheat(retro_ctx_cheat_info_t *info)
39631 {
39632    struct rarch_state *p_rarch  = &rarch_st;
39633    p_rarch->current_core.retro_cheat_set(info->index, info->enabled, info->code);
39634    return true;
39635 }
39636 
core_reset_cheat(void)39637 bool core_reset_cheat(void)
39638 {
39639    struct rarch_state *p_rarch  = &rarch_st;
39640    p_rarch->current_core.retro_cheat_reset();
39641    return true;
39642 }
39643 
core_set_poll_type(unsigned type)39644 bool core_set_poll_type(unsigned type)
39645 {
39646    struct rarch_state *p_rarch  = &rarch_st;
39647    p_rarch->current_core.poll_type = type;
39648    return true;
39649 }
39650 
core_set_controller_port_device(retro_ctx_controller_info_t * pad)39651 bool core_set_controller_port_device(retro_ctx_controller_info_t *pad)
39652 {
39653    struct rarch_state *p_rarch  = &rarch_st;
39654    if (!pad)
39655       return false;
39656 
39657    /* We are potentially 'connecting' a entirely different
39658     * type of virtual input device, which may or may not
39659     * support analog inputs. We therefore have to reset
39660     * the 'analog input requested' flag for this port - but
39661     * since port mapping is arbitrary/mutable, it is easiest
39662     * to simply reset the flags for all ports.
39663     * Correct values will be registered at the next call
39664     * of 'input_state()' */
39665    memset(&p_rarch->input_driver_analog_requested, 0,
39666          sizeof(p_rarch->input_driver_analog_requested));
39667 
39668 #ifdef HAVE_RUNAHEAD
39669    remember_controller_port_device(p_rarch, pad->port, pad->device);
39670 #endif
39671 
39672    p_rarch->current_core.retro_set_controller_port_device(pad->port, pad->device);
39673    return true;
39674 }
39675 
core_get_memory(retro_ctx_memory_info_t * info)39676 bool core_get_memory(retro_ctx_memory_info_t *info)
39677 {
39678    struct rarch_state *p_rarch  = &rarch_st;
39679    if (!info)
39680       return false;
39681    info->size  = p_rarch->current_core.retro_get_memory_size(info->id);
39682    info->data  = p_rarch->current_core.retro_get_memory_data(info->id);
39683    return true;
39684 }
39685 
core_load_game(retro_ctx_load_content_info_t * load_info)39686 bool core_load_game(retro_ctx_load_content_info_t *load_info)
39687 {
39688    bool             contentless = false;
39689    bool             is_inited   = false;
39690    bool             game_loaded = false;
39691    struct rarch_state *p_rarch  = &rarch_st;
39692 
39693    video_driver_set_cached_frame_ptr(NULL);
39694 
39695 #ifdef HAVE_RUNAHEAD
39696    set_load_content_info(p_rarch, load_info);
39697    clear_controller_port_map(p_rarch);
39698 #endif
39699 
39700    content_get_status(&contentless, &is_inited);
39701    set_save_state_in_background(false);
39702 
39703    if (load_info && load_info->special)
39704       game_loaded = p_rarch->current_core.retro_load_game_special(
39705             load_info->special->id, load_info->info, load_info->content->size);
39706    else if (load_info && !string_is_empty(load_info->content->elems[0].data))
39707       game_loaded = p_rarch->current_core.retro_load_game(load_info->info);
39708    else if (contentless)
39709       game_loaded = p_rarch->current_core.retro_load_game(NULL);
39710 
39711    p_rarch->current_core.game_loaded = game_loaded;
39712 
39713    /* If 'game_loaded' is true at this point, then
39714     * core is actually running; register that any
39715     * changes to global remap-related parameters
39716     * should be reset once core is deinitialised */
39717    if (game_loaded)
39718       input_remapping_enable_global_config_restore();
39719 
39720    return game_loaded;
39721 }
39722 
core_get_system_info(struct retro_system_info * system)39723 bool core_get_system_info(struct retro_system_info *system)
39724 {
39725    struct rarch_state *p_rarch  = &rarch_st;
39726    if (!system)
39727       return false;
39728    p_rarch->current_core.retro_get_system_info(system);
39729    return true;
39730 }
39731 
core_unserialize(retro_ctx_serialize_info_t * info)39732 bool core_unserialize(retro_ctx_serialize_info_t *info)
39733 {
39734    struct rarch_state *p_rarch  = &rarch_st;
39735    if (!info || !p_rarch->current_core.retro_unserialize(info->data_const, info->size))
39736       return false;
39737 
39738 #if HAVE_NETWORKING
39739    netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
39740 #endif
39741 
39742    return true;
39743 }
39744 
core_serialize(retro_ctx_serialize_info_t * info)39745 bool core_serialize(retro_ctx_serialize_info_t *info)
39746 {
39747    struct rarch_state *p_rarch  = &rarch_st;
39748    if (!info || !p_rarch->current_core.retro_serialize(info->data, info->size))
39749       return false;
39750    return true;
39751 }
39752 
core_serialize_size(retro_ctx_size_info_t * info)39753 bool core_serialize_size(retro_ctx_size_info_t *info)
39754 {
39755    struct rarch_state *p_rarch  = &rarch_st;
39756    if (!info)
39757       return false;
39758    info->size = p_rarch->current_core.retro_serialize_size();
39759    return true;
39760 }
39761 
core_serialization_quirks(void)39762 uint64_t core_serialization_quirks(void)
39763 {
39764    struct rarch_state *p_rarch  = &rarch_st;
39765    return p_rarch->current_core.serialization_quirks_v;
39766 }
39767 
core_reset(void)39768 bool core_reset(void)
39769 {
39770    struct rarch_state *p_rarch  = &rarch_st;
39771 
39772    video_driver_set_cached_frame_ptr(NULL);
39773 
39774    p_rarch->current_core.retro_reset();
39775    return true;
39776 }
39777 
core_unload_game(struct rarch_state * p_rarch)39778 static bool core_unload_game(struct rarch_state *p_rarch)
39779 {
39780    video_driver_free_hw_context(p_rarch);
39781 
39782    video_driver_set_cached_frame_ptr(NULL);
39783 
39784    if (p_rarch->current_core.game_loaded)
39785    {
39786       RARCH_LOG("[Core]: Unloading game..\n");
39787       p_rarch->current_core.retro_unload_game();
39788       p_rarch->core_poll_type_override  = POLL_TYPE_OVERRIDE_DONTCARE;
39789       p_rarch->current_core.game_loaded = false;
39790    }
39791 
39792    audio_driver_stop(p_rarch);
39793 
39794    return true;
39795 }
39796 
core_run(void)39797 bool core_run(void)
39798 {
39799    struct rarch_state
39800       *p_rarch                 = &rarch_st;
39801    struct retro_core_t *
39802       current_core             = &p_rarch->current_core;
39803    const enum poll_type_override_t
39804       core_poll_type_override  = p_rarch->core_poll_type_override;
39805    unsigned new_poll_type      = (core_poll_type_override != POLL_TYPE_OVERRIDE_DONTCARE)
39806       ? (core_poll_type_override - 1)
39807       : current_core->poll_type;
39808    bool early_polling          = new_poll_type == POLL_TYPE_EARLY;
39809    bool late_polling           = new_poll_type == POLL_TYPE_LATE;
39810 #ifdef HAVE_NETWORKING
39811    bool netplay_preframe       = netplay_driver_ctl(
39812          RARCH_NETPLAY_CTL_PRE_FRAME, NULL);
39813 
39814    if (!netplay_preframe)
39815    {
39816       /* Paused due to netplay. We must poll and display something so that a
39817        * netplay peer pausing doesn't just hang. */
39818       input_driver_poll();
39819       video_driver_cached_frame();
39820       return true;
39821    }
39822 #endif
39823 
39824    if (early_polling)
39825       input_driver_poll();
39826    else if (late_polling)
39827       current_core->input_polled = false;
39828 
39829    current_core->retro_run();
39830 
39831    if (late_polling && !current_core->input_polled)
39832       input_driver_poll();
39833 
39834 #ifdef HAVE_NETWORKING
39835    netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL);
39836 #endif
39837 
39838    return true;
39839 }
39840 
core_verify_api_version(struct rarch_state * p_rarch)39841 static bool core_verify_api_version(struct rarch_state *p_rarch)
39842 {
39843    unsigned api_version        = p_rarch->current_core.retro_api_version();
39844 
39845    RARCH_LOG("%s: %u\n%s %s: %u\n",
39846          msg_hash_to_str(MSG_VERSION_OF_LIBRETRO_API),
39847          api_version,
39848          FILE_PATH_LOG_INFO,
39849          msg_hash_to_str(MSG_COMPILED_AGAINST_API),
39850          RETRO_API_VERSION
39851          );
39852 
39853    if (api_version != RETRO_API_VERSION)
39854    {
39855       RARCH_WARN("%s\n", msg_hash_to_str(MSG_LIBRETRO_ABI_BREAK));
39856       return false;
39857    }
39858    return true;
39859 }
39860 
core_load(struct rarch_state * p_rarch,unsigned poll_type_behavior)39861 static bool core_load(
39862       struct rarch_state *p_rarch,
39863       unsigned poll_type_behavior)
39864 {
39865    p_rarch->current_core.poll_type      = poll_type_behavior;
39866 
39867    if (!core_verify_api_version(p_rarch))
39868       return false;
39869    if (!core_init_libretro_cbs(p_rarch,
39870             &p_rarch->retro_ctx))
39871       return false;
39872 
39873    p_rarch->current_core.retro_get_system_av_info(
39874          &p_rarch->video_driver_av_info);
39875 
39876    return true;
39877 }
39878 
core_has_set_input_descriptor(void)39879 bool core_has_set_input_descriptor(void)
39880 {
39881    struct rarch_state *p_rarch = &rarch_st;
39882    return p_rarch->current_core.has_set_input_descriptors;
39883 }
39884 
retroarch_get_rotation(void)39885 unsigned int retroarch_get_rotation(void)
39886 {
39887    struct rarch_state *p_rarch = &rarch_st;
39888    settings_t     *settings    = p_rarch->configuration_settings;
39889    unsigned     video_rotation = settings->uints.video_rotation;
39890    return video_rotation + runloop_state.system.rotation;
39891 }
39892 
39893 #ifdef HAVE_ACCESSIBILITY
accessibility_speak_priority(struct rarch_state * p_rarch,bool accessibility_enable,unsigned accessibility_narrator_speech_speed,const char * speak_text,int priority)39894 static bool accessibility_speak_priority(
39895       struct rarch_state *p_rarch,
39896       bool accessibility_enable,
39897       unsigned accessibility_narrator_speech_speed,
39898       const char* speak_text, int priority)
39899 {
39900    if (is_accessibility_enabled(
39901             accessibility_enable,
39902             p_rarch->accessibility_enabled))
39903    {
39904       frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
39905 
39906       RARCH_LOG("Spoke: %s\n", speak_text);
39907 
39908       if (frontend && frontend->accessibility_speak)
39909          return frontend->accessibility_speak(accessibility_narrator_speech_speed, speak_text,
39910                priority);
39911 
39912       RARCH_LOG("Platform not supported for accessibility.\n");
39913       /* The following method is a fallback for other platforms to use the
39914          AI Service url to do the TTS.  However, since the playback is done
39915          via the audio mixer, which only processes the audio while the
39916          core is running, this playback method won't work.  When the audio
39917          mixer can handle playing streams while the core is paused, then
39918          we can use this. */
39919 #if 0
39920 #if defined(HAVE_NETWORKING)
39921       return accessibility_speak_ai_service(speak_text, voice, priority);
39922 #endif
39923 #endif
39924    }
39925 
39926    return true;
39927 }
39928 
39929 #ifdef HAVE_TRANSLATE
is_narrator_running(struct rarch_state * p_rarch,bool accessibility_enable)39930 static bool is_narrator_running(struct rarch_state *p_rarch,
39931       bool accessibility_enable)
39932 {
39933    if (is_accessibility_enabled(
39934             accessibility_enable,
39935             p_rarch->accessibility_enabled))
39936    {
39937       frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
39938       if (frontend && frontend->is_narrator_running)
39939          return frontend->is_narrator_running();
39940    }
39941    return true;
39942 }
39943 #endif
39944 #endif
39945 
39946 /* Creates folder and core options stub file for subsequent runs */
core_options_create_override(bool game_specific)39947 bool core_options_create_override(bool game_specific)
39948 {
39949    char options_path[PATH_MAX_LENGTH];
39950    config_file_t *conf         = NULL;
39951 
39952    options_path[0]             = '\0';
39953 
39954    if (!game_specific)
39955    {
39956       /* Sanity check - cannot create a folder-specific
39957        * override if a game-specific override is
39958        * already active */
39959       if (runloop_state.game_options_active)
39960          goto error;
39961 
39962       /* Get options file path (folder-specific) */
39963       if (!retroarch_validate_folder_options(
39964                options_path,
39965                sizeof(options_path), true))
39966          goto error;
39967    }
39968    else
39969    {
39970       /* Get options file path (game-specific) */
39971       if (!retroarch_validate_game_options(
39972                options_path,
39973                sizeof(options_path), true))
39974          goto error;
39975    }
39976 
39977    /* Open config file */
39978    if (!(conf = config_file_new_from_path_to_string(options_path)))
39979       if (!(conf = config_file_new_alloc()))
39980          goto error;
39981 
39982    /* Write config file */
39983    core_option_manager_flush(conf, runloop_state.core_options);
39984 
39985    if (!config_file_write(conf, options_path, true))
39986       goto error;
39987 
39988    runloop_msg_queue_push(
39989          msg_hash_to_str(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY),
39990          1, 100, true,
39991          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
39992 
39993    path_set(RARCH_PATH_CORE_OPTIONS, options_path);
39994    runloop_state.game_options_active   = game_specific;
39995    runloop_state.folder_options_active = !game_specific;
39996 
39997    config_file_free(conf);
39998    return true;
39999 
40000 error:
40001    runloop_msg_queue_push(
40002          msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE),
40003          1, 100, true,
40004          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
40005 
40006    if (conf)
40007       config_file_free(conf);
40008 
40009    return false;
40010 }
40011 
core_options_remove_override(bool game_specific)40012 bool core_options_remove_override(bool game_specific)
40013 {
40014    char new_options_path[PATH_MAX_LENGTH];
40015    struct rarch_state *p_rarch      = &rarch_st;
40016    core_option_manager_t *coreopts  = runloop_state.core_options;
40017    settings_t *settings             = p_rarch->configuration_settings;
40018    bool per_core_options            = !settings->bools.global_core_options;
40019    const char *path_core_options    = settings->paths.path_core_options;
40020    const char *current_options_path = NULL;
40021    config_file_t *conf              = NULL;
40022    bool folder_options_active       = false;
40023 
40024    new_options_path[0] = '\0';
40025 
40026    /* Sanity check 1 - if there are no core options
40027     * or no overrides are active, there is nothing to do */
40028    if (!coreopts ||
40029        (!runloop_state.game_options_active &&
40030             !runloop_state.folder_options_active))
40031       return true;
40032 
40033    /* Sanity check 2 - can only remove an override
40034     * if the specified type is currently active */
40035    if (game_specific && !runloop_state.game_options_active)
40036       goto error;
40037 
40038    /* Get current options file path */
40039    current_options_path = path_get(RARCH_PATH_CORE_OPTIONS);
40040    if (string_is_empty(current_options_path))
40041       goto error;
40042 
40043    /* Remove current options file, if required */
40044    if (path_is_valid(current_options_path))
40045       filestream_delete(current_options_path);
40046 
40047    /* Reload any existing 'parent' options file
40048     * > If we have removed a game-specific config,
40049     *   check whether a folder-specific config
40050     *   exists */
40051    if (game_specific &&
40052        retroarch_validate_folder_options(
40053           new_options_path,
40054           sizeof(new_options_path), false) &&
40055        path_is_valid(new_options_path))
40056       folder_options_active = true;
40057 
40058    /* > If a folder-specific config does not exist,
40059     *   or we removed it, check whether we have a
40060     *   top-level config file */
40061    if (!folder_options_active)
40062    {
40063       /* Try core-specific options, if enabled */
40064       if (per_core_options)
40065       {
40066          const char *core_name = runloop_state.system.info.library_name;
40067          per_core_options      = retroarch_validate_per_core_options(
40068                new_options_path, sizeof(new_options_path), true,
40069                      core_name, core_name);
40070       }
40071 
40072       /* ...otherwise use global options */
40073       if (!per_core_options)
40074       {
40075          if (!string_is_empty(path_core_options))
40076             strlcpy(new_options_path,
40077                   path_core_options, sizeof(new_options_path));
40078          else if (!path_is_empty(RARCH_PATH_CONFIG))
40079             fill_pathname_resolve_relative(
40080                   new_options_path, path_get(RARCH_PATH_CONFIG),
40081                         FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(new_options_path));
40082       }
40083    }
40084 
40085    if (string_is_empty(new_options_path))
40086       goto error;
40087 
40088    /* > If we have a valid file, load it */
40089    if (folder_options_active ||
40090        path_is_valid(new_options_path))
40091    {
40092       size_t i, j;
40093 
40094       if (!(conf = config_file_new_from_path_to_string(new_options_path)))
40095          goto error;
40096 
40097       for (i = 0; i < coreopts->size; i++)
40098       {
40099          struct core_option *option      = NULL;
40100          struct config_entry_list *entry = NULL;
40101 
40102          option = (struct core_option*)&coreopts->opts[i];
40103          if (!option)
40104             continue;
40105 
40106          entry = config_get_entry(conf, option->key);
40107          if (!entry || string_is_empty(entry->value))
40108             continue;
40109 
40110          /* Set current config value from file entry */
40111          for (j = 0; j < option->vals->size; j++)
40112          {
40113             if (string_is_equal(option->vals->elems[j].data, entry->value))
40114             {
40115                option->index = j;
40116                break;
40117             }
40118          }
40119       }
40120 
40121       coreopts->updated = true;
40122       config_file_free(conf);
40123 
40124 #ifdef HAVE_CHEEVOS
40125       rcheevos_validate_config_settings();
40126 #endif
40127    }
40128 
40129    /* Update runloop status */
40130    if (folder_options_active)
40131    {
40132       path_set(RARCH_PATH_CORE_OPTIONS, new_options_path);
40133       runloop_state.game_options_active   = false;
40134       runloop_state.folder_options_active = true;
40135    }
40136    else
40137    {
40138       path_clear(RARCH_PATH_CORE_OPTIONS);
40139       runloop_state.game_options_active   = false;
40140       runloop_state.folder_options_active = false;
40141 
40142       strlcpy(coreopts->conf_path, new_options_path,
40143             sizeof(coreopts->conf_path));
40144    }
40145 
40146    runloop_msg_queue_push(
40147          msg_hash_to_str(MSG_CORE_OPTIONS_FILE_REMOVED_SUCCESSFULLY),
40148          1, 100, true,
40149          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
40150 
40151    return true;
40152 
40153 error:
40154    runloop_msg_queue_push(
40155          msg_hash_to_str(MSG_ERROR_REMOVING_CORE_OPTIONS_FILE),
40156          1, 100, true,
40157          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
40158 
40159    if (conf)
40160       config_file_free(conf);
40161 
40162    return false;
40163 }
40164 
core_options_reset(void)40165 void core_options_reset(void)
40166 {
40167    core_option_manager_t *coreopts = runloop_state.core_options;
40168    size_t i;
40169 
40170    /* If there are no core options, there
40171     * is nothing to do */
40172    if (!coreopts || (coreopts->size < 1))
40173       return;
40174 
40175    for (i = 0; i < coreopts->size; i++)
40176       coreopts->opts[i].index = coreopts->opts[i].default_index;
40177 
40178    coreopts->updated = true;
40179 
40180 #ifdef HAVE_CHEEVOS
40181    rcheevos_validate_config_settings();
40182 #endif
40183 
40184    runloop_msg_queue_push(
40185          msg_hash_to_str(MSG_CORE_OPTIONS_RESET),
40186          1, 100, true,
40187          NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
40188 }
40189 
menu_content_environment_get(int * argc,char * argv[],void * args,void * params_data)40190 void menu_content_environment_get(int *argc, char *argv[],
40191       void *args, void *params_data)
40192 {
40193    struct rarch_state       *p_rarch = &rarch_st;
40194    struct rarch_main_wrap *wrap_args = (struct rarch_main_wrap*)params_data;
40195    rarch_system_info_t *sys_info     = &runloop_state.system;
40196 
40197    if (!wrap_args)
40198       return;
40199 
40200    wrap_args->no_content             = sys_info->load_no_content;
40201 
40202    if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_VERBOSITY, NULL))
40203       wrap_args->verbose       = verbosity_is_enabled();
40204 
40205    wrap_args->touched          = true;
40206    wrap_args->config_path      = NULL;
40207    wrap_args->sram_path        = NULL;
40208    wrap_args->state_path       = NULL;
40209    wrap_args->content_path     = NULL;
40210 
40211    if (!path_is_empty(RARCH_PATH_CONFIG))
40212       wrap_args->config_path   = path_get(RARCH_PATH_CONFIG);
40213    if (!string_is_empty(p_rarch->dir_savefile))
40214       wrap_args->sram_path     = p_rarch->dir_savefile;
40215    if (!string_is_empty(p_rarch->dir_savestate))
40216       wrap_args->state_path    = p_rarch->dir_savestate;
40217    if (!path_is_empty(RARCH_PATH_CONTENT))
40218       wrap_args->content_path  = path_get(RARCH_PATH_CONTENT);
40219    if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL))
40220       wrap_args->libretro_path = string_is_empty(path_get(RARCH_PATH_CORE)) ? NULL :
40221          path_get(RARCH_PATH_CORE);
40222 }
40223 
frontend_get_ptr(void)40224 frontend_ctx_driver_t *frontend_get_ptr(void)
40225 {
40226    struct rarch_state *p_rarch = &rarch_st;
40227    return p_rarch->current_frontend_ctx;
40228 }
40229 
frontend_driver_parse_drive_list(void * data,bool load_content)40230 int frontend_driver_parse_drive_list(void *data, bool load_content)
40231 {
40232    struct rarch_state     *p_rarch = &rarch_st;
40233    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40234 
40235    if (!frontend || !frontend->parse_drive_list)
40236       return -1;
40237    return frontend->parse_drive_list(data, load_content);
40238 }
40239 
frontend_driver_content_loaded(void)40240 void frontend_driver_content_loaded(void)
40241 {
40242    struct rarch_state     *p_rarch = &rarch_st;
40243    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40244 
40245    if (!frontend || !frontend->content_loaded)
40246       return;
40247    frontend->content_loaded();
40248 }
40249 
frontend_driver_has_fork(void)40250 bool frontend_driver_has_fork(void)
40251 {
40252    struct rarch_state     *p_rarch = &rarch_st;
40253    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40254 
40255    if (!frontend || !frontend->set_fork)
40256       return false;
40257    return true;
40258 }
40259 
frontend_driver_set_fork(enum frontend_fork fork_mode)40260 bool frontend_driver_set_fork(enum frontend_fork fork_mode)
40261 {
40262    struct rarch_state     *p_rarch = &rarch_st;
40263    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40264 
40265    if (!frontend_driver_has_fork())
40266       return false;
40267    return frontend->set_fork(fork_mode);
40268 }
40269 
frontend_driver_process_args(int * argc,char * argv[])40270 void frontend_driver_process_args(int *argc, char *argv[])
40271 {
40272    struct rarch_state     *p_rarch = &rarch_st;
40273    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40274 
40275    if (frontend && frontend->process_args)
40276       frontend->process_args(argc, argv);
40277 }
40278 
frontend_driver_is_inited(void)40279 bool frontend_driver_is_inited(void)
40280 {
40281    struct rarch_state     *p_rarch = &rarch_st;
40282    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40283    return frontend != NULL;
40284 }
40285 
frontend_driver_init_first(void * args)40286 void frontend_driver_init_first(void *args)
40287 {
40288    struct rarch_state *p_rarch   = &rarch_st;
40289    p_rarch->current_frontend_ctx = (frontend_ctx_driver_t*)
40290       frontend_ctx_init_first();
40291 
40292    if (p_rarch->current_frontend_ctx && p_rarch->current_frontend_ctx->init)
40293       p_rarch->current_frontend_ctx->init(args);
40294 }
40295 
frontend_driver_free(void)40296 void frontend_driver_free(void)
40297 {
40298    struct rarch_state *p_rarch      = &rarch_st;
40299 
40300    if (p_rarch)
40301       p_rarch->current_frontend_ctx = NULL;
40302 }
40303 
frontend_driver_environment_get_ptr(void)40304 environment_get_t frontend_driver_environment_get_ptr(void)
40305 {
40306    struct rarch_state     *p_rarch = &rarch_st;
40307    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40308    if (frontend)
40309       return frontend->environment_get;
40310    return NULL;
40311 }
40312 
frontend_driver_has_get_video_driver_func(void)40313 bool frontend_driver_has_get_video_driver_func(void)
40314 {
40315    struct rarch_state     *p_rarch = &rarch_st;
40316    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40317    if (!frontend || !frontend->get_video_driver)
40318       return false;
40319    return true;
40320 }
40321 
frontend_driver_get_video_driver(void)40322 const struct video_driver *frontend_driver_get_video_driver(void)
40323 {
40324    struct rarch_state     *p_rarch = &rarch_st;
40325    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40326    if (!frontend || !frontend->get_video_driver)
40327       return NULL;
40328    return frontend->get_video_driver();
40329 }
40330 
frontend_driver_exitspawn(char * s,size_t len,char * args)40331 void frontend_driver_exitspawn(char *s, size_t len, char *args)
40332 {
40333    struct rarch_state     *p_rarch = &rarch_st;
40334    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40335    if (frontend && frontend->exitspawn)
40336       frontend->exitspawn(s, len, args);
40337 }
40338 
frontend_driver_deinit(void * args)40339 void frontend_driver_deinit(void *args)
40340 {
40341    struct rarch_state     *p_rarch = &rarch_st;
40342    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40343    if (frontend && frontend->deinit)
40344       frontend->deinit(args);
40345 }
40346 
frontend_driver_shutdown(bool a)40347 void frontend_driver_shutdown(bool a)
40348 {
40349    struct rarch_state     *p_rarch = &rarch_st;
40350    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40351    if (frontend && frontend->shutdown)
40352       frontend->shutdown(a);
40353 }
40354 
frontend_driver_get_cpu_architecture(void)40355 enum frontend_architecture frontend_driver_get_cpu_architecture(void)
40356 {
40357    struct rarch_state     *p_rarch = &rarch_st;
40358    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40359    if (!frontend || !frontend->get_architecture)
40360       return FRONTEND_ARCH_NONE;
40361    return frontend->get_architecture();
40362 }
40363 
frontend_driver_get_cpu_architecture_str(char * architecture,size_t size)40364 const void *frontend_driver_get_cpu_architecture_str(
40365       char *architecture, size_t size)
40366 {
40367    struct rarch_state     *p_rarch = &rarch_st;
40368    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40369    enum frontend_architecture arch = frontend_driver_get_cpu_architecture();
40370 
40371    switch (arch)
40372    {
40373       case FRONTEND_ARCH_X86:
40374          strcpy_literal(architecture, "x86");
40375          break;
40376       case FRONTEND_ARCH_X86_64:
40377          strcpy_literal(architecture, "x64");
40378          break;
40379       case FRONTEND_ARCH_PPC:
40380          strcpy_literal(architecture, "PPC");
40381          break;
40382       case FRONTEND_ARCH_ARM:
40383          strcpy_literal(architecture, "ARM");
40384          break;
40385       case FRONTEND_ARCH_ARMV7:
40386          strcpy_literal(architecture, "ARMv7");
40387          break;
40388       case FRONTEND_ARCH_ARMV8:
40389          strcpy_literal(architecture, "ARMv8");
40390          break;
40391       case FRONTEND_ARCH_MIPS:
40392          strcpy_literal(architecture, "MIPS");
40393          break;
40394       case FRONTEND_ARCH_TILE:
40395          strcpy_literal(architecture, "Tilera");
40396          break;
40397       case FRONTEND_ARCH_NONE:
40398       default:
40399          strcpy_literal(architecture, "N/A");
40400          break;
40401    }
40402 
40403    return frontend;
40404 }
40405 
frontend_driver_get_total_memory(void)40406 uint64_t frontend_driver_get_total_memory(void)
40407 {
40408    struct rarch_state     *p_rarch = &rarch_st;
40409    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40410    if (!frontend || !frontend->get_total_mem)
40411       return 0;
40412    return frontend->get_total_mem();
40413 }
40414 
frontend_driver_get_free_memory(void)40415 uint64_t frontend_driver_get_free_memory(void)
40416 {
40417    struct rarch_state     *p_rarch = &rarch_st;
40418    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40419    if (!frontend || !frontend->get_free_mem)
40420       return 0;
40421    return frontend->get_free_mem();
40422 }
40423 
frontend_driver_install_signal_handler(void)40424 void frontend_driver_install_signal_handler(void)
40425 {
40426    struct rarch_state     *p_rarch = &rarch_st;
40427    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40428    if (frontend && frontend->install_signal_handler)
40429       frontend->install_signal_handler();
40430 }
40431 
frontend_driver_get_signal_handler_state(void)40432 int frontend_driver_get_signal_handler_state(void)
40433 {
40434    struct rarch_state     *p_rarch = &rarch_st;
40435    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40436    if (!frontend || !frontend->get_signal_handler_state)
40437       return -1;
40438    return frontend->get_signal_handler_state();
40439 }
40440 
frontend_driver_set_signal_handler_state(int value)40441 void frontend_driver_set_signal_handler_state(int value)
40442 {
40443    struct rarch_state     *p_rarch = &rarch_st;
40444    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40445    if (frontend && frontend->set_signal_handler_state)
40446       frontend->set_signal_handler_state(value);
40447 }
40448 
frontend_driver_attach_console(void)40449 void frontend_driver_attach_console(void)
40450 {
40451    struct rarch_state     *p_rarch = &rarch_st;
40452    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40453    if (frontend && frontend->attach_console)
40454       frontend->attach_console();
40455 }
40456 
frontend_driver_set_screen_brightness(int value)40457 void frontend_driver_set_screen_brightness(int value)
40458 {
40459    struct rarch_state     *p_rarch = &rarch_st;
40460    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40461    if (frontend && frontend->set_screen_brightness)
40462       frontend->set_screen_brightness(value);
40463 }
40464 
frontend_driver_can_set_screen_brightness()40465 bool frontend_driver_can_set_screen_brightness()
40466 {
40467    struct rarch_state     *p_rarch = &rarch_st;
40468    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40469    return (frontend && frontend->set_screen_brightness);
40470 }
40471 
frontend_driver_detach_console(void)40472 void frontend_driver_detach_console(void)
40473 {
40474    struct rarch_state     *p_rarch = &rarch_st;
40475    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40476    if (frontend && frontend->detach_console)
40477       frontend->detach_console();
40478 }
40479 
frontend_driver_destroy_signal_handler_state(void)40480 void frontend_driver_destroy_signal_handler_state(void)
40481 {
40482    struct rarch_state     *p_rarch = &rarch_st;
40483    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40484    if (frontend && frontend->destroy_signal_handler_state)
40485       frontend->destroy_signal_handler_state();
40486 }
40487 
frontend_driver_can_watch_for_changes(void)40488 bool frontend_driver_can_watch_for_changes(void)
40489 {
40490    struct rarch_state     *p_rarch = &rarch_st;
40491    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40492    if (!frontend || !frontend->watch_path_for_changes)
40493       return false;
40494    return true;
40495 }
40496 
frontend_driver_watch_path_for_changes(struct string_list * list,int flags,path_change_data_t ** change_data)40497 void frontend_driver_watch_path_for_changes(
40498       struct string_list *list, int flags,
40499       path_change_data_t **change_data)
40500 {
40501    struct rarch_state     *p_rarch = &rarch_st;
40502    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40503    if (frontend && frontend->watch_path_for_changes)
40504       frontend->watch_path_for_changes(list, flags, change_data);
40505 }
40506 
frontend_driver_check_for_path_changes(path_change_data_t * change_data)40507 bool frontend_driver_check_for_path_changes(path_change_data_t *change_data)
40508 {
40509    struct rarch_state     *p_rarch = &rarch_st;
40510    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40511    if (!frontend || !frontend->check_for_path_changes)
40512       return false;
40513    return frontend->check_for_path_changes(change_data);
40514 }
40515 
frontend_driver_set_sustained_performance_mode(bool on)40516 void frontend_driver_set_sustained_performance_mode(bool on)
40517 {
40518    struct rarch_state     *p_rarch = &rarch_st;
40519    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40520    if (frontend && frontend->set_sustained_performance_mode)
40521       frontend->set_sustained_performance_mode(on);
40522 }
40523 
frontend_driver_get_cpu_model_name(void)40524 const char* frontend_driver_get_cpu_model_name(void)
40525 {
40526    struct rarch_state     *p_rarch = &rarch_st;
40527    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40528    if (!frontend || !frontend->get_cpu_model_name)
40529       return NULL;
40530    return frontend->get_cpu_model_name();
40531 }
40532 
frontend_driver_get_user_language(void)40533 enum retro_language frontend_driver_get_user_language(void)
40534 {
40535    struct rarch_state     *p_rarch = &rarch_st;
40536    frontend_ctx_driver_t *frontend = p_rarch->current_frontend_ctx;
40537    if (!frontend || !frontend->get_user_language)
40538       return RETRO_LANGUAGE_ENGLISH;
40539    return frontend->get_user_language();
40540 }
40541