diff --git a/gfx/video_crt_switch.c b/gfx/video_crt_switch.c index d154cfa41b..4a9e582aaa 100644 --- a/gfx/video_crt_switch.c +++ b/gfx/video_crt_switch.c @@ -1,206 +1,351 @@ -/* CRT SwitchRes Core - * Copyright (C) 2018 Alphanu / Ben Templeman. - * - * RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ -#include -#include -#include - -#include "video_driver.h" -#include "video_crt_switch.h" -#include "video_display_server.h" - -static unsigned ra_core_width = 0; -static unsigned ra_core_height = 0; -static unsigned ra_tmp_width = 0; -static unsigned ra_tmp_height = 0; -static unsigned ra_set_core_hz = 0; -static unsigned orig_width = 0; -static unsigned orig_height = 0; -static int crt_center_adjust = 0; - -static bool first_run = true; - -static float ra_tmp_core_hz = 0.0f; -static float fly_aspect = 0.0f; -static float ra_core_hz = 0.0f; - -static void crt_check_first_run(void) -{ - if (!first_run) - return; - - first_run = false; -} - -static void switch_crt_hz(void) -{ - if (ra_core_hz == ra_tmp_core_hz) - return; - /* set hz float to an int for windows switching */ - if (ra_core_hz < 100) - { - if (ra_core_hz < 53) - ra_set_core_hz = 50; - if (ra_core_hz >= 53 && ra_core_hz < 57) - ra_set_core_hz = 55; - if (ra_core_hz >= 57) - ra_set_core_hz = 60; - } - - if (ra_core_hz > 100) - { - if (ra_core_hz < 106) - ra_set_core_hz = 120; - if (ra_core_hz >= 106 && ra_core_hz < 114) - ra_set_core_hz = 110; - if (ra_core_hz >= 114) - ra_set_core_hz = 120; - } - - video_monitor_set_refresh_rate(ra_set_core_hz); - - ra_tmp_core_hz = ra_core_hz; -} - -void crt_aspect_ratio_switch(unsigned width, unsigned height) -{ - /* send aspect float to videeo_driver */ - fly_aspect = (float)width / height; - video_driver_set_aspect_ratio_value((float)fly_aspect); -} - -static void switch_res_crt(unsigned width, unsigned height) -{ - if (height > 100) - { - video_display_server_set_resolution(width, height, - ra_set_core_hz, ra_core_hz, crt_center_adjust); - video_driver_apply_state_changes(); - } -} - -/* Create correct aspect to fit video if resolution does not exist */ -static void crt_screen_setup_aspect(unsigned width, unsigned height) -{ - - switch_crt_hz(); - /* get original resolution of core */ - if (height == 4) - { - /* detect menu only */ - if (width < 1920) - width = 320; - - height = 240; - - crt_aspect_ratio_switch(width, height); - } - - if (height < 200 && height != 144) - { - crt_aspect_ratio_switch(width, height); - height = 200; - } - - if (height > 200) - crt_aspect_ratio_switch(width, height); - - if (height == 144 && ra_set_core_hz == 50) - { - height = 288; - crt_aspect_ratio_switch(width, height); - } - - if (height > 200 && height < 224) - { - crt_aspect_ratio_switch(width, height); - height = 224; - } - - if (height > 224 && height < 240) - { - crt_aspect_ratio_switch(width, height); - height = 240; - } - - if (height > 240 && height < 255) - { - crt_aspect_ratio_switch(width, height); - height = 254; - } - - if (height == 528 && ra_set_core_hz == 60) - { - crt_aspect_ratio_switch(width, height); - height = 480; - } - - if (height >= 240 && height < 255 && ra_set_core_hz == 55) - { - crt_aspect_ratio_switch(width, height); - height = 254; - } - - switch_res_crt(width, height); -} - -void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust) -{ - /* ra_core_hz float passed from within - * void video_driver_monitor_adjust_system_rates(void) */ - ra_core_width = width; - ra_core_height = height; - ra_core_hz = hz; - crt_center_adjust = crt_switch_center_adjust; - - if (crt_mode == 2) - { - if (hz > 53) - ra_core_hz = hz * 2; - - if (hz <= 53) - ra_core_hz = 120.0f; - } - - crt_check_first_run(); - - /* Detect resolution change and switch */ - if ( - (ra_tmp_height != ra_core_height) || - (ra_core_width != ra_tmp_width) - ) - crt_screen_setup_aspect(width, height); - - ra_tmp_height = ra_core_height; - ra_tmp_width = ra_core_width; - - /* Check if aspect is correct, if notchange */ - if (video_driver_get_aspect_ratio() != fly_aspect) - { - video_driver_set_aspect_ratio_value((float)fly_aspect); - video_driver_apply_state_changes(); - } -} - -void crt_video_restore(void) -{ - if (first_run) - return; - - first_run = true; -} +/* CRT SwitchRes Core + * Copyright (C) 2018 Alphanu / Ben Templeman. + * + * RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ +#include +#include +#include + +#include "video_driver.h" +#include "video_crt_switch.h" +#include "video_display_server.h" + +#if defined(__arm__) + #include "include/userland/interface/vmcs_host/vc_vchi_gencmd.h" +#endif + +static unsigned ra_core_width = 0; +static unsigned ra_core_height = 0; +static unsigned ra_tmp_width = 0; +static unsigned ra_tmp_height = 0; +static unsigned ra_set_core_hz = 0; +static unsigned orig_width = 0; +static unsigned orig_height = 0; +static int crt_center_adjust = 0; + +static bool first_run = true; + +static float ra_tmp_core_hz = 0.0f; +static float fly_aspect = 0.0f; +static float ra_core_hz = 0.0f; +static unsigned crt_index = 0; + +static void crt_check_first_run(void) +{ + if (!first_run) + return; + + first_run = false; +} + +static void switch_crt_hz(void) +{ + if (ra_core_hz == ra_tmp_core_hz) + return; + /* set hz float to an int for windows switching */ + if (ra_core_hz < 100) + { + if (ra_core_hz < 53) + ra_set_core_hz = 50; + if (ra_core_hz >= 53 && ra_core_hz < 57) + ra_set_core_hz = 55; + if (ra_core_hz >= 57) + ra_set_core_hz = 60; + } + + if (ra_core_hz > 100) + { + if (ra_core_hz < 106) + ra_set_core_hz = 120; + if (ra_core_hz >= 106 && ra_core_hz < 114) + ra_set_core_hz = 110; + if (ra_core_hz >= 114) + ra_set_core_hz = 120; + } + + video_monitor_set_refresh_rate(ra_set_core_hz); + + ra_tmp_core_hz = ra_core_hz; +} + +void crt_aspect_ratio_switch(unsigned width, unsigned height) +{ + /* send aspect float to videeo_driver */ + fly_aspect = (float)width / height; + video_driver_set_aspect_ratio_value((float)fly_aspect); +} + +static void switch_res_crt(unsigned width, unsigned height) +{ + video_display_server_set_resolution(width, height, + ra_set_core_hz, ra_core_hz, crt_center_adjust, crt_index); + #if defined(__arm__) + crt_rpi_switch(width, height, ra_core_hz); + video_monitor_set_refresh_rate(ra_core_hz); + crt_switch_driver_reinit(); + #endif + video_driver_apply_state_changes(); +} + +/* Create correct aspect to fit video if resolution does not exist */ +static void crt_screen_setup_aspect(unsigned width, unsigned height) +{ + #if defined(__arm__) + if (height > 300) + height = height/2; + #endif + + switch_crt_hz(); + /* get original resolution of core */ + if (height == 4) + { + /* detect menu only */ + if (width < 1920) + width = 320; + + height = 240; + + crt_aspect_ratio_switch(width, height); + } + + if (height < 200 && height != 144) + { + crt_aspect_ratio_switch(width, height); + height = 200; + } + + if (height > 200) + crt_aspect_ratio_switch(width, height); + + if (height == 144 && ra_set_core_hz == 50) + { + height = 288; + crt_aspect_ratio_switch(width, height); + } + + if (height > 200 && height < 224) + { + crt_aspect_ratio_switch(width, height); + height = 224; + } + + if (height > 224 && height < 240) + { + crt_aspect_ratio_switch(width, height); + height = 240; + } + + if (height > 240 && height < 255) + { + crt_aspect_ratio_switch(width, height); + height = 254; + } + + if (height == 528 && ra_set_core_hz == 60) + { + crt_aspect_ratio_switch(width, height); + height = 480; + } + + if (height >= 240 && height < 255 && ra_set_core_hz == 55) + { + crt_aspect_ratio_switch(width, height); + height = 254; + } + + switch_res_crt(width, height); +} + +void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust) +{ + /* ra_core_hz float passed from within + * void video_driver_monitor_adjust_system_rates(void) */ + ra_core_width = width; + ra_core_height = height; + ra_core_hz = hz; + crt_center_adjust = crt_switch_center_adjust; + crt_index = monitor_index; + + if (crt_mode == 2) + { + if (hz > 53) + ra_core_hz = hz * 2; + + if (hz <= 53) + ra_core_hz = 120.0f; + } + + crt_check_first_run(); + + /* Detect resolution change and switch */ + if ( + (ra_tmp_height != ra_core_height) || + (ra_core_width != ra_tmp_width) + ) + crt_screen_setup_aspect(width, height); + + ra_tmp_height = ra_core_height; + ra_tmp_width = ra_core_width; + + /* Check if aspect is correct, if notchange */ + if (video_driver_get_aspect_ratio() != fly_aspect) + { + video_driver_set_aspect_ratio_value((float)fly_aspect); + video_driver_apply_state_changes(); + } +} + +void crt_video_restore(void) +{ + if (first_run) + return; + + first_run = true; +} + +#if defined(__arm__) +static void crt_rpi_switch(int width, int height, float hz) +{ + static char output[250] = {0}; + static char output1[250] = {0}; + static char output2[250] = {0}; + static char set_hdmi[250] ={0}; + static char set_hdmi_timing[250] = {0}; + int i = 0; + int hfp = 0; + int hsp = 0; + int hbp = 0; + int vfp = 0; + int vsp = 0; + int vbp = 0; + int hmax = 0; + int vmax = 0; + int pdefault = 8; + int pwidth = 0; + float roundw = 0.0f; + float roundh = 0.0f; + float pixel_clock = 0; + int ip_flag = 0; + + /* set core refresh from hz */ + video_monitor_set_refresh_rate(hz); + + /* following code is the mode line generator */ + + pwidth = width; + + if (height < 400 && width > 400) + pwidth = width / 2; + + roundw = roundf((float)pwidth / (float)height * 100) / 100; + + if (height > width) + roundw = roundf((float)height / (float)width * 100) / 100; + + if (roundw > 1.35) + roundw = 1.25; + + if (roundw < 1.20) + roundw = 1.34; + hfp = width * 0.065; + + hsp = width * 0.1433-hfp; + + hbp = width * 0.3-hsp-hfp; + + + if (height < 241) + vmax = 261; + if (height < 241 && hz > 56 && hz < 58) + vmax = 280; + if (height < 241 && hz < 55) + vmax = 313; + if (height > 250 && height < 260 && hz > 54) + vmax = 296; + if (height > 250 && height < 260 && hz > 52 && hz < 54) + vmax = 285; + if (height > 250 && height < 260 && hz < 52) + vmax = 313; + if (height > 260 && height < 300) + vmax = 318; + + if (height > 400 && hz > 56) + vmax = 533; + if (height > 520 && hz < 57) + vmax = 580; + + if (height > 300 && hz < 56) + vmax = 615; + if (height > 500 && hz < 56) + vmax = 624; + if (height > 300) + pdefault = pdefault * 2; + + vfp = (height + ((vmax - height) / 2) - pdefault) - height; + + if (height < 300) + vsp = vfp + 3; /* needs to be 3 for progressive */ + if (height > 300) + vsp = vfp + 6; /* needs to be 6 for interlaced */ + + vsp = 3; + + vbp = (vmax-height)-vsp-vfp; + + hmax = width+hfp+hsp+hbp; + + if (height < 300) + { + pixel_clock = (hmax * vmax * hz) ; + ip_flag = 0; + } + + if (height > 300) + { + pixel_clock = (hmax * vmax * (hz/2)) /2 ; + ip_flag = 1; + } + /* above code is the modeline generator */ + + snprintf(set_hdmi_timing, sizeof(set_hdmi_timings), "hdmi_timings %d 1 %d %d %d %d 1 %d %d %d 0 0 0 %f %d %f 1 ", width, hfp, hsp, hbp, height, vfp,vsp, vbp, hz, ip_flag, pixel_clock); + + VCHI_INSTANCE_T vchi_instance; + VCHI_CONNECTION_T *vchi_connection = NULL; + char buffer[1024]; + + vcos_init (); + + vchi_initialise (&vchi_instance); + + vchi_connect (NULL, 0, vchi_instance); + + vc_vchi_gencmd_init (vchi_instance, &vchi_connection, 1); + + + vc_gencmd (buffer, sizeof (buffer), set_hdmi_timing); + + vc_gencmd_stop (); + + vchi_disconnect (vchi_instance); + + snprintf(output1, sizeof(output1),"tvservice -e \"DMT 87\" > /dev/null"); + system(output1); + snprintf(output2, sizeof(output1),"fbset -g %d %d %d %d 24 > /dev/null",width, height, width, height); + system(output2); +} +#endif + diff --git a/gfx/video_crt_switch.h b/gfx/video_crt_switch.h index 98cfd4150b..df388ec2ce 100644 --- a/gfx/video_crt_switch.h +++ b/gfx/video_crt_switch.h @@ -1,38 +1,38 @@ -/* CRT SwitchRes Core - * Copyright (C) 2018 Alphanu / Ben Templeman. - * - * RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __VIDEO_CRT_SWITCH_H__ -#define __VIDEO_CRT_SWITCH_H__ - -#include - -#include -#include - -RETRO_BEGIN_DECLS - -void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust); - -void crt_aspect_ratio_switch(unsigned width, unsigned height); - -void crt_video_restore(void); - -RETRO_END_DECLS - -#endif +/* CRT SwitchRes Core + * Copyright (C) 2018 Alphanu / Ben Templeman. + * + * RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __VIDEO_CRT_SWITCH_H__ +#define __VIDEO_CRT_SWITCH_H__ + +#include + +#include +#include + +RETRO_BEGIN_DECLS + +void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust, int monitor_index); + +void crt_aspect_ratio_switch(unsigned width, unsigned height); + +void crt_video_restore(void); + +RETRO_END_DECLS + +#endif diff --git a/gfx/video_display_server.c b/gfx/video_display_server.c index f5f4f917ea..9917de9ddd 100644 --- a/gfx/video_display_server.c +++ b/gfx/video_display_server.c @@ -1,112 +1,112 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2016-2017 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include "video_display_server.h" -#include "video_driver.h" -#include "../verbosity.h" - -static const video_display_server_t *current_display_server = &dispserv_null; -static void *current_display_server_data = NULL; - -const char *video_display_server_get_ident(void) -{ - if (!current_display_server) - return "null"; - return current_display_server->ident; -} - -void* video_display_server_init(void) -{ - enum rarch_display_type type = video_driver_display_type_get(); - - video_display_server_destroy(); - - switch (type) - { - case RARCH_DISPLAY_WIN32: -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) - current_display_server = &dispserv_win32; -#endif - break; - case RARCH_DISPLAY_X11: -#if defined(HAVE_X11) - current_display_server = &dispserv_x11; -#endif - break; - default: - current_display_server = &dispserv_null; - break; - } - - current_display_server_data = current_display_server->init(); - - RARCH_LOG("[Video]: Found display server: %s\n", - current_display_server->ident); - - return current_display_server_data; -} - -void video_display_server_destroy(void) -{ - if (current_display_server && current_display_server->destroy) - if (current_display_server_data) - current_display_server->destroy(current_display_server_data); -} - -bool video_display_server_set_window_opacity(unsigned opacity) -{ - if (current_display_server && current_display_server->set_window_opacity) - return current_display_server->set_window_opacity(current_display_server_data, opacity); - return false; -} - -bool video_display_server_set_window_progress(int progress, bool finished) -{ - if (current_display_server && current_display_server->set_window_progress) - return current_display_server->set_window_progress(current_display_server_data, progress, finished); - return false; -} - -bool video_display_server_set_window_decorations(bool on) -{ - if (current_display_server && current_display_server->set_window_decorations) - return current_display_server->set_window_decorations(current_display_server_data, on); - return false; -} - -bool video_display_server_set_resolution(unsigned width, unsigned height, - int int_hz, float hz, int center) -{ - if (current_display_server && current_display_server->set_resolution) - return current_display_server->set_resolution(current_display_server_data, width, height, int_hz, hz, center); - return false; -} - -void *video_display_server_get_resolution_list(unsigned *size) -{ - if (current_display_server && current_display_server->get_resolution_list) - return current_display_server->get_resolution_list(current_display_server_data, size); - return NULL; -} - -const char *video_display_server_get_output_options(void) -{ - if (current_display_server && current_display_server->get_output_options) - return current_display_server->get_output_options(current_display_server_data); - return NULL; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include "video_display_server.h" +#include "video_driver.h" +#include "../verbosity.h" + +static const video_display_server_t *current_display_server = &dispserv_null; +static void *current_display_server_data = NULL; + +const char *video_display_server_get_ident(void) +{ + if (!current_display_server) + return "null"; + return current_display_server->ident; +} + +void* video_display_server_init(void) +{ + enum rarch_display_type type = video_driver_display_type_get(); + + video_display_server_destroy(); + + switch (type) + { + case RARCH_DISPLAY_WIN32: +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) + current_display_server = &dispserv_win32; +#endif + break; + case RARCH_DISPLAY_X11: +#if defined(HAVE_X11) + current_display_server = &dispserv_x11; +#endif + break; + default: + current_display_server = &dispserv_null; + break; + } + + current_display_server_data = current_display_server->init(); + + RARCH_LOG("[Video]: Found display server: %s\n", + current_display_server->ident); + + return current_display_server_data; +} + +void video_display_server_destroy(void) +{ + if (current_display_server && current_display_server->destroy) + if (current_display_server_data) + current_display_server->destroy(current_display_server_data); +} + +bool video_display_server_set_window_opacity(unsigned opacity) +{ + if (current_display_server && current_display_server->set_window_opacity) + return current_display_server->set_window_opacity(current_display_server_data, opacity); + return false; +} + +bool video_display_server_set_window_progress(int progress, bool finished) +{ + if (current_display_server && current_display_server->set_window_progress) + return current_display_server->set_window_progress(current_display_server_data, progress, finished); + return false; +} + +bool video_display_server_set_window_decorations(bool on) +{ + if (current_display_server && current_display_server->set_window_decorations) + return current_display_server->set_window_decorations(current_display_server_data, on); + return false; +} + +bool video_display_server_set_resolution(unsigned width, unsigned height, + int int_hz, float hz, int center, int monitor_index) +{ + if (current_display_server && current_display_server->set_resolution) + return current_display_server->set_resolution(current_display_server_data, width, height, int_hz, hz, center, monitor_index); + return false; +} + +void *video_display_server_get_resolution_list(unsigned *size) +{ + if (current_display_server && current_display_server->get_resolution_list) + return current_display_server->get_resolution_list(current_display_server_data, size); + return NULL; +} + +const char *video_display_server_get_output_options(void) +{ + if (current_display_server && current_display_server->get_output_options) + return current_display_server->get_output_options(current_display_server_data); + return NULL; +} diff --git a/gfx/video_display_server.h b/gfx/video_display_server.h index 2824b4b4ee..d3c990ca85 100644 --- a/gfx/video_display_server.h +++ b/gfx/video_display_server.h @@ -1,77 +1,77 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2016-2017 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __VIDEO_DISPLAY_SERVER__H -#define __VIDEO_DISPLAY_SERVER__H - -#include -#include - -RETRO_BEGIN_DECLS - -typedef struct video_display_config -{ - unsigned width; - unsigned height; - unsigned bpp; - unsigned refreshrate; - unsigned idx; - bool current; -} video_display_config_t; - -typedef struct video_display_server -{ - void *(*init)(void); - void (*destroy)(void *data); - bool (*set_window_opacity)(void *data, unsigned opacity); - bool (*set_window_progress)(void *data, int progress, bool finished); - bool (*set_window_decorations)(void *data, bool on); - bool (*set_resolution)(void *data, unsigned width, - unsigned height, int int_hz, float hz, int center); - void *(*get_resolution_list)(void *data, - unsigned *size); - const char *(*get_output_options)(void *data); - const char *ident; -} video_display_server_t; - -void* video_display_server_init(void); - -void video_display_server_destroy(void); - -bool video_display_server_set_window_opacity(unsigned opacity); - -bool video_display_server_set_window_progress(int progress, bool finished); - -bool video_display_server_set_window_decorations(bool on); - -bool video_display_server_set_resolution( - unsigned width, unsigned height, - int int_hz, float hz, int center); - -void *video_display_server_get_resolution_list(unsigned *size); - -const char *video_display_server_get_output_options(void); - -const char *video_display_server_get_ident(void); - -extern const video_display_server_t dispserv_win32; -extern const video_display_server_t dispserv_x11; -extern const video_display_server_t dispserv_null; - -RETRO_END_DECLS - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __VIDEO_DISPLAY_SERVER__H +#define __VIDEO_DISPLAY_SERVER__H + +#include +#include + +RETRO_BEGIN_DECLS + +typedef struct video_display_config +{ + unsigned width; + unsigned height; + unsigned bpp; + unsigned refreshrate; + unsigned idx; + bool current; +} video_display_config_t; + +typedef struct video_display_server +{ + void *(*init)(void); + void (*destroy)(void *data); + bool (*set_window_opacity)(void *data, unsigned opacity); + bool (*set_window_progress)(void *data, int progress, bool finished); + bool (*set_window_decorations)(void *data, bool on); + bool (*set_resolution)(void *data, unsigned width, + unsigned height, int int_hz, float hz, int center, int monitor_index); + void *(*get_resolution_list)(void *data, + unsigned *size); + const char *(*get_output_options)(void *data); + const char *ident; +} video_display_server_t; + +void* video_display_server_init(void); + +void video_display_server_destroy(void); + +bool video_display_server_set_window_opacity(unsigned opacity); + +bool video_display_server_set_window_progress(int progress, bool finished); + +bool video_display_server_set_window_decorations(bool on); + +bool video_display_server_set_resolution( + unsigned width, unsigned height, + int int_hz, float hz, int center, int monitor_index); + +void *video_display_server_get_resolution_list(unsigned *size); + +const char *video_display_server_get_output_options(void); + +const char *video_display_server_get_ident(void); + +extern const video_display_server_t dispserv_win32; +extern const video_display_server_t dispserv_x11; +extern const video_display_server_t dispserv_null; + +RETRO_END_DECLS + +#endif diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 3e05c64d70..f3a9bb5096 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -1,3778 +1,3783 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../audio/audio_driver.h" -#include "../menu/menu_shader.h" - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#include "../dynamic.h" - -#ifdef HAVE_THREADS -#include -#endif - -#ifdef HAVE_MENU -#include "../menu/menu_driver.h" -#include "../menu/menu_setting.h" -#endif - -#include "video_thread_wrapper.h" -#include "video_driver.h" -#include "video_display_server.h" -#include "video_crt_switch.h" - -#include "../frontend/frontend_driver.h" -#include "../record/record_driver.h" -#include "../config.def.h" -#include "../configuration.h" -#include "../driver.h" -#include "../retroarch.h" -#include "../input/input_driver.h" -#include "../list_special.h" -#include "../core.h" -#include "../command.h" -#include "../msg_hash.h" -#include "../verbosity.h" - -#define MEASURE_FRAME_TIME_SAMPLES_COUNT (2 * 1024) - -#define TIME_TO_FPS(last_time, new_time, frames) ((1000000.0f * (frames)) / ((new_time) - (last_time))) - -#define FPS_UPDATE_INTERVAL 256 - -#ifdef HAVE_THREADS -#define video_driver_is_threaded_internal() ((!video_driver_is_hw_context() && video_driver_threaded) ? true : false) -#else -#define video_driver_is_threaded_internal() (false) -#endif - -#ifdef HAVE_THREADS -#define video_driver_lock() \ - if (display_lock) \ - slock_lock(display_lock) - -#define video_driver_unlock() \ - if (display_lock) \ - slock_unlock(display_lock) - -#define video_driver_context_lock() \ - if (context_lock) \ - slock_lock(context_lock) - -#define video_driver_context_unlock() \ - if (context_lock) \ - slock_unlock(context_lock) - -#define video_driver_lock_free() \ - slock_free(display_lock); \ - slock_free(context_lock); \ - display_lock = NULL; \ - context_lock = NULL - -#define video_driver_threaded_lock(is_threaded) \ - if (is_threaded) \ - video_driver_lock() - -#define video_driver_threaded_unlock(is_threaded) \ - if (is_threaded) \ - video_driver_unlock() -#else -#define video_driver_lock() ((void)0) -#define video_driver_unlock() ((void)0) -#define video_driver_lock_free() ((void)0) -#define video_driver_threaded_lock(is_threaded) ((void)0) -#define video_driver_threaded_unlock(is_threaded) ((void)0) -#define video_driver_context_lock() ((void)0) -#define video_driver_context_unlock() ((void)0) -#endif - -typedef struct video_pixel_scaler -{ - struct scaler_ctx *scaler; - void *scaler_out; -} video_pixel_scaler_t; - -static void (*video_driver_cb_shader_use)(void *data, - void *shader_data, unsigned index, bool set_active); -static bool (*video_driver_cb_shader_set_mvp)(void *data, - void *shader_data, const void *mat_data); -bool (*video_driver_cb_has_focus)(void); - -/* Opaque handles to currently running window. - * Used by e.g. input drivers which bind to a window. - * Drivers are responsible for setting these if an input driver - * could potentially make use of this. */ -static uintptr_t video_driver_display = 0; -static uintptr_t video_driver_window = 0; - -static rarch_softfilter_t *video_driver_state_filter = NULL; -static void *video_driver_state_buffer = NULL; -static unsigned video_driver_state_scale = 0; -static unsigned video_driver_state_out_bpp = 0; -static bool video_driver_state_out_rgb32 = false; -static bool video_driver_crt_switching_active = false; - -static struct retro_system_av_info video_driver_av_info; - -static enum retro_pixel_format video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555; - -static const void *frame_cache_data = NULL; -static unsigned frame_cache_width = 0; -static unsigned frame_cache_height = 0; -static size_t frame_cache_pitch = 0; -static bool video_driver_threaded = false; - -static float video_driver_core_hz = 0.0f; -static float video_driver_aspect_ratio = 0.0f; -static unsigned video_driver_width = 0; -static unsigned video_driver_height = 0; - -static enum rarch_display_type video_driver_display_type = RARCH_DISPLAY_NONE; -static char video_driver_title_buf[64] = {0}; -static char video_driver_window_title[512] = {0}; -static bool video_driver_window_title_update = true; - -static retro_time_t video_driver_frame_time_samples[MEASURE_FRAME_TIME_SAMPLES_COUNT]; -static uint64_t video_driver_frame_time_count = 0; -static uint64_t video_driver_frame_count = 0; - -static void *video_driver_data = NULL; -static video_driver_t *current_video = NULL; - -/* Interface for "poking". */ -static const video_poke_interface_t *video_driver_poke = NULL; - -/* Used for 15-bit -> 16-bit conversions that take place before - * being passed to video driver. */ -static video_pixel_scaler_t *video_driver_scaler_ptr = NULL; - -static struct retro_hw_render_callback hw_render; - -static const struct -retro_hw_render_context_negotiation_interface * -hw_render_context_negotiation = NULL; - -/* Graphics driver requires RGBA byte order data (ABGR on little-endian) - * for 32-bit. - * This takes effect for overlay and shader cores that wants to load - * data into graphics driver. Kinda hackish to place it here, it is only - * used for GLES. - * TODO: Refactor this better. */ -static bool video_driver_use_rgba = false; -static bool video_driver_data_own = false; -static bool video_driver_active = false; - -static video_driver_frame_t frame_bak = NULL; - -/* If set during context deinit, the driver should keep - * graphics context alive to avoid having to reset all - * context state. */ -static bool video_driver_cache_context = false; - -/* Set to true by driver if context caching succeeded. */ -static bool video_driver_cache_context_ack = false; -static uint8_t *video_driver_record_gpu_buffer = NULL; - -#ifdef HAVE_THREADS -static slock_t *display_lock = NULL; -static slock_t *context_lock = NULL; -#endif - -static gfx_ctx_driver_t current_video_context; - -static void *video_context_data = NULL; - -/** - * dynamic.c:dynamic_request_hw_context will try to set flag data when the context - * is in the middle of being rebuilt; in these cases we will save flag - * data and set this to true. - * When the context is reinit, it checks this, reads from - * deferred_flag_data and cleans it. - * - * TODO - Dirty hack, fix it better - */ -static bool deferred_video_context_driver_set_flags = false; -static gfx_ctx_flags_t deferred_flag_data = {0}; - -static bool video_started_fullscreen = false; - -static shader_backend_t *current_shader = NULL; -static void *current_shader_data = NULL; - -struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { - { "4:3", 1.3333f }, - { "16:9", 1.7778f }, - { "16:10", 1.6f }, - { "16:15", 16.0f / 15.0f }, - { "21:9", 21.0f / 9.0f }, - { "1:1", 1.0f }, - { "2:1", 2.0f }, - { "3:2", 1.5f }, - { "3:4", 0.75f }, - { "4:1", 4.0f }, - { "9:16", 0.5625f }, - { "5:4", 1.25f }, - { "6:5", 1.2f }, - { "7:9", 0.7777f }, - { "8:3", 2.6666f }, - { "8:7", 1.1428f }, - { "19:12", 1.5833f }, - { "19:14", 1.3571f }, - { "30:17", 1.7647f }, - { "32:9", 3.5555f }, - { "Config", 0.0f }, - { "Square pixel", 1.0f }, - { "Core provided", 1.0f }, - { "Custom", 0.0f } -}; - -static const video_driver_t *video_drivers[] = { -#ifdef HAVE_OPENGL - &video_gl, -#endif -#ifdef HAVE_VULKAN - &video_vulkan, -#endif -#ifdef HAVE_METAL - &video_metal, -#endif -#ifdef XENON - &video_xenon360, -#endif -#if defined(HAVE_D3D12) - &video_d3d12, -#endif -#if defined(HAVE_D3D11) - &video_d3d11, -#endif -#if defined(HAVE_D3D10) - &video_d3d10, -#endif -#if defined(HAVE_D3D9) - &video_d3d9, -#endif -#if defined(HAVE_D3D8) - &video_d3d8, -#endif -#ifdef HAVE_VITA2D - &video_vita2d, -#endif -#ifdef PSP - &video_psp1, -#endif -#ifdef PS2 - &video_ps2, -#endif -#ifdef _3DS - &video_ctr, -#endif -#ifdef SWITCH - &video_switch, -#endif -#ifdef HAVE_SDL - &video_sdl, -#endif -#ifdef HAVE_SDL2 - &video_sdl2, -#endif -#ifdef HAVE_XVIDEO - &video_xvideo, -#endif -#ifdef GEKKO - &video_gx, -#endif -#ifdef WIIU - &video_wiiu, -#endif -#ifdef HAVE_VG - &video_vg, -#endif -#ifdef HAVE_OMAP - &video_omap, -#endif -#ifdef HAVE_EXYNOS - &video_exynos, -#endif -#ifdef HAVE_DISPMANX - &video_dispmanx, -#endif -#ifdef HAVE_SUNXI - &video_sunxi, -#endif -#ifdef HAVE_PLAIN_DRM - &video_drm, -#endif -#ifdef HAVE_XSHM - &video_xshm, -#endif -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) - &video_gdi, -#endif -#ifdef DJGPP - &video_vga, -#endif -#ifdef HAVE_SIXEL - &video_sixel, -#endif -#ifdef HAVE_CACA - &video_caca, -#endif - &video_null, - NULL, -}; - -static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { -#if defined(ORBIS) - &orbis_ctx, -#endif -#if defined(HAVE_LIBNX) && defined(HAVE_OPENGL) - &switch_ctx, -#endif -#if defined(__CELLOS_LV2__) - &gfx_ctx_ps3, -#endif -#if defined(HAVE_VIDEOCORE) - &gfx_ctx_videocore, -#endif -#if defined(HAVE_MALI_FBDEV) - &gfx_ctx_mali_fbdev, -#endif -#if defined(HAVE_VIVANTE_FBDEV) - &gfx_ctx_vivante_fbdev, -#endif -#if defined(HAVE_OPENDINGUX_FBDEV) - &gfx_ctx_opendingux_fbdev, -#endif -#if defined(_WIN32) && (defined(HAVE_OPENGL) || defined(HAVE_VULKAN)) - &gfx_ctx_wgl, -#endif -#if defined(HAVE_WAYLAND) - &gfx_ctx_wayland, -#endif -#if defined(HAVE_X11) && !defined(HAVE_OPENGLES) -#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) - &gfx_ctx_x, -#endif -#endif -#if defined(HAVE_X11) && defined(HAVE_OPENGL) && defined(HAVE_EGL) - &gfx_ctx_x_egl, -#endif -#if defined(HAVE_KMS) - &gfx_ctx_drm, -#endif -#if defined(ANDROID) - &gfx_ctx_android, -#endif -#if defined(__QNX__) - &gfx_ctx_qnx, -#endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) - &gfx_ctx_cocoagl, -#endif -#if defined(__APPLE__) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE) - &gfx_ctx_cgl, -#endif -#if (defined(HAVE_SDL) || defined(HAVE_SDL2)) && defined(HAVE_OPENGL) - &gfx_ctx_sdl_gl, -#endif -#ifdef HAVE_OSMESA - &gfx_ctx_osmesa, -#endif -#ifdef EMSCRIPTEN - &gfx_ctx_emscripten, -#endif -#if defined(HAVE_VULKAN) && defined(HAVE_VULKAN_DISPLAY) - &gfx_ctx_khr_display, -#endif -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) - &gfx_ctx_gdi, -#endif -#ifdef HAVE_SIXEL - &gfx_ctx_sixel, -#endif - &gfx_ctx_null, - NULL -}; - -static const shader_backend_t *shader_ctx_drivers[] = { -#ifdef HAVE_GLSL - &gl_glsl_backend, -#endif -#ifdef HAVE_CG - &gl_cg_backend, -#endif - &shader_null_backend, - NULL -}; - -bool video_driver_started_fullscreen(void) -{ - return video_started_fullscreen; -} - -/* Stub functions */ - -static void update_window_title_null(void *data, void *data2) -{ -} - -static void swap_buffers_null(void *data, void *data2) -{ -} - -static bool get_metrics_null(void *data, enum display_metric_types type, - float *value) -{ - return false; -} - -static bool set_resize_null(void *a, unsigned b, unsigned c) -{ - return false; -} - -/** - * video_driver_find_handle: - * @idx : index of driver to get handle to. - * - * Returns: handle to video driver at index. Can be NULL - * if nothing found. - **/ -const void *video_driver_find_handle(int idx) -{ - const void *drv = video_drivers[idx]; - if (!drv) - return NULL; - return drv; -} - -/** - * video_driver_find_ident: - * @idx : index of driver to get handle to. - * - * Returns: Human-readable identifier of video driver at index. Can be NULL - * if nothing found. - **/ -const char *video_driver_find_ident(int idx) -{ - const video_driver_t *drv = video_drivers[idx]; - if (!drv) - return NULL; - return drv->ident; -} - -/** - * config_get_video_driver_options: - * - * Get an enumerated list of all video driver names, separated by '|'. - * - * Returns: string listing of all video driver names, separated by '|'. - **/ -const char* config_get_video_driver_options(void) -{ - return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL); -} - -bool video_driver_is_threaded(void) -{ - return video_driver_is_threaded_internal(); -} - -#ifdef HAVE_VULKAN -static bool hw_render_context_is_vulkan(enum retro_hw_context_type type) -{ - return type == RETRO_HW_CONTEXT_VULKAN; -} -#endif - -#if defined(HAVE_OPENGL) -static bool hw_render_context_is_gl(enum retro_hw_context_type type) -{ - switch (type) - { - case RETRO_HW_CONTEXT_OPENGL: - case RETRO_HW_CONTEXT_OPENGLES2: - case RETRO_HW_CONTEXT_OPENGL_CORE: - case RETRO_HW_CONTEXT_OPENGLES3: - case RETRO_HW_CONTEXT_OPENGLES_VERSION: - return true; - default: - break; - } - - return false; -} -#endif - -bool *video_driver_get_threaded(void) -{ - return &video_driver_threaded; -} - -void video_driver_set_threaded(bool val) -{ - video_driver_threaded = val; -} - -/** - * video_driver_get_ptr: - * - * Use this if you need the real video driver - * and driver data pointers. - * - * Returns: video driver's userdata. - **/ -void *video_driver_get_ptr(bool force_nonthreaded_data) -{ -#ifdef HAVE_THREADS - if (video_driver_is_threaded_internal() && !force_nonthreaded_data) - return video_thread_get_ptr(NULL); -#endif - - return video_driver_data; -} - -const char *video_driver_get_ident(void) -{ - return (current_video) ? current_video->ident : NULL; -} - -const video_poke_interface_t *video_driver_get_poke(void) -{ - return video_driver_poke; -} - -static bool video_context_has_focus(void) -{ - return current_video_context.has_focus && current_video_context.has_focus(video_context_data); -} - -static bool video_driver_has_focus(void) -{ - return current_video && current_video->focus && current_video->focus(video_driver_data); -} - -static bool null_driver_has_focus(void) -{ - return true; -} - -static void video_context_driver_reset(void) -{ - if (!current_video_context.get_metrics) - current_video_context.get_metrics = get_metrics_null; - - if (!current_video_context.update_window_title) - current_video_context.update_window_title = update_window_title_null; - - if (!current_video_context.set_resize) - current_video_context.set_resize = set_resize_null; - - if (!current_video_context.swap_buffers) - current_video_context.swap_buffers = swap_buffers_null; - - if (current_video_context.has_focus) - video_driver_cb_has_focus = video_context_has_focus; - -} - -bool video_context_driver_set(const gfx_ctx_driver_t *data) -{ - if (!data) - return false; - current_video_context = *data; - video_context_driver_reset(); - return true; -} - -void video_context_driver_destroy(void) -{ - current_video_context.init = NULL; - current_video_context.bind_api = NULL; - current_video_context.swap_interval = NULL; - current_video_context.set_video_mode = NULL; - current_video_context.get_video_size = NULL; - current_video_context.get_video_output_size = NULL; - current_video_context.get_video_output_prev = NULL; - current_video_context.get_video_output_next = NULL; - current_video_context.get_metrics = get_metrics_null; - current_video_context.translate_aspect = NULL; - current_video_context.update_window_title = update_window_title_null; - current_video_context.check_window = NULL; - current_video_context.set_resize = set_resize_null; - current_video_context.has_focus = NULL; - current_video_context.suppress_screensaver = NULL; - current_video_context.has_windowed = NULL; - current_video_context.swap_buffers = swap_buffers_null; - current_video_context.input_driver = NULL; - current_video_context.get_proc_address = NULL; - current_video_context.image_buffer_init = NULL; - current_video_context.image_buffer_write = NULL; - current_video_context.show_mouse = NULL; - current_video_context.ident = NULL; - current_video_context.get_flags = NULL; - current_video_context.set_flags = NULL; - current_video_context.bind_hw_render = NULL; - current_video_context.get_context_data = NULL; - current_video_context.make_current = NULL; -} - -/** - * video_driver_get_current_framebuffer: - * - * Gets pointer to current hardware renderer framebuffer object. - * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. - * - * Returns: pointer to hardware framebuffer object, otherwise 0. - **/ -uintptr_t video_driver_get_current_framebuffer(void) -{ - if (video_driver_poke && video_driver_poke->get_current_framebuffer) - return video_driver_poke->get_current_framebuffer(video_driver_data); - return 0; -} - -retro_proc_address_t video_driver_get_proc_address(const char *sym) -{ - if (video_driver_poke && video_driver_poke->get_proc_address) - return video_driver_poke->get_proc_address(video_driver_data, sym); - return NULL; -} - -bool video_driver_set_shader(enum rarch_shader_type type, - const char *path) -{ - if (current_video->set_shader) - return current_video->set_shader(video_driver_data, type, path); - return false; -} - -static void video_driver_filter_free(void) -{ - if (video_driver_state_filter) - rarch_softfilter_free(video_driver_state_filter); - video_driver_state_filter = NULL; - - if (video_driver_state_buffer) - { -#ifdef _3DS - linearFree(video_driver_state_buffer); -#else - free(video_driver_state_buffer); -#endif - } - video_driver_state_buffer = NULL; - - video_driver_state_scale = 0; - video_driver_state_out_bpp = 0; - video_driver_state_out_rgb32 = false; -} - -static void video_driver_init_filter(enum retro_pixel_format colfmt_int) -{ - unsigned pow2_x, pow2_y, maxsize; - void *buf = NULL; - settings_t *settings = config_get_ptr(); - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - unsigned width = geom->max_width; - unsigned height = geom->max_height; - /* Deprecated format. Gets pre-converted. */ - enum retro_pixel_format colfmt = - (colfmt_int == RETRO_PIXEL_FORMAT_0RGB1555) ? - RETRO_PIXEL_FORMAT_RGB565 : colfmt_int; - - if (video_driver_is_hw_context()) - { - RARCH_WARN("Cannot use CPU filters when hardware rendering is used.\n"); - return; - } - - video_driver_state_filter = rarch_softfilter_new( - settings->paths.path_softfilter_plugin, - RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height); - - if (!video_driver_state_filter) - { - RARCH_ERR("[Video]: Failed to load filter.\n"); - return; - } - - rarch_softfilter_get_max_output_size(video_driver_state_filter, - &width, &height); - - pow2_x = next_pow2(width); - pow2_y = next_pow2(height); - maxsize = MAX(pow2_x, pow2_y); - video_driver_state_scale = maxsize / RARCH_SCALE_BASE; - video_driver_state_out_rgb32 = rarch_softfilter_get_output_format( - video_driver_state_filter) == - RETRO_PIXEL_FORMAT_XRGB8888; - - video_driver_state_out_bpp = video_driver_state_out_rgb32 ? - sizeof(uint32_t) : - sizeof(uint16_t); - - /* TODO: Aligned output. */ -#ifdef _3DS - buf = linearMemAlign( - width * height * video_driver_state_out_bpp, 0x80); -#else - buf = malloc( - width * height * video_driver_state_out_bpp); -#endif - if (!buf) - { - RARCH_ERR("[Video]: Softfilter initialization failed.\n"); - video_driver_filter_free(); - return; - } - - video_driver_state_buffer = buf; -} - -static void video_driver_init_input(const input_driver_t *tmp) -{ - const input_driver_t **input = input_get_double_ptr(); - if (*input) - return; - - /* Video driver didn't provide an input driver, - * so we use configured one. */ - RARCH_LOG("[Video]: Graphics driver did not initialize an input driver." - " Attempting to pick a suitable driver.\n"); - - if (tmp) - *input = tmp; - else - input_driver_find_driver(); - - /* This should never really happen as tmp (driver.input) is always - * found before this in find_driver_input(), or we have aborted - * in a similar fashion anyways. */ - if (!input_get_ptr()) - goto error; - - if (input_driver_init()) - return; - -error: - RARCH_ERR("[Video]: Cannot initialize input driver. Exiting ...\n"); - retroarch_fail(1, "video_driver_init_input()"); -} - -/** - * video_driver_monitor_compute_fps_statistics: - * - * Computes monitor FPS statistics. - **/ -static void video_driver_monitor_compute_fps_statistics(void) -{ - double avg_fps = 0.0; - double stddev = 0.0; - unsigned samples = 0; - - if (video_driver_frame_time_count < - (2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)) - { - RARCH_LOG( - "[Video]: Does not have enough samples for monitor refresh rate" - " estimation. Requires to run for at least %u frames.\n", - 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT); - return; - } - - if (video_monitor_fps_statistics(&avg_fps, &stddev, &samples)) - { - RARCH_LOG("[Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time" - " deviation, based on %u last samples).\n", - avg_fps, 100.0 * stddev, samples); - } -} - -static void video_driver_pixel_converter_free(void) -{ - if (!video_driver_scaler_ptr) - return; - - scaler_ctx_gen_reset(video_driver_scaler_ptr->scaler); - - if (video_driver_scaler_ptr->scaler) - free(video_driver_scaler_ptr->scaler); - video_driver_scaler_ptr->scaler = NULL; - - if (video_driver_scaler_ptr->scaler_out) - free(video_driver_scaler_ptr->scaler_out); - video_driver_scaler_ptr->scaler_out = NULL; - - if (video_driver_scaler_ptr) - free(video_driver_scaler_ptr); - video_driver_scaler_ptr = NULL; -} - -static void video_driver_free_internal(void) -{ -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); -#endif - - command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); - - if (!video_driver_is_video_cache_context()) - video_driver_free_hw_context(); - - if ( - !input_driver_owns_driver() && - !input_driver_is_data_ptr_same(video_driver_data) - ) - input_driver_deinit(); - - if ( - !video_driver_data_own - && video_driver_data - && current_video && current_video->free - ) - current_video->free(video_driver_data); - - video_driver_pixel_converter_free(); - video_driver_filter_free(); - - command_event(CMD_EVENT_SHADER_DIR_DEINIT, NULL); - -#ifdef HAVE_THREADS - if (is_threaded) - return; -#endif - - video_driver_monitor_compute_fps_statistics(); -} - -static bool video_driver_pixel_converter_init(unsigned size) -{ - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); - void *scalr_out = NULL; - video_pixel_scaler_t *scalr = NULL; - struct scaler_ctx *scalr_ctx = NULL; - - /* If pixel format is not 0RGB1555, we don't need to do - * any internal pixel conversion. */ - if (video_driver_pix_fmt != RETRO_PIXEL_FORMAT_0RGB1555) - return true; - - /* No need to perform pixel conversion for HW rendering contexts. */ - if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) - return true; - - RARCH_WARN("0RGB1555 pixel format is deprecated," - " and will be slower. For 15/16-bit, RGB565" - " format is preferred.\n"); - - scalr = (video_pixel_scaler_t*)calloc(1, sizeof(*scalr)); - - if (!scalr) - goto error; - - video_driver_scaler_ptr = scalr; - - scalr_ctx = (struct scaler_ctx*)calloc(1, sizeof(*scalr_ctx)); - - if (!scalr_ctx) - goto error; - - video_driver_scaler_ptr->scaler = scalr_ctx; - video_driver_scaler_ptr->scaler->scaler_type = SCALER_TYPE_POINT; - video_driver_scaler_ptr->scaler->in_fmt = SCALER_FMT_0RGB1555; - - /* TODO: Pick either ARGB8888 or RGB565 depending on driver. */ - video_driver_scaler_ptr->scaler->out_fmt = SCALER_FMT_RGB565; - - if (!scaler_ctx_gen_filter(scalr_ctx)) - goto error; - - scalr_out = calloc(sizeof(uint16_t), size * size); - - if (!scalr_out) - goto error; - - video_driver_scaler_ptr->scaler_out = scalr_out; - - return true; - -error: - video_driver_pixel_converter_free(); - video_driver_filter_free(); - - return false; -} - -static bool video_driver_init_internal(bool *video_is_threaded) -{ - video_info_t video; - unsigned max_dim, scale, width, height; - video_viewport_t *custom_vp = NULL; - const input_driver_t *tmp = NULL; - rarch_system_info_t *system = NULL; - static uint16_t dummy_pixels[32] = {0}; - settings_t *settings = config_get_ptr(); - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - - if (!string_is_empty(settings->paths.path_softfilter_plugin)) - video_driver_init_filter(video_driver_pix_fmt); - - max_dim = MAX(geom->max_width, geom->max_height); - scale = next_pow2(max_dim) / RARCH_SCALE_BASE; - scale = MAX(scale, 1); - - if (video_driver_state_filter) - scale = video_driver_state_scale; - - /* Update core-dependent aspect ratio values. */ - video_driver_set_viewport_square_pixel(); - video_driver_set_viewport_core(); - video_driver_set_viewport_config(); - - /* Update CUSTOM viewport. */ - custom_vp = video_viewport_get_custom(); - - if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) - { - float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; - aspectratio_lut[ASPECT_RATIO_CUSTOM].value = - (custom_vp->width && custom_vp->height) ? - (float)custom_vp->width / custom_vp->height : default_aspect; - } - - video_driver_set_aspect_ratio_value( - aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); - - if (settings->bools.video_fullscreen|| retroarch_is_forced_fullscreen()) - { - width = settings->uints.video_fullscreen_x; - height = settings->uints.video_fullscreen_y; - } - else - { - /* To-Do: remove when the new window resizing core is hooked */ - if (settings->bools.video_window_save_positions && - (settings->uints.window_position_width || settings->uints.window_position_height)) - { - width = settings->uints.window_position_width; - height = settings->uints.window_position_height; - } - else - { - if (settings->bools.video_force_aspect) - { - /* Do rounding here to simplify integer scale correctness. */ - unsigned base_width = - roundf(geom->base_height * video_driver_get_aspect_ratio()); - width = roundf(base_width * settings->floats.video_scale); - } - else - width = roundf(geom->base_width * settings->floats.video_scale); - height = roundf(geom->base_height * settings->floats.video_scale); -} - } - - if (width && height) - RARCH_LOG("[Video]: Video @ %ux%u\n", width, height); - else - RARCH_LOG("[Video]: Video @ fullscreen\n"); - - video_driver_display_type_set(RARCH_DISPLAY_NONE); - video_driver_display_set(0); - video_driver_window_set(0); - - if (!video_driver_pixel_converter_init(RARCH_SCALE_BASE * scale)) - { - RARCH_ERR("[Video]: Failed to initialize pixel converter.\n"); - goto error; - } - - video.width = width; - video.height = height; - video.fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); - video.vsync = settings->bools.video_vsync && !rarch_ctl(RARCH_CTL_IS_NONBLOCK_FORCED, NULL); - video.force_aspect = settings->bools.video_force_aspect; - video.font_enable = settings->bools.video_font_enable; - video.swap_interval = settings->uints.video_swap_interval; -#ifdef GEKKO - video.viwidth = settings->uints.video_viwidth; - video.vfilter = settings->bools.video_vfilter; -#endif - video.smooth = settings->bools.video_smooth; - video.input_scale = scale; - video.rgb32 = video_driver_state_filter ? - video_driver_state_out_rgb32 : - (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); - video.parent = 0; - - video_started_fullscreen = video.fullscreen; - - /* Reset video frame count */ - video_driver_frame_count = 0; - - tmp = input_get_ptr(); - /* Need to grab the "real" video driver interface on a reinit. */ - video_driver_find_driver(); - -#ifdef HAVE_THREADS - video.is_threaded = video_driver_is_threaded_internal(); - *video_is_threaded = video.is_threaded; - - if (video.is_threaded) - { - /* Can't do hardware rendering with threaded driver currently. */ - RARCH_LOG("[Video]: Starting threaded video driver ...\n"); - - if (!video_init_thread((const video_driver_t**)¤t_video, - &video_driver_data, - input_get_double_ptr(), input_driver_get_data_ptr(), - current_video, video)) - { - RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n"); - goto error; - } - } - else -#endif - video_driver_data = current_video->init( - &video, input_get_double_ptr(), - input_driver_get_data_ptr()); - - if (!video_driver_data) - { - RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n"); - goto error; - } - - if (current_video->focus) - video_driver_cb_has_focus = video_driver_has_focus; - - video_driver_poke = NULL; - if (current_video->poke_interface) - current_video->poke_interface(video_driver_data, &video_driver_poke); - - if (current_video->viewport_info && - (!custom_vp->width || - !custom_vp->height)) - { - /* Force custom viewport to have sane parameters. */ - custom_vp->width = width; - custom_vp->height = height; - - video_driver_get_viewport_info(custom_vp); - } - - system = runloop_get_system_info(); - - video_driver_set_rotation( - (settings->uints.video_rotation + system->rotation) % 4); - - current_video->suppress_screensaver(video_driver_data, - settings->bools.ui_suspend_screensaver_enable); - - video_driver_init_input(tmp); - - command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); - command_event(CMD_EVENT_OVERLAY_INIT, NULL); - - if (!core_is_game_loaded()) - video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8); - -#if defined(PSP) - video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f); -#endif - - video_context_driver_reset(); - - video_display_server_init(); - - command_event(CMD_EVENT_SHADER_DIR_INIT, NULL); - - return true; - -error: - retroarch_fail(1, "init_video()"); - return false; -} - -bool video_driver_set_viewport(unsigned width, unsigned height, - bool force_fullscreen, bool allow_rotate) -{ - if (!current_video || !current_video->set_viewport) - return false; - current_video->set_viewport(video_driver_data, width, height, - force_fullscreen, allow_rotate); - return true; -} - -bool video_driver_set_rotation(unsigned rotation) -{ - if (!current_video || !current_video->set_rotation) - return false; - current_video->set_rotation(video_driver_data, rotation); - return true; -} - -bool video_driver_set_video_mode(unsigned width, - unsigned height, bool fullscreen) -{ - gfx_ctx_mode_t mode; - - if (video_driver_poke && video_driver_poke->set_video_mode) - { - video_driver_poke->set_video_mode(video_driver_data, - width, height, fullscreen); - return true; - } - - mode.width = width; - mode.height = height; - mode.fullscreen = fullscreen; - - return video_context_driver_set_video_mode(&mode); -} - -bool video_driver_get_video_output_size(unsigned *width, unsigned *height) -{ - if (!video_driver_poke || !video_driver_poke->get_video_output_size) - return false; - video_driver_poke->get_video_output_size(video_driver_data, - width, height); - return true; -} - -void video_driver_set_osd_msg(const char *msg, const void *data, void *font) -{ - video_frame_info_t video_info; - video_driver_build_info(&video_info); - if (video_driver_poke && video_driver_poke->set_osd_msg) - video_driver_poke->set_osd_msg(video_driver_data, &video_info, msg, data, font); -} - -void video_driver_set_texture_enable(bool enable, bool fullscreen) -{ - if (video_driver_poke && video_driver_poke->set_texture_enable) - video_driver_poke->set_texture_enable(video_driver_data, - enable, fullscreen); -} - -void video_driver_set_texture_frame(const void *frame, bool rgb32, - unsigned width, unsigned height, float alpha) -{ - if (video_driver_poke && video_driver_poke->set_texture_frame) - video_driver_poke->set_texture_frame(video_driver_data, - frame, rgb32, width, height, alpha); -} - -#ifdef HAVE_OVERLAY -bool video_driver_overlay_interface(const video_overlay_interface_t **iface) -{ - if (!current_video || !current_video->overlay_interface) - return false; - current_video->overlay_interface(video_driver_data, iface); - return true; -} -#endif - -void *video_driver_read_frame_raw(unsigned *width, - unsigned *height, size_t *pitch) -{ - if (!current_video || !current_video->read_frame_raw) - return NULL; - return current_video->read_frame_raw(video_driver_data, width, - height, pitch); -} - -void video_driver_set_filtering(unsigned index, bool smooth) -{ - if (video_driver_poke && video_driver_poke->set_filtering) - video_driver_poke->set_filtering(video_driver_data, index, smooth); -} - -void video_driver_cached_frame_set(const void *data, unsigned width, - unsigned height, size_t pitch) -{ - if (data) - frame_cache_data = data; - frame_cache_width = width; - frame_cache_height = height; - frame_cache_pitch = pitch; -} - -void video_driver_cached_frame_get(const void **data, unsigned *width, - unsigned *height, size_t *pitch) -{ - if (data) - *data = frame_cache_data; - if (width) - *width = frame_cache_width; - if (height) - *height = frame_cache_height; - if (pitch) - *pitch = frame_cache_pitch; -} - -void video_driver_get_size(unsigned *width, unsigned *height) -{ -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); - video_driver_threaded_lock(is_threaded); -#endif - if (width) - *width = video_driver_width; - if (height) - *height = video_driver_height; -#ifdef HAVE_THREADS - video_driver_threaded_unlock(is_threaded); -#endif -} - -void video_driver_set_size(unsigned *width, unsigned *height) -{ -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); - video_driver_threaded_lock(is_threaded); -#endif - if (width) - video_driver_width = *width; - if (height) - video_driver_height = *height; -#ifdef HAVE_THREADS - video_driver_threaded_unlock(is_threaded); -#endif -} - -/** - * video_monitor_set_refresh_rate: - * @hz : New refresh rate for monitor. - * - * Sets monitor refresh rate to new value. - **/ -void video_monitor_set_refresh_rate(float hz) -{ - char msg[128]; - settings_t *settings = config_get_ptr(); - - snprintf(msg, sizeof(msg), - "Setting refresh rate to: %.3f Hz.", hz); - runloop_msg_queue_push(msg, 1, 180, false); - RARCH_LOG("%s\n", msg); - - configuration_set_float(settings, - settings->floats.video_refresh_rate, - hz); -} - -/** - * video_monitor_fps_statistics - * @refresh_rate : Monitor refresh rate. - * @deviation : Deviation from measured refresh rate. - * @sample_points : Amount of sampled points. - * - * Gets the monitor FPS statistics based on the current - * runtime. - * - * Returns: true (1) on success. - * false (0) if: - * a) threaded video mode is enabled - * b) less than 2 frame time samples. - * c) FPS monitor enable is off. - **/ -bool video_monitor_fps_statistics(double *refresh_rate, - double *deviation, unsigned *sample_points) -{ - unsigned i; - retro_time_t accum = 0; - retro_time_t avg = 0; - retro_time_t accum_var = 0; - unsigned samples = 0; - -#ifdef HAVE_THREADS - if (video_driver_is_threaded_internal()) - return false; -#endif - - samples = MIN(MEASURE_FRAME_TIME_SAMPLES_COUNT, - (unsigned)video_driver_frame_time_count); - - if (samples < 2) - return false; - - /* Measure statistics on frame time (microsecs), *not* FPS. */ - for (i = 0; i < samples; i++) - { - accum += video_driver_frame_time_samples[i]; -#if 0 - RARCH_LOG("[Video]: Interval #%u: %d usec / frame.\n", - i, (int)frame_time_samples[i]); -#endif - } - - avg = accum / samples; - - /* Drop first measurement. It is likely to be bad. */ - for (i = 0; i < samples; i++) - { - retro_time_t diff = video_driver_frame_time_samples[i] - avg; - accum_var += diff * diff; - } - - *deviation = sqrt((double)accum_var / (samples - 1)) / avg; - - if (refresh_rate) - *refresh_rate = 1000000.0 / avg; - - if (sample_points) - *sample_points = samples; - - return true; -} - -float video_driver_get_aspect_ratio(void) -{ - return video_driver_aspect_ratio; -} - -void video_driver_set_aspect_ratio_value(float value) -{ - video_driver_aspect_ratio = value; -} - -static bool video_driver_frame_filter( - const void *data, - video_frame_info_t *video_info, - unsigned width, unsigned height, - size_t pitch, - unsigned *output_width, unsigned *output_height, - unsigned *output_pitch) -{ - rarch_softfilter_get_output_size(video_driver_state_filter, - output_width, output_height, width, height); - - *output_pitch = (*output_width) * video_driver_state_out_bpp; - - rarch_softfilter_process(video_driver_state_filter, - video_driver_state_buffer, *output_pitch, - data, width, height, pitch); - - if (video_info->post_filter_record && recording_data) - recording_dump_frame(video_driver_state_buffer, - *output_width, *output_height, *output_pitch, - video_info->runloop_is_idle); - - return true; -} - -rarch_softfilter_t *video_driver_frame_filter_get_ptr(void) -{ - return video_driver_state_filter; -} - -enum retro_pixel_format video_driver_get_pixel_format(void) -{ - return video_driver_pix_fmt; -} - -void video_driver_set_pixel_format(enum retro_pixel_format fmt) -{ - video_driver_pix_fmt = fmt; -} - -/** - * video_driver_cached_frame: - * - * Renders the current video frame. - **/ -bool video_driver_cached_frame(void) -{ - void *recording = recording_driver_get_data_ptr(); - - recording_driver_lock(); - - /* Cannot allow recording when pushing duped frames. */ - recording_data = NULL; - - retro_ctx.frame_cb( - (frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID) - ? frame_cache_data : NULL, - frame_cache_width, - frame_cache_height, frame_cache_pitch); - - recording_data = recording; - - recording_driver_unlock(); - - return true; -} - -void video_driver_monitor_adjust_system_rates(void) -{ - float timing_skew = 0.0f; - settings_t *settings = config_get_ptr(); - float video_refresh_rate = settings->floats.video_refresh_rate; - float timing_skew_hz = video_refresh_rate; - const struct retro_system_timing *info = (const struct retro_system_timing*)&video_driver_av_info.timing; - - rarch_ctl(RARCH_CTL_UNSET_NONBLOCK_FORCED, NULL); - - if (!info || info->fps <= 0.0) - return; - - video_driver_core_hz = info->fps; - - if (video_driver_crt_switching_active) - timing_skew_hz = video_driver_core_hz; - timing_skew = fabs( - 1.0f - info->fps / timing_skew_hz); - - if (!settings->bools.vrr_runloop_enable) - { - /* We don't want to adjust pitch too much. If we have extreme cases, - * just don't readjust at all. */ - if (timing_skew <= settings->floats.audio_max_timing_skew) - return; - - RARCH_LOG("[Video]: Timings deviate too much. Will not adjust." - " (Display = %.2f Hz, Game = %.2f Hz)\n", - video_refresh_rate, - (float)info->fps); - } - - if (info->fps <= timing_skew_hz) - return; - - /* We won't be able to do VSync reliably when game FPS > monitor FPS. */ - rarch_ctl(RARCH_CTL_SET_NONBLOCK_FORCED, NULL); - RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n"); -} - -void video_driver_menu_settings(void **list_data, void *list_info_data, - void *group_data, void *subgroup_data, const char *parent_group) -{ -#ifdef HAVE_MENU - rarch_setting_t **list = (rarch_setting_t**)list_data; - rarch_setting_info_t *list_info = (rarch_setting_info_t*)list_info_data; - rarch_setting_group_info_t *group_info = (rarch_setting_group_info_t*)group_data; - rarch_setting_group_info_t *subgroup_info = (rarch_setting_group_info_t*)subgroup_data; - global_t *global = global_get_ptr(); - - (void)list; - (void)list_info; - (void)group_info; - (void)subgroup_info; - (void)global; - -#if defined(__CELLOS_LV2__) - CONFIG_BOOL( - list, list_info, - &global->console.screen.pal60_enable, - MENU_ENUM_LABEL_PAL60_ENABLE, - MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, - false, - MENU_ENUM_LABEL_VALUE_OFF, - MENU_ENUM_LABEL_VALUE_ON, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler, - SD_FLAG_NONE); -#endif -#if defined(GEKKO) || defined(_XBOX360) - CONFIG_UINT( - list, list_info, - &global->console.screen.gamma_correction, - MENU_ENUM_LABEL_VIDEO_GAMMA, - MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - 0, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - menu_settings_list_current_add_cmd( - list, - list_info, - CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); - menu_settings_list_current_add_range( - list, - list_info, - 0, - MAX_GAMMA_SETTING, - 1, - true, - true); - settings_data_list_current_add_flags(list, list_info, - SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); -#endif -#if defined(_XBOX1) || defined(HW_RVL) - CONFIG_BOOL( - list, list_info, - &global->console.softfilter_enable, - MENU_ENUM_LABEL_VIDEO_SOFT_FILTER, - MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - false, - MENU_ENUM_LABEL_VALUE_OFF, - MENU_ENUM_LABEL_VALUE_ON, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler, - SD_FLAG_NONE); - menu_settings_list_current_add_cmd( - list, - list_info, - CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); -#endif -#ifdef _XBOX1 - CONFIG_UINT( - list, list_info, - &global->console.screen.flicker_filter_index, - MENU_ENUM_LABEL_VIDEO_FILTER_FLICKER, - MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - 0, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - menu_settings_list_current_add_range(list, list_info, - 0, 5, 1, true, true); -#endif -#endif -} - -static void video_driver_lock_new(void) -{ - video_driver_lock_free(); -#ifdef HAVE_THREADS - if (!display_lock) - display_lock = slock_new(); - retro_assert(display_lock); - - if (!context_lock) - context_lock = slock_new(); - retro_assert(context_lock); -#endif -} - -void video_driver_destroy(void) -{ - video_display_server_destroy(); - crt_video_restore(); - - video_driver_cb_has_focus = null_driver_has_focus; - video_driver_use_rgba = false; - video_driver_data_own = false; - video_driver_active = false; - video_driver_cache_context = false; - video_driver_cache_context_ack = false; - video_driver_record_gpu_buffer = NULL; - current_video = NULL; - video_driver_set_cached_frame_ptr(NULL); -} - -void video_driver_set_cached_frame_ptr(const void *data) -{ - if (data) - frame_cache_data = data; -} - -void video_driver_set_stub_frame(void) -{ - frame_bak = current_video->frame; - current_video->frame = video_null.frame; -} - -void video_driver_unset_stub_frame(void) -{ - if (frame_bak != NULL) - current_video->frame = frame_bak; - - frame_bak = NULL; -} - -bool video_driver_is_stub_frame(void) -{ - return current_video->frame == video_null.frame; -} - -bool video_driver_supports_recording(void) -{ - settings_t *settings = config_get_ptr(); - return settings->bools.video_gpu_record - && current_video->read_viewport; -} - -bool video_driver_supports_viewport_read(void) -{ - settings_t *settings = config_get_ptr(); - return (settings->bools.video_gpu_screenshot || - (video_driver_is_hw_context() && !current_video->read_frame_raw)) - && current_video->read_viewport && current_video->viewport_info; -} - -bool video_driver_supports_read_frame_raw(void) -{ - if (current_video->read_frame_raw) - return true; - return false; -} - -void video_driver_set_viewport_config(void) -{ - settings_t *settings = config_get_ptr(); - - if (settings->floats.video_aspect_ratio < 0.0f) - { - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - - if (geom->aspect_ratio > 0.0f && - settings->bools.video_aspect_ratio_auto) - aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio; - else - { - unsigned base_width = geom->base_width; - unsigned base_height = geom->base_height; - - /* Get around division by zero errors */ - if (base_width == 0) - base_width = 1; - if (base_height == 0) - base_height = 1; - aspectratio_lut[ASPECT_RATIO_CONFIG].value = - (float)base_width / base_height; /* 1:1 PAR. */ - } - } - else - { - aspectratio_lut[ASPECT_RATIO_CONFIG].value = - settings->floats.video_aspect_ratio; - } -} - -void video_driver_set_viewport_square_pixel(void) -{ - unsigned len, highest, i, aspect_x, aspect_y; - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - unsigned width = geom->base_width; - unsigned height = geom->base_height; - - if (width == 0 || height == 0) - return; - - len = MIN(width, height); - highest = 1; - - for (i = 1; i < len; i++) - { - if ((width % i) == 0 && (height % i) == 0) - highest = i; - } - - aspect_x = width / highest; - aspect_y = height / highest; - - snprintf(aspectratio_lut[ASPECT_RATIO_SQUARE].name, - sizeof(aspectratio_lut[ASPECT_RATIO_SQUARE].name), - "1:1 PAR (%u:%u DAR)", aspect_x, aspect_y); - - aspectratio_lut[ASPECT_RATIO_SQUARE].value = (float)aspect_x / aspect_y; -} - -void video_driver_set_viewport_core(void) -{ - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - - if (!geom || geom->base_width <= 0.0f || geom->base_height <= 0.0f) - return; - - /* Fallback to 1:1 pixel ratio if none provided */ - if (geom->aspect_ratio > 0.0f) - aspectratio_lut[ASPECT_RATIO_CORE].value = geom->aspect_ratio; - else - aspectratio_lut[ASPECT_RATIO_CORE].value = - (float)geom->base_width / geom->base_height; -} - -void video_driver_reset_custom_viewport(void) -{ - struct video_viewport *custom_vp = video_viewport_get_custom(); - - custom_vp->width = 0; - custom_vp->height = 0; - custom_vp->x = 0; - custom_vp->y = 0; -} - -void video_driver_set_rgba(void) -{ - video_driver_lock(); - video_driver_use_rgba = true; - video_driver_unlock(); -} - -void video_driver_unset_rgba(void) -{ - video_driver_lock(); - video_driver_use_rgba = false; - video_driver_unlock(); -} - -bool video_driver_supports_rgba(void) -{ - bool tmp; - video_driver_lock(); - tmp = video_driver_use_rgba; - video_driver_unlock(); - return tmp; -} - -bool video_driver_get_next_video_out(void) -{ - if (!video_driver_poke) - return false; - - if (!video_driver_poke->get_video_output_next) - return video_context_driver_get_video_output_next(); - video_driver_poke->get_video_output_next(video_driver_data); - return true; -} - -bool video_driver_get_prev_video_out(void) -{ - if (!video_driver_poke) - return false; - - if (!video_driver_poke->get_video_output_prev) - return video_context_driver_get_video_output_prev(); - video_driver_poke->get_video_output_prev(video_driver_data); - return true; -} - -bool video_driver_init(bool *video_is_threaded) -{ - video_driver_lock_new(); - video_driver_filter_free(); - video_driver_set_cached_frame_ptr(NULL); - return video_driver_init_internal(video_is_threaded); -} - -void video_driver_destroy_data(void) -{ - video_driver_data = NULL; -} - -void video_driver_free(void) -{ - video_driver_free_internal(); - video_driver_lock_free(); - video_driver_data = NULL; - video_driver_set_cached_frame_ptr(NULL); -} - -void video_driver_monitor_reset(void) -{ - video_driver_frame_time_count = 0; -} - -void video_driver_set_aspect_ratio(void) -{ - settings_t *settings = config_get_ptr(); - - switch (settings->uints.video_aspect_ratio_idx) - { - case ASPECT_RATIO_SQUARE: - video_driver_set_viewport_square_pixel(); - break; - - case ASPECT_RATIO_CORE: - video_driver_set_viewport_core(); - break; - - case ASPECT_RATIO_CONFIG: - video_driver_set_viewport_config(); - break; - - default: - break; - } - - video_driver_set_aspect_ratio_value( - aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); - - if (!video_driver_poke || !video_driver_poke->set_aspect_ratio) - return; - video_driver_poke->set_aspect_ratio( - video_driver_data, settings->uints.video_aspect_ratio_idx); -} - -void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect) -{ - gfx_ctx_aspect_t aspect_data; - float device_aspect = (float)vp->full_width / vp->full_height; - settings_t* settings = config_get_ptr(); - - aspect_data.aspect = &device_aspect; - aspect_data.width = vp->full_width; - aspect_data.height = vp->full_height; - - video_context_driver_translate_aspect(&aspect_data); - - vp->x = 0; - vp->y = 0; - vp->width = vp->full_width; - vp->height = vp->full_height; - - if (settings->bools.video_scale_integer && !force_full) - { - video_viewport_get_scaled_integer( - vp, vp->full_width, vp->full_height, video_driver_get_aspect_ratio(), keep_aspect); - } - else if (keep_aspect && !force_full) - { - float desired_aspect = video_driver_get_aspect_ratio(); - -#if defined(HAVE_MENU) - if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) - { - const struct video_viewport* custom = video_viewport_get_custom(); - - vp->x = custom->x; - vp->y = custom->y; - vp->width = custom->width; - vp->height = custom->height; - } - else -#endif - { - float delta; - - if (fabsf(device_aspect - desired_aspect) < 0.0001f) - { - /* If the aspect ratios of screen and desired aspect - * ratio are sufficiently equal (floating point stuff), - * assume they are actually equal. - */ - } - else if (device_aspect > desired_aspect) - { - delta = (desired_aspect / device_aspect - 1.0f) - / 2.0f + 0.5f; - vp->x = (int)roundf(vp->full_width * (0.5f - delta)); - vp->width = (unsigned)roundf(2.0f * vp->full_width * delta); - vp->y = 0; - vp->height = vp->full_height; - } - else - { - vp->x = 0; - vp->width = vp->full_width; - delta = (device_aspect / desired_aspect - 1.0f) - / 2.0f + 0.5f; - vp->y = (int)roundf(vp->full_height * (0.5f - delta)); - vp->height = (unsigned)roundf(2.0f * vp->full_height * delta); - } - } - } - -#if defined(RARCH_MOBILE) - /* In portrait mode, we want viewport to gravitate to top of screen. */ - if (device_aspect < 1.0f) - vp->y = 0; -#endif -} - -void video_driver_show_mouse(void) -{ - if (video_driver_poke && video_driver_poke->show_mouse) - video_driver_poke->show_mouse(video_driver_data, true); -} - -void video_driver_hide_mouse(void) -{ - if (video_driver_poke && video_driver_poke->show_mouse) - video_driver_poke->show_mouse(video_driver_data, false); -} - -void video_driver_set_nonblock_state(bool toggle) -{ - if (current_video->set_nonblock_state) - current_video->set_nonblock_state(video_driver_data, toggle); -} - -bool video_driver_find_driver(void) -{ - int i; - driver_ctx_info_t drv; - settings_t *settings = config_get_ptr(); - - if (video_driver_is_hw_context()) - { - struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); - - current_video = NULL; - - (void)hwr; - -#if defined(HAVE_VULKAN) - if (hwr && hw_render_context_is_vulkan(hwr->context_type)) - { - RARCH_LOG("[Video]: Using HW render, Vulkan driver forced.\n"); - current_video = &video_vulkan; - } -#endif - -#if defined(HAVE_OPENGL) - if (hwr && hw_render_context_is_gl(hwr->context_type)) - { - RARCH_LOG("[Video]: Using HW render, OpenGL driver forced.\n"); - current_video = &video_gl; - } -#endif - - if (current_video) - return true; - } - - if (frontend_driver_has_get_video_driver_func()) - { - current_video = (video_driver_t*)frontend_driver_get_video_driver(); - - if (current_video) - return true; - RARCH_WARN("Frontend supports get_video_driver() but did not specify one.\n"); - } - - drv.label = "video_driver"; - drv.s = settings->arrays.video_driver; - - driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv); - - i = (int)drv.len; - - if (i >= 0) - current_video = (video_driver_t*)video_driver_find_handle(i); - else - { - if (verbosity_is_enabled()) - { - unsigned d; - RARCH_ERR("Couldn't find any video driver named \"%s\"\n", - settings->arrays.video_driver); - RARCH_LOG_OUTPUT("Available video drivers are:\n"); - for (d = 0; video_driver_find_handle(d); d++) - RARCH_LOG_OUTPUT("\t%s\n", video_driver_find_ident(d)); - RARCH_WARN("Going to default to first video driver...\n"); - } - - current_video = (video_driver_t*)video_driver_find_handle(0); - - if (!current_video) - retroarch_fail(1, "find_video_driver()"); - } - return true; -} - -void video_driver_apply_state_changes(void) -{ - if (video_driver_poke && - video_driver_poke->apply_state_changes) - video_driver_poke->apply_state_changes(video_driver_data); -} - -bool video_driver_read_viewport(uint8_t *buffer, bool is_idle) -{ - if ( current_video->read_viewport - && current_video->read_viewport( - video_driver_data, buffer, is_idle)) - return true; - return false; -} - -bool video_driver_frame_filter_alive(void) -{ - return !!video_driver_state_filter; -} - -bool video_driver_frame_filter_is_32bit(void) -{ - return video_driver_state_out_rgb32; -} - -void video_driver_default_settings(void) -{ - global_t *global = global_get_ptr(); - - if (!global) - return; - - global->console.screen.gamma_correction = DEFAULT_GAMMA; - global->console.flickerfilter_enable = false; - global->console.softfilter_enable = false; - - global->console.screen.resolutions.current.id = 0; -} - -void video_driver_load_settings(config_file_t *conf) -{ - bool tmp_bool = false; - global_t *global = global_get_ptr(); - - if (!conf) - return; - -#ifdef _XBOX - CONFIG_GET_BOOL_BASE(conf, global, - console.screen.gamma_correction, "gamma_correction"); -#else - CONFIG_GET_INT_BASE(conf, global, - console.screen.gamma_correction, "gamma_correction"); -#endif - - if (config_get_bool(conf, "flicker_filter_enable", - &tmp_bool)) - global->console.flickerfilter_enable = tmp_bool; - - if (config_get_bool(conf, "soft_filter_enable", - &tmp_bool)) - global->console.softfilter_enable = tmp_bool; - - CONFIG_GET_INT_BASE(conf, global, - console.screen.soft_filter_index, - "soft_filter_index"); - CONFIG_GET_INT_BASE(conf, global, - console.screen.resolutions.current.id, - "current_resolution_id"); - CONFIG_GET_INT_BASE(conf, global, - console.screen.flicker_filter_index, - "flicker_filter_index"); -} - -void video_driver_save_settings(config_file_t *conf) -{ - global_t *global = global_get_ptr(); - if (!conf) - return; - -#ifdef _XBOX - config_set_bool(conf, "gamma_correction", - global->console.screen.gamma_correction); -#else - config_set_int(conf, "gamma_correction", - global->console.screen.gamma_correction); -#endif - config_set_bool(conf, "flicker_filter_enable", - global->console.flickerfilter_enable); - config_set_bool(conf, "soft_filter_enable", - global->console.softfilter_enable); - - config_set_int(conf, "soft_filter_index", - global->console.screen.soft_filter_index); - config_set_int(conf, "current_resolution_id", - global->console.screen.resolutions.current.id); - config_set_int(conf, "flicker_filter_index", - global->console.screen.flicker_filter_index); -} - -void video_driver_reinit(void) -{ - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); - - if (hwr->cache_context) - video_driver_cache_context = true; - else - video_driver_cache_context = false; - - video_driver_cache_context_ack = false; - command_event(CMD_EVENT_RESET_CONTEXT, NULL); - video_driver_cache_context = false; -} - -void video_driver_set_own_driver(void) -{ - video_driver_data_own = true; -} - -void video_driver_unset_own_driver(void) -{ - video_driver_data_own = false; -} - -bool video_driver_owns_driver(void) -{ - return video_driver_data_own; -} - -bool video_driver_is_hw_context(void) -{ - bool is_hw_context = false; - - video_driver_context_lock(); - is_hw_context = (hw_render.context_type != RETRO_HW_CONTEXT_NONE); - video_driver_context_unlock(); - - return is_hw_context; -} - -void video_driver_free_hw_context(void) -{ - video_driver_context_lock(); - - if (hw_render.context_destroy) - hw_render.context_destroy(); - - memset(&hw_render, 0, sizeof(hw_render)); - - video_driver_context_unlock(); - - hw_render_context_negotiation = NULL; -} - -struct retro_hw_render_callback *video_driver_get_hw_context(void) -{ - return &hw_render; -} - -const struct retro_hw_render_context_negotiation_interface * - video_driver_get_context_negotiation_interface(void) -{ - return hw_render_context_negotiation; -} - -void video_driver_set_context_negotiation_interface( - const struct retro_hw_render_context_negotiation_interface *iface) -{ - hw_render_context_negotiation = iface; -} - -bool video_driver_is_video_cache_context(void) -{ - return video_driver_cache_context; -} - -void video_driver_set_video_cache_context_ack(void) -{ - video_driver_cache_context_ack = true; -} - -void video_driver_unset_video_cache_context_ack(void) -{ - video_driver_cache_context_ack = false; -} - -bool video_driver_is_video_cache_context_ack(void) -{ - return video_driver_cache_context_ack; -} - -void video_driver_set_active(void) -{ - video_driver_active = true; -} - -void video_driver_unset_active(void) -{ - video_driver_active = false; -} - -bool video_driver_is_active(void) -{ - return video_driver_active; -} - -void video_driver_get_record_status( - bool *has_gpu_record, - uint8_t **gpu_buf) -{ - *gpu_buf = video_driver_record_gpu_buffer; - *has_gpu_record = video_driver_record_gpu_buffer != NULL; -} - -bool video_driver_gpu_record_init(unsigned size) -{ - video_driver_record_gpu_buffer = (uint8_t*)malloc(size); - if (!video_driver_record_gpu_buffer) - return false; - return true; -} - -void video_driver_gpu_record_deinit(void) -{ - free(video_driver_record_gpu_buffer); - video_driver_record_gpu_buffer = NULL; -} - -bool video_driver_get_current_software_framebuffer( - struct retro_framebuffer *fb) -{ - if ( - video_driver_poke - && video_driver_poke->get_current_software_framebuffer - && video_driver_poke->get_current_software_framebuffer( - video_driver_data, fb)) - return true; - - return false; -} - -bool video_driver_get_hw_render_interface( - const struct retro_hw_render_interface **iface) -{ - if ( - video_driver_poke - && video_driver_poke->get_hw_render_interface - && video_driver_poke->get_hw_render_interface( - video_driver_data, iface)) - return true; - - return false; -} - -bool video_driver_get_viewport_info(struct video_viewport *viewport) -{ - if (!current_video || !current_video->viewport_info) - return false; - current_video->viewport_info(video_driver_data, viewport); - return true; -} - -void video_driver_set_title_buf(void) -{ - struct retro_system_info info; - core_get_system_info(&info); - - fill_pathname_join_concat_noext( - video_driver_title_buf, - msg_hash_to_str(MSG_PROGRAM), - " ", - info.library_name, - sizeof(video_driver_title_buf)); - strlcat(video_driver_title_buf, - " ", sizeof(video_driver_title_buf)); - strlcat(video_driver_title_buf, - info.library_version, - sizeof(video_driver_title_buf)); -} - -/** - * video_viewport_get_scaled_integer: - * @vp : Viewport handle - * @width : Width. - * @height : Height. - * @aspect_ratio : Aspect ratio (in float). - * @keep_aspect : Preserve aspect ratio? - * - * Gets viewport scaling dimensions based on - * scaled integer aspect ratio. - **/ -void video_viewport_get_scaled_integer(struct video_viewport *vp, - unsigned width, unsigned height, - float aspect_ratio, bool keep_aspect) -{ - int padding_x = 0; - int padding_y = 0; - settings_t *settings = config_get_ptr(); - - if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) - { - struct video_viewport *custom = video_viewport_get_custom(); - - if (custom) - { - padding_x = width - custom->width; - padding_y = height - custom->height; - width = custom->width; - height = custom->height; - } - } - else - { - unsigned base_width; - /* Use system reported sizes as these define the - * geometry for the "normal" case. */ - unsigned base_height = - video_driver_av_info.geometry.base_height; - - if (base_height == 0) - base_height = 1; - - /* Account for non-square pixels. - * This is sort of contradictory with the goal of integer scale, - * but it is desirable in some cases. - * - * If square pixels are used, base_height will be equal to - * system->av_info.base_height. */ - base_width = (unsigned)roundf(base_height * aspect_ratio); - - /* Make sure that we don't get 0x scale ... */ - if (width >= base_width && height >= base_height) - { - if (keep_aspect) - { - /* X/Y scale must be same. */ - unsigned max_scale = MIN(width / base_width, - height / base_height); - padding_x = width - base_width * max_scale; - padding_y = height - base_height * max_scale; - } - else - { - /* X/Y can be independent, each scaled as much as possible. */ - padding_x = width % base_width; - padding_y = height % base_height; - } - } - - width -= padding_x; - height -= padding_y; - } - - vp->width = width; - vp->height = height; - vp->x = padding_x / 2; - vp->y = padding_y / 2; -} - -struct retro_system_av_info *video_viewport_get_system_av_info(void) -{ - return &video_driver_av_info; -} - -struct video_viewport *video_viewport_get_custom(void) -{ - settings_t *settings = config_get_ptr(); - return &settings->video_viewport_custom; -} - -unsigned video_pixel_get_alignment(unsigned pitch) -{ - if (pitch & 1) - return 1; - if (pitch & 2) - return 2; - if (pitch & 4) - return 4; - return 8; -} - -/** - * video_driver_frame: - * @data : pointer to data of the video frame. - * @width : width of the video frame. - * @height : height of the video frame. - * @pitch : pitch of the video frame. - * - * Video frame render callback function. - **/ -void video_driver_frame(const void *data, unsigned width, - unsigned height, size_t pitch) -{ - static char video_driver_msg[256]; - static char title[256]; - video_frame_info_t video_info; - static retro_time_t curr_time; - static retro_time_t fps_time; - static float last_fps, frame_time; - unsigned output_width = 0; - unsigned output_height = 0; - unsigned output_pitch = 0; - const char *msg = NULL; - retro_time_t new_time = - cpu_features_get_time_usec(); - - if (!video_driver_active) - return; - - if (video_driver_scaler_ptr && data && - (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_0RGB1555) && - (data != RETRO_HW_FRAME_BUFFER_VALID)) - { - if (video_pixel_frame_scale( - video_driver_scaler_ptr->scaler, - video_driver_scaler_ptr->scaler_out, - data, width, height, pitch)) - { - data = video_driver_scaler_ptr->scaler_out; - pitch = video_driver_scaler_ptr->scaler->out_stride; - } - } - - if (data) - frame_cache_data = data; - frame_cache_width = width; - frame_cache_height = height; - frame_cache_pitch = pitch; - - video_driver_build_info(&video_info); - - /* Get the amount of frames per seconds. */ - if (video_driver_frame_count) - { - unsigned write_index = - video_driver_frame_time_count++ & - (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1); - frame_time = new_time - fps_time; - video_driver_frame_time_samples[write_index] = frame_time; - fps_time = new_time; - - if (video_driver_frame_count == 1) - strlcpy(title, video_driver_window_title, sizeof(title)); - - if ((video_driver_frame_count % FPS_UPDATE_INTERVAL) == 0) - { - char frames_text[64]; - last_fps = TIME_TO_FPS(curr_time, new_time, FPS_UPDATE_INTERVAL); - - if (video_info.fps_show || video_info.framecount_show) - { - if (video_info.fps_show) - { - snprintf(video_info.fps_text, sizeof(video_info.fps_text), - " || FPS: %6.1f ", last_fps); - } - if (video_info.framecount_show) - { - snprintf(frames_text, - sizeof(frames_text), - " || Frames: %" PRIu64, - (uint64_t)video_driver_frame_count); - } - snprintf(video_driver_window_title, sizeof(video_driver_window_title), - "%s%s%s", title, - video_info.fps_show ? video_info.fps_text : "", - video_info.framecount_show ? frames_text : ""); - } - else - { - if (!string_is_equal(video_driver_window_title, title)) - strlcpy(video_driver_window_title, title, sizeof(video_driver_window_title)); - } - - curr_time = new_time; - video_driver_window_title_update = true; - } - - if (video_info.fps_show) - { - if (video_info.framecount_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f || %s: %" PRIu64, - last_fps, - msg_hash_to_str(MSG_FRAMES), - (uint64_t)video_driver_frame_count); - else - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f", - last_fps); - } - - if (video_info.fps_show && video_info.framecount_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f || %s: %" PRIu64, - last_fps, - msg_hash_to_str(MSG_FRAMES), - (uint64_t)video_driver_frame_count); - else if (video_info.framecount_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "%s: %" PRIu64, - msg_hash_to_str(MSG_FRAMES), - (uint64_t)video_driver_frame_count); - else if (video_info.fps_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f", - last_fps); - } - else - { - - curr_time = fps_time = new_time; - - strlcpy(video_driver_window_title, - video_driver_title_buf, - sizeof(video_driver_window_title)); - - if (video_info.fps_show) - strlcpy(video_info.fps_text, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), - sizeof(video_info.fps_text)); - - video_driver_window_title_update = true; - } - - video_info.frame_rate = last_fps; - video_info.frame_time = frame_time / 1000.0f; - video_info.frame_count = (uint64_t) video_driver_frame_count; - - /* Slightly messy code, - * but we really need to do processing before blocking on VSync - * for best possible scheduling. - */ - if ( - ( - !video_driver_state_filter - || !video_info.post_filter_record - || !data - || video_driver_record_gpu_buffer - ) && recording_data - ) - recording_dump_frame(data, width, height, - pitch, video_info.runloop_is_idle); - - if (data && video_driver_state_filter && - video_driver_frame_filter(data, &video_info, width, height, pitch, - &output_width, &output_height, &output_pitch)) - { - data = video_driver_state_buffer; - width = output_width; - height = output_height; - pitch = output_pitch; - } - - video_driver_msg[0] = '\0'; - - if ( video_info.font_enable - && runloop_msg_queue_pull((const char**)&msg) - && msg) - { -#ifdef HAVE_THREADS - /* the msg pointer may point to data modified by another thread */ - runloop_msg_queue_lock(); -#endif - strlcpy(video_driver_msg, msg, sizeof(video_driver_msg)); -#ifdef HAVE_THREADS - runloop_msg_queue_unlock(); -#endif - } - - if (video_info.statistics_show) - { - audio_statistics_t audio_stats = {0.0f}; - double stddev = 0.0; - struct retro_system_av_info *av_info = &video_driver_av_info; - unsigned red = 255; - unsigned green = 255; - unsigned blue = 255; - unsigned alpha = 255; - - video_monitor_fps_statistics(NULL, &stddev, NULL); - - video_info.osd_stat_params.x = 0.010f; - video_info.osd_stat_params.y = 0.950f; - video_info.osd_stat_params.scale = 1.0f; - video_info.osd_stat_params.full_screen = true; - video_info.osd_stat_params.drop_x = -2; - video_info.osd_stat_params.drop_y = -2; - video_info.osd_stat_params.drop_mod = 0.3f; - video_info.osd_stat_params.drop_alpha = 1.0f; - video_info.osd_stat_params.color = COLOR_ABGR( - red, green, blue, alpha); - - compute_audio_buffer_statistics(&audio_stats); - - snprintf(video_info.stat_text, - sizeof(video_info.stat_text), - "Video Statistics:\n -Frame rate: %6.2f fps\n -Frame time: %6.2f ms\n -Frame time deviation: %.3f %%\n" - " -Frame count: %" PRIu64"\n -Viewport: %d x %d x %3.2f\n" - "Audio Statistics:\n -Average buffer saturation: %.2f %%\n -Standard deviation: %.2f %%\n -Time spent close to underrun: %.2f %%\n -Time spent close to blocking: %.2f %%\n -Sample count: %d\n" - "Core Geometry:\n -Size: %u x %u\n -Max Size: %u x %u\n -Aspect: %3.2f\nCore Timing:\n -FPS: %3.2f\n -Sample Rate: %6.2f\n", - video_info.frame_rate, - video_info.frame_time, - 100.0 * stddev, - video_info.frame_count, - video_info.width, - video_info.height, - video_info.refresh_rate, - audio_stats.average_buffer_saturation, - audio_stats.std_deviation_percentage, - audio_stats.close_to_underrun, - audio_stats.close_to_blocking, - audio_stats.samples, - av_info->geometry.base_width, - av_info->geometry.base_height, - av_info->geometry.max_width, - av_info->geometry.max_height, - av_info->geometry.aspect_ratio, - av_info->timing.fps, - av_info->timing.sample_rate); - - /* TODO/FIXME - add OSD chat text here */ -#if 0 - snprintf(video_info.chat_text, sizeof(video_info.chat_text), - "anon: does retroarch netplay have in-game chat?\nradius: I don't know \u2605"); -#endif - } - - video_driver_active = current_video->frame( - video_driver_data, data, width, height, - video_driver_frame_count, - (unsigned)pitch, video_driver_msg, &video_info); - - video_driver_frame_count++; - - /* Display the FPS, with a higher priority. */ - if (video_info.fps_show || video_info.framecount_show) - runloop_msg_queue_push(video_info.fps_text, 2, 1, true); - - /* trigger set resolution*/ - if (video_info.crt_switch_resolution) - { - video_driver_crt_switching_active = true; - - if (video_info.crt_switch_resolution_super == 2560) - width = 2560; - if (video_info.crt_switch_resolution_super == 3840) - width = 3840; - if (video_info.crt_switch_resolution_super == 1920) - width = 1920; - crt_switch_res_core(width, height, video_driver_core_hz, video_info.crt_switch_resolution, video_info.crt_switch_center_adjust); - } - else if (!video_info.crt_switch_resolution) - video_driver_crt_switching_active = false; - - /* trigger set resolution*/ -} - -void video_driver_display_type_set(enum rarch_display_type type) -{ - video_driver_display_type = type; -} - -uintptr_t video_driver_display_get(void) -{ - return video_driver_display; -} - -void video_driver_display_set(uintptr_t idx) -{ - video_driver_display = idx; -} - -enum rarch_display_type video_driver_display_type_get(void) -{ - return video_driver_display_type; -} - -void video_driver_window_set(uintptr_t idx) -{ - video_driver_window = idx; -} - -uintptr_t video_driver_window_get(void) -{ - return video_driver_window; -} - -bool video_driver_texture_load(void *data, - enum texture_filter_type filter_type, - uintptr_t *id) -{ - if (!id || !video_driver_poke || !video_driver_poke->load_texture) - return false; - - *id = video_driver_poke->load_texture(video_driver_data, data, - video_driver_is_threaded_internal(), - filter_type); - - return true; -} - -bool video_driver_texture_unload(uintptr_t *id) -{ - if (!video_driver_poke || !video_driver_poke->unload_texture) - return false; - - video_driver_poke->unload_texture(video_driver_data, *id); - *id = 0; - return true; -} - -static void video_shader_driver_use_null(void *data, - void *shader_data, unsigned idx, bool set_active) -{ - (void)data; - (void)idx; - (void)set_active; -} - -static bool video_driver_cb_set_coords(void *handle_data, - void *shader_data, const struct video_coords *coords) -{ - video_shader_ctx_coords_t ctx_coords; - ctx_coords.handle_data = handle_data; - ctx_coords.data = coords; - - video_driver_set_coords(&ctx_coords); - return true; -} - -void video_driver_build_info(video_frame_info_t *video_info) -{ - bool is_perfcnt_enable = false; - bool is_paused = false; - bool is_idle = false; - bool is_slowmotion = false; - settings_t *settings = NULL; - video_viewport_t *custom_vp = NULL; - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); - video_driver_threaded_lock(is_threaded); -#endif - settings = config_get_ptr(); - custom_vp = &settings->video_viewport_custom; - video_info->refresh_rate = settings->floats.video_refresh_rate; - video_info->crt_switch_resolution = settings->uints.crt_switch_resolution; - video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super; - video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust; - video_info->black_frame_insertion = settings->bools.video_black_frame_insertion; - video_info->hard_sync = settings->bools.video_hard_sync; - video_info->hard_sync_frames = settings->uints.video_hard_sync_frames; - video_info->fps_show = settings->bools.video_fps_show; - video_info->statistics_show = settings->bools.video_statistics_show; - video_info->framecount_show = settings->bools.video_framecount_show; - video_info->scale_integer = settings->bools.video_scale_integer; - video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx; - video_info->post_filter_record = settings->bools.video_post_filter_record; - video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons; - video_info->max_swapchain_images = settings->uints.video_max_swapchain_images; - video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen; - video_info->fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); - video_info->monitor_index = settings->uints.video_monitor_index; - video_info->shared_context = settings->bools.video_shared_context; - - if (libretro_get_shared_context() && hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) - video_info->shared_context = true; - - video_info->font_enable = settings->bools.video_font_enable; - video_info->font_msg_pos_x = settings->floats.video_msg_pos_x; - video_info->font_msg_pos_y = settings->floats.video_msg_pos_y; - video_info->font_msg_color_r = settings->floats.video_msg_color_r; - video_info->font_msg_color_g = settings->floats.video_msg_color_g; - video_info->font_msg_color_b = settings->floats.video_msg_color_b; - video_info->custom_vp_x = custom_vp->x; - video_info->custom_vp_y = custom_vp->y; - video_info->custom_vp_width = custom_vp->width; - video_info->custom_vp_height = custom_vp->height; - video_info->custom_vp_full_width = custom_vp->full_width; - video_info->custom_vp_full_height = custom_vp->full_height; - - video_info->fps_text[0] = '\0'; - - video_info->width = video_driver_width; - video_info->height = video_driver_height; - - video_info->use_rgba = video_driver_use_rgba; - - video_info->libretro_running = false; - video_info->msg_bgcolor_enable = settings->bools.video_msg_bgcolor_enable; - -#ifdef HAVE_MENU - video_info->menu_is_alive = menu_driver_is_alive(); - video_info->menu_footer_opacity = settings->floats.menu_footer_opacity; - video_info->menu_header_opacity = settings->floats.menu_header_opacity; - video_info->materialui_color_theme = settings->uints.menu_materialui_color_theme; - video_info->ozone_color_theme = settings->uints.menu_ozone_color_theme; - video_info->menu_shader_pipeline = settings->uints.menu_xmb_shader_pipeline; - video_info->xmb_theme = settings->uints.menu_xmb_theme; - video_info->xmb_color_theme = settings->uints.menu_xmb_color_theme; - video_info->timedate_enable = settings->bools.menu_timedate_enable; - video_info->battery_level_enable = settings->bools.menu_battery_level_enable; - video_info->xmb_shadows_enable = settings->bools.menu_xmb_shadows_enable; - video_info->xmb_alpha_factor = settings->uints.menu_xmb_alpha_factor; - video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity; - video_info->menu_framebuffer_opacity = settings->floats.menu_framebuffer_opacity; - - video_info->libretro_running = core_is_game_loaded(); -#else - video_info->menu_is_alive = false; - video_info->menu_footer_opacity = 0.0f; - video_info->menu_header_opacity = 0.0f; - video_info->materialui_color_theme = 0; - video_info->menu_shader_pipeline = 0; - video_info->xmb_color_theme = 0; - video_info->xmb_theme = 0; - video_info->timedate_enable = false; - video_info->battery_level_enable = false; - video_info->xmb_shadows_enable = false; - video_info->xmb_alpha_factor = 0.0f; - video_info->menu_framebuffer_opacity = 0.0f; - video_info->menu_wallpaper_opacity = 0.0f; -#endif - - runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); - - video_info->is_perfcnt_enable = is_perfcnt_enable; - video_info->runloop_is_paused = is_paused; - video_info->runloop_is_idle = is_idle; - video_info->runloop_is_slowmotion = is_slowmotion; - - video_info->input_driver_nonblock_state = input_driver_is_nonblock_state(); - - video_info->context_data = video_context_data; - video_info->shader_driver = current_shader; - video_info->shader_data = current_shader_data; - - video_info->cb_update_window_title = current_video_context.update_window_title; - video_info->cb_swap_buffers = current_video_context.swap_buffers; - video_info->cb_get_metrics = current_video_context.get_metrics; - video_info->cb_set_resize = current_video_context.set_resize; - - video_info->cb_set_mvp = video_driver_cb_shader_set_mvp; - - video_info->userdata = video_driver_get_ptr(false); - -#ifdef HAVE_THREADS - video_driver_threaded_unlock(is_threaded); -#endif -} - -/** - * video_driver_translate_coord_viewport: - * @mouse_x : Pointer X coordinate. - * @mouse_y : Pointer Y coordinate. - * @res_x : Scaled X coordinate. - * @res_y : Scaled Y coordinate. - * @res_screen_x : Scaled screen X coordinate. - * @res_screen_y : Scaled screen Y coordinate. - * - * Translates pointer [X,Y] coordinates into scaled screen - * coordinates based on viewport info. - * - * Returns: true (1) if successful, false if video driver doesn't support - * viewport info. - **/ -bool video_driver_translate_coord_viewport( - struct video_viewport *vp, - int mouse_x, int mouse_y, - int16_t *res_x, int16_t *res_y, - int16_t *res_screen_x, int16_t *res_screen_y) -{ - int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y; - int norm_vp_width = (int)vp->width; - int norm_vp_height = (int)vp->height; - int norm_full_vp_width = (int)vp->full_width; - int norm_full_vp_height = (int)vp->full_height; - - if (norm_full_vp_width <= 0 || norm_full_vp_height <= 0) - return false; - - if (mouse_x >= 0 && mouse_x <= norm_full_vp_width) - scaled_screen_x = ((2 * mouse_x * 0x7fff) - / norm_full_vp_width) - 0x7fff; - else - scaled_screen_x = -0x8000; /* OOB */ - - if (mouse_y >= 0 && mouse_y <= norm_full_vp_height) - scaled_screen_y = ((2 * mouse_y * 0x7fff) - / norm_full_vp_height) - 0x7fff; - else - scaled_screen_y = -0x8000; /* OOB */ - - mouse_x -= vp->x; - mouse_y -= vp->y; - - if (mouse_x >= 0 && mouse_x <= norm_vp_width) - scaled_x = ((2 * mouse_x * 0x7fff) - / norm_vp_width) - 0x7fff; - else - scaled_x = -0x8000; /* OOB */ - - if (mouse_y >= 0 && mouse_y <= norm_vp_height) - scaled_y = ((2 * mouse_y * 0x7fff) - / norm_vp_height) - 0x7fff; - else - scaled_y = -0x8000; /* OOB */ - - *res_x = scaled_x; - *res_y = scaled_y; - *res_screen_x = scaled_screen_x; - *res_screen_y = scaled_screen_y; - - return true; -} - -void video_driver_get_window_title(char *buf, unsigned len) -{ - if (buf && video_driver_window_title_update) - { - strlcpy(buf, video_driver_window_title, len); - video_driver_window_title_update = false; - } -} - -void video_driver_get_status(uint64_t *frame_count, bool * is_alive, - bool *is_focused) -{ - *frame_count = video_driver_frame_count; - *is_alive = current_video ? - current_video->alive(video_driver_data) : true; - *is_focused = video_driver_cb_has_focus(); -} - -/** - * find_video_context_driver_driver_index: - * @ident : Identifier of resampler driver to find. - * - * Finds graphics context driver index by @ident name. - * - * Returns: graphics context driver index if driver was found, otherwise - * -1. - **/ -static int find_video_context_driver_index(const char *ident) -{ - unsigned i; - for (i = 0; gfx_ctx_drivers[i]; i++) - if (string_is_equal_noncase(ident, gfx_ctx_drivers[i]->ident)) - return i; - return -1; -} - -/** - * find_prev_context_driver: - * - * Finds previous driver in graphics context driver array. - **/ -bool video_context_driver_find_prev_driver(void) -{ - settings_t *settings = config_get_ptr(); - int i = find_video_context_driver_index( - settings->arrays.video_context_driver); - - if (i > 0) - { - strlcpy(settings->arrays.video_context_driver, - gfx_ctx_drivers[i - 1]->ident, - sizeof(settings->arrays.video_context_driver)); - return true; - } - - RARCH_WARN("Couldn't find any previous video context driver.\n"); - return false; -} - -/** - * find_next_context_driver: - * - * Finds next driver in graphics context driver array. - **/ -bool video_context_driver_find_next_driver(void) -{ - settings_t *settings = config_get_ptr(); - int i = find_video_context_driver_index( - settings->arrays.video_context_driver); - - if (i >= 0 && gfx_ctx_drivers[i + 1]) - { - strlcpy(settings->arrays.video_context_driver, - gfx_ctx_drivers[i + 1]->ident, - sizeof(settings->arrays.video_context_driver)); - return true; - } - - RARCH_WARN("Couldn't find any next video context driver.\n"); - return false; -} - -/** - * video_context_driver_init: - * @data : Input data. - * @ctx : Graphics context driver to initialize. - * @ident : Identifier of graphics context driver to find. - * @api : API of higher-level graphics API. - * @major : Major version number of higher-level graphics API. - * @minor : Minor version number of higher-level graphics API. - * @hw_render_ctx : Request a graphics context driver capable of - * hardware rendering? - * - * Initialize graphics context driver. - * - * Returns: graphics context driver if successfully initialized, - * otherwise NULL. - **/ -static const gfx_ctx_driver_t *video_context_driver_init( - void *data, - const gfx_ctx_driver_t *ctx, - const char *ident, - enum gfx_ctx_api api, unsigned major, - unsigned minor, bool hw_render_ctx, - void **ctx_data) -{ - video_frame_info_t video_info; - - if (!ctx->bind_api(data, api, major, minor)) - { - RARCH_WARN("Failed to bind API (#%u, version %u.%u)" - " on context driver \"%s\".\n", - (unsigned)api, major, minor, ctx->ident); - - return NULL; - } - - video_driver_build_info(&video_info); - - if (!(*ctx_data = ctx->init(&video_info, data))) - return NULL; - - if (ctx->bind_hw_render) - ctx->bind_hw_render(*ctx_data, - video_info.shared_context && hw_render_ctx); - - return ctx; -} - -/** - * video_context_driver_init_first: - * @data : Input data. - * @ident : Identifier of graphics context driver to find. - * @api : API of higher-level graphics API. - * @major : Major version number of higher-level graphics API. - * @minor : Minor version number of higher-level graphics API. - * @hw_render_ctx : Request a graphics context driver capable of - * hardware rendering? - * - * Finds first suitable graphics context driver and initializes. - * - * Returns: graphics context driver if found, otherwise NULL. - **/ -const gfx_ctx_driver_t *video_context_driver_init_first(void *data, - const char *ident, enum gfx_ctx_api api, unsigned major, - unsigned minor, bool hw_render_ctx, void **ctx_data) -{ - int i = find_video_context_driver_index(ident); - - if (i >= 0) - { - const gfx_ctx_driver_t *ctx = video_context_driver_init(data, gfx_ctx_drivers[i], ident, - api, major, minor, hw_render_ctx, ctx_data); - if (ctx) - { - video_context_data = *ctx_data; - return ctx; - } - } - - for (i = 0; gfx_ctx_drivers[i]; i++) - { - const gfx_ctx_driver_t *ctx = - video_context_driver_init(data, gfx_ctx_drivers[i], ident, - api, major, minor, hw_render_ctx, ctx_data); - - if (ctx) - { - video_context_data = *ctx_data; - return ctx; - } - } - - return NULL; -} - -bool video_context_driver_init_image_buffer(const video_info_t *data) -{ - if ( - current_video_context.image_buffer_init - && current_video_context.image_buffer_init( - video_context_data, data)) - return true; - return false; -} - -bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img) -{ - if ( - current_video_context.image_buffer_write - && current_video_context.image_buffer_write(video_context_data, - img->frame, img->width, img->height, img->pitch, - img->rgb32, img->index, img->handle)) - return true; - return false; -} - -bool video_context_driver_get_video_output_prev(void) -{ - if (!current_video_context.get_video_output_prev) - return false; - current_video_context.get_video_output_prev(video_context_data); - return true; -} - -bool video_context_driver_get_video_output_next(void) -{ - if (!current_video_context.get_video_output_next) - return false; - current_video_context.get_video_output_next(video_context_data); - return true; -} - -void video_context_driver_make_current(bool release) -{ - if (current_video_context.make_current) - current_video_context.make_current(release); -} - -bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect) -{ - if (!video_context_data || !aspect) - return false; - if (!current_video_context.translate_aspect) - return false; - *aspect->aspect = current_video_context.translate_aspect( - video_context_data, aspect->width, aspect->height); - return true; -} - -void video_context_driver_free(void) -{ - if (current_video_context.destroy) - current_video_context.destroy(video_context_data); - video_context_driver_destroy(); - video_context_data = NULL; -} - -bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data) -{ - if (!size_data) - return false; - if (!current_video_context.get_video_output_size) - return false; - current_video_context.get_video_output_size(video_context_data, - size_data->width, size_data->height); - return true; -} - -bool video_context_driver_swap_interval(int *interval) -{ - gfx_ctx_flags_t flags; - int current_interval = *interval; - settings_t *settings = config_get_ptr(); - bool adaptive_vsync_enabled = video_driver_get_all_flags(&flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && settings->bools.video_adaptive_vsync; - - if (!current_video_context.swap_interval) - return false; - if (adaptive_vsync_enabled && current_interval == 1) - current_interval = -1; - current_video_context.swap_interval(video_context_data, current_interval); - return true; -} - -bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc) -{ - if (!current_video_context.get_proc_address) - return false; - - proc->addr = current_video_context.get_proc_address(proc->sym); - - return true; -} - -bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics) -{ - if ( - current_video_context.get_metrics(video_context_data, - metrics->type, - metrics->value)) - return true; - return false; -} - -bool video_context_driver_get_refresh_rate(float *refresh_rate) -{ - float refresh_holder = 0; - - if (!current_video_context.get_refresh_rate || !refresh_rate) - return false; - if (!video_context_data) - return false; - - if (!video_driver_crt_switching_active) - if (refresh_rate) - *refresh_rate = - current_video_context.get_refresh_rate(video_context_data); - - if (video_driver_crt_switching_active) - { - if (refresh_rate) - refresh_holder = - current_video_context.get_refresh_rate(video_context_data); - if (refresh_holder != video_driver_core_hz) /* Fix for incorrect interlace detsction -- HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/ - *refresh_rate = video_driver_core_hz; - } - - return true; -} - -bool video_context_driver_input_driver(gfx_ctx_input_t *inp) -{ - settings_t *settings = config_get_ptr(); - const char *joypad_name = settings ? - settings->arrays.input_joypad_driver : NULL; - - if (!current_video_context.input_driver) - return false; - current_video_context.input_driver( - video_context_data, joypad_name, - inp->input, inp->input_data); - return true; -} - -bool video_context_driver_suppress_screensaver(bool *bool_data) -{ - if ( video_context_data - && current_video_context.suppress_screensaver( - video_context_data, *bool_data)) - return true; - return false; -} - -bool video_context_driver_get_ident(gfx_ctx_ident_t *ident) -{ - if (!ident) - return false; - ident->ident = current_video_context.ident; - return true; -} - -bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info) -{ - video_frame_info_t video_info; - - if (!current_video_context.set_video_mode) - return false; - - video_driver_build_info(&video_info); - - if (!current_video_context.set_video_mode( - video_context_data, &video_info, mode_info->width, - mode_info->height, mode_info->fullscreen)) - return false; - return true; -} - -bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info) -{ - if (!current_video_context.get_video_size) - return false; - current_video_context.get_video_size(video_context_data, - &mode_info->width, &mode_info->height); - return true; -} - -bool video_context_driver_show_mouse(bool *bool_data) -{ - if (!current_video_context.show_mouse) - return false; - current_video_context.show_mouse(video_context_data, *bool_data); - return true; -} - -static bool video_context_driver_get_flags(gfx_ctx_flags_t *flags) -{ - if (!current_video_context.get_flags) - return false; - - if (deferred_video_context_driver_set_flags) - { - flags->flags = deferred_flag_data.flags; - deferred_video_context_driver_set_flags = false; - return true; - } - - flags->flags = current_video_context.get_flags(video_context_data); - return true; -} - -static bool video_driver_get_flags(gfx_ctx_flags_t *flags) -{ - if (!video_driver_poke || !video_driver_poke->get_flags) - return false; - flags->flags = video_driver_poke->get_flags(video_driver_data); - return true; -} - -bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, enum display_flags flag) -{ - if (!flags) - return false; - - if (video_driver_get_flags(flags)) - if (BIT32_GET(flags->flags, flag)) - return true; - - flags->flags = 0; - - if (video_context_driver_get_flags(flags)) - if (BIT32_GET(flags->flags, flag)) - return true; - - return false; -} - -bool video_context_driver_set_flags(gfx_ctx_flags_t *flags) -{ - if (!flags) - return false; - if (!current_video_context.set_flags) - { - deferred_flag_data.flags = flags->flags; - deferred_video_context_driver_set_flags = true; - return false; - } - - current_video_context.set_flags(video_context_data, flags->flags); - return true; -} - -enum gfx_ctx_api video_context_driver_get_api(void) -{ - enum gfx_ctx_api ctx_api = video_context_data ? - current_video_context.get_api(video_context_data) : GFX_CTX_NONE; - - if (ctx_api == GFX_CTX_NONE) - { - const char *video_driver = video_driver_get_ident(); - if (string_is_equal(video_driver, "d3d9")) - return GFX_CTX_DIRECT3D9_API; - else if (string_is_equal(video_driver, "d3d10")) - return GFX_CTX_DIRECT3D10_API; - else if (string_is_equal(video_driver, "d3d11")) - return GFX_CTX_DIRECT3D11_API; - else if (string_is_equal(video_driver, "d3d12")) - return GFX_CTX_DIRECT3D12_API; - else if (string_is_equal(video_driver, "gx2")) - return GFX_CTX_GX2_API; - else if (string_is_equal(video_driver, "gx")) - return GFX_CTX_GX_API; - else if (string_is_equal(video_driver, "gl")) - return GFX_CTX_OPENGL_API; - else if (string_is_equal(video_driver, "vulkan")) - return GFX_CTX_VULKAN_API; - else if (string_is_equal(video_driver, "metal")) - return GFX_CTX_METAL_API; - - return GFX_CTX_NONE; - } - - return ctx_api; -} - -bool video_driver_has_windowed(void) -{ -#if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE)) - if (video_driver_data && current_video->has_windowed) - return current_video->has_windowed(video_driver_data); - else if (video_context_data && current_video_context.has_windowed) - return current_video_context.has_windowed(video_context_data); -#endif - return false; -} - -bool video_driver_cached_frame_has_valid_framebuffer(void) -{ - if (frame_cache_data) - return (frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID); - return false; -} - -static const shader_backend_t *video_shader_set_backend( - enum rarch_shader_type type) -{ - switch (type) - { - case RARCH_SHADER_CG: - { -#ifdef HAVE_CG - gfx_ctx_flags_t flags; - flags.flags = 0; - video_context_driver_get_flags(&flags); - - if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) - { - RARCH_ERR("[Shader driver]: Cg cannot be used with core" - " GL context. Trying to fall back to GLSL...\n"); - return video_shader_set_backend(RARCH_SHADER_GLSL); - } - - RARCH_LOG("[Shader driver]: Using Cg shader backend.\n"); - return &gl_cg_backend; -#else - break; -#endif - } - case RARCH_SHADER_GLSL: -#ifdef HAVE_GLSL - RARCH_LOG("[Shader driver]: Using GLSL shader backend.\n"); - return &gl_glsl_backend; -#else - break; -#endif - case RARCH_SHADER_HLSL: - case RARCH_SHADER_NONE: - default: - break; - } - - return NULL; -} - -void video_shader_driver_use(video_shader_ctx_info_t *shader_info) -{ - if (current_shader && current_shader->use) - current_shader->use(shader_info->data, current_shader_data, - shader_info->idx, shader_info->set_active); -} - -void video_shader_driver_set_parameter(struct uniform_info *param) -{ - if (current_shader && current_shader->set_uniform_parameter) - current_shader->set_uniform_parameter(current_shader_data, - param, NULL); -} - -void video_shader_driver_set_parameters(video_shader_ctx_params_t *params) -{ - if (current_shader && current_shader->set_params) - current_shader->set_params(params, current_shader_data); -} - -bool video_shader_driver_get_prev_textures( - video_shader_ctx_texture_t *texture) -{ - if (!texture || !current_shader) - return false; - texture->id = current_shader->get_prev_textures(current_shader_data); - - return true; -} - -bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident) -{ - if (!ident || !current_shader) - return false; - ident->ident = current_shader->ident; - return true; -} - -bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader) -{ - void *video_driver = video_driver_get_ptr(true); - const video_poke_interface_t *video_poke = video_driver_get_poke(); - - shader->data = NULL; - if (!video_poke || !video_driver || !video_poke->get_current_shader) - return false; - shader->data = video_poke->get_current_shader(video_driver); - return true; -} - -bool video_shader_driver_direct_get_current_shader( - video_shader_ctx_t *shader) -{ - if (!current_shader) - return false; - - shader->data = current_shader->get_current_shader(current_shader_data); - - return true; -} - -bool video_shader_driver_deinit(void) -{ - if (!current_shader) - return false; - - if (current_shader->deinit) - current_shader->deinit(current_shader_data); - - current_shader_data = NULL; - current_shader = NULL; - return true; -} - -static enum gfx_wrap_type video_shader_driver_wrap_type_null( - void *data, unsigned index) -{ - return RARCH_WRAP_BORDER; -} - -static bool video_driver_cb_set_mvp(void *data, - void *shader_data, const void *mat_data) -{ - video_shader_ctx_mvp_t mvp; - mvp.data = data; - mvp.matrix = mat_data; - - video_driver_set_mvp(&mvp); - return true; -} - -static struct video_shader * -video_shader_driver_get_current_shader_null(void *data) -{ - return NULL; -} - -static void video_shader_driver_set_params_null( - void *data, void *shader_data) -{ -} - -static void video_shader_driver_scale_null(void *data, - unsigned idx, struct gfx_fbo_scale *scale) -{ - (void)idx; - (void)scale; -} - -static bool video_shader_driver_mipmap_input_null( - void *data, unsigned idx) -{ - (void)idx; - return false; -} - -static bool video_shader_driver_filter_type_null( - void *data, unsigned idx, bool *smooth) -{ - (void)idx; - (void)smooth; - return false; -} - -static unsigned video_shader_driver_num_null(void *data) -{ - return 0; -} - -static bool video_shader_driver_get_feedback_pass_null( - void *data, unsigned *idx) -{ - (void)idx; - return false; -} - -static void video_shader_driver_reset_to_defaults(void) -{ - if (!current_shader) - return; - - if (!current_shader->wrap_type) - current_shader->wrap_type = video_shader_driver_wrap_type_null; - if (current_shader->set_mvp) - video_driver_cb_shader_set_mvp = current_shader->set_mvp; - else - { - current_shader->set_mvp = video_driver_cb_set_mvp; - video_driver_cb_shader_set_mvp = video_driver_cb_set_mvp; - } - if (!current_shader->set_coords) - current_shader->set_coords = video_driver_cb_set_coords; - - if (current_shader->use) - video_driver_cb_shader_use = current_shader->use; - else - { - current_shader->use = video_shader_driver_use_null; - video_driver_cb_shader_use = video_shader_driver_use_null; - } - if (!current_shader->set_params) - current_shader->set_params = video_shader_driver_set_params_null; - if (!current_shader->shader_scale) - current_shader->shader_scale = video_shader_driver_scale_null; - if (!current_shader->mipmap_input) - current_shader->mipmap_input = video_shader_driver_mipmap_input_null; - if (!current_shader->filter_type) - current_shader->filter_type = video_shader_driver_filter_type_null; - if (!current_shader->num_shaders) - current_shader->num_shaders = video_shader_driver_num_null; - if (!current_shader->get_current_shader) - current_shader->get_current_shader= video_shader_driver_get_current_shader_null; - if (!current_shader->get_feedback_pass) - current_shader->get_feedback_pass = video_shader_driver_get_feedback_pass_null; -} - -/* Finds first suitable shader context driver. */ -bool video_shader_driver_init_first(void) -{ - current_shader = (shader_backend_t*)shader_ctx_drivers[0]; - video_shader_driver_reset_to_defaults(); - return true; -} - -bool video_shader_driver_init(video_shader_ctx_init_t *init) -{ - void *tmp = NULL; - settings_t *settings = config_get_ptr(); - - if (!init->shader || !init->shader->init) - { - init->shader = video_shader_set_backend(init->shader_type); - - if (!init->shader) - return false; - } - - tmp = init->shader->init(init->data, init->path); - - if (!tmp) - return false; - - if (string_is_equal(settings->arrays.menu_driver, "xmb") - && init->shader->init_menu_shaders) - { - RARCH_LOG("Setting up menu pipeline shaders for XMB ... \n"); - init->shader->init_menu_shaders(tmp); - } - - current_shader_data = tmp; - - RARCH_LOG("Resetting shader to defaults ... \n"); - - current_shader = (shader_backend_t*)init->shader; - video_shader_driver_reset_to_defaults(); - - return true; -} - -bool video_shader_driver_get_feedback_pass(unsigned *data) -{ - return current_shader->get_feedback_pass(current_shader_data, data); -} - -bool video_shader_driver_mipmap_input(unsigned *index) -{ - return current_shader->mipmap_input(current_shader_data, *index); -} - -bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler) -{ - if (!scaler || !scaler->scale) - return false; - - scaler->scale->valid = false; - - current_shader->shader_scale(current_shader_data, - scaler->idx, scaler->scale); - return true; -} - -bool video_shader_driver_info(video_shader_ctx_info_t *shader_info) -{ - if (!shader_info) - return false; - - shader_info->num = current_shader->num_shaders(current_shader_data); - - return true; -} - -bool video_shader_driver_filter_type(video_shader_ctx_filter_t *filter) -{ - if (filter) - return current_shader->filter_type(current_shader_data, - filter->index, filter->smooth); - return false; -} - -bool video_shader_driver_compile_program( - struct shader_program_info *program_info) -{ - if (program_info) - return current_shader->compile_program(program_info->data, - program_info->idx, NULL, program_info); - return false; -} - -bool video_shader_driver_wrap_type(video_shader_ctx_wrap_t *wrap) -{ - wrap->type = current_shader->wrap_type( - current_shader_data, wrap->idx); - return true; -} - -void video_driver_set_coords(video_shader_ctx_coords_t *coords) -{ - if (current_shader && current_shader->set_coords) - current_shader->set_coords(coords->handle_data, - current_shader_data, - (const struct video_coords*)coords->data); - else - { - if (video_driver_poke && video_driver_poke->set_coords) - video_driver_poke->set_coords(coords->handle_data, - current_shader_data, - (const struct video_coords*)coords->data); - } -} - -void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp) -{ - if (!mvp || !mvp->matrix) - return; - - if (current_shader && current_shader->set_mvp) - current_shader->set_mvp(mvp->data, - current_shader_data, mvp->matrix); - else - { - if (video_driver_poke && video_driver_poke->set_mvp) - video_driver_poke->set_mvp(mvp->data, - current_shader_data, mvp->matrix); - } -} - -float video_driver_get_refresh_rate(void) -{ - if (video_driver_poke && video_driver_poke->get_refresh_rate) - return video_driver_poke->get_refresh_rate(video_driver_data); - - return 0.0f; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../audio/audio_driver.h" +#include "../menu/menu_shader.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#include "../dynamic.h" + +#ifdef HAVE_THREADS +#include +#endif + +#ifdef HAVE_MENU +#include "../menu/menu_driver.h" +#include "../menu/menu_setting.h" +#endif + +#include "video_thread_wrapper.h" +#include "video_driver.h" +#include "video_display_server.h" +#include "video_crt_switch.h" + +#include "../frontend/frontend_driver.h" +#include "../record/record_driver.h" +#include "../config.def.h" +#include "../configuration.h" +#include "../driver.h" +#include "../retroarch.h" +#include "../input/input_driver.h" +#include "../list_special.h" +#include "../core.h" +#include "../command.h" +#include "../msg_hash.h" +#include "../verbosity.h" + +#define MEASURE_FRAME_TIME_SAMPLES_COUNT (2 * 1024) + +#define TIME_TO_FPS(last_time, new_time, frames) ((1000000.0f * (frames)) / ((new_time) - (last_time))) + +#define FPS_UPDATE_INTERVAL 256 + +#ifdef HAVE_THREADS +#define video_driver_is_threaded_internal() ((!video_driver_is_hw_context() && video_driver_threaded) ? true : false) +#else +#define video_driver_is_threaded_internal() (false) +#endif + +#ifdef HAVE_THREADS +#define video_driver_lock() \ + if (display_lock) \ + slock_lock(display_lock) + +#define video_driver_unlock() \ + if (display_lock) \ + slock_unlock(display_lock) + +#define video_driver_context_lock() \ + if (context_lock) \ + slock_lock(context_lock) + +#define video_driver_context_unlock() \ + if (context_lock) \ + slock_unlock(context_lock) + +#define video_driver_lock_free() \ + slock_free(display_lock); \ + slock_free(context_lock); \ + display_lock = NULL; \ + context_lock = NULL + +#define video_driver_threaded_lock(is_threaded) \ + if (is_threaded) \ + video_driver_lock() + +#define video_driver_threaded_unlock(is_threaded) \ + if (is_threaded) \ + video_driver_unlock() +#else +#define video_driver_lock() ((void)0) +#define video_driver_unlock() ((void)0) +#define video_driver_lock_free() ((void)0) +#define video_driver_threaded_lock(is_threaded) ((void)0) +#define video_driver_threaded_unlock(is_threaded) ((void)0) +#define video_driver_context_lock() ((void)0) +#define video_driver_context_unlock() ((void)0) +#endif + +typedef struct video_pixel_scaler +{ + struct scaler_ctx *scaler; + void *scaler_out; +} video_pixel_scaler_t; + +static void (*video_driver_cb_shader_use)(void *data, + void *shader_data, unsigned index, bool set_active); +static bool (*video_driver_cb_shader_set_mvp)(void *data, + void *shader_data, const void *mat_data); +bool (*video_driver_cb_has_focus)(void); + +/* Opaque handles to currently running window. + * Used by e.g. input drivers which bind to a window. + * Drivers are responsible for setting these if an input driver + * could potentially make use of this. */ +static uintptr_t video_driver_display = 0; +static uintptr_t video_driver_window = 0; + +static rarch_softfilter_t *video_driver_state_filter = NULL; +static void *video_driver_state_buffer = NULL; +static unsigned video_driver_state_scale = 0; +static unsigned video_driver_state_out_bpp = 0; +static bool video_driver_state_out_rgb32 = false; +static bool video_driver_crt_switching_active = false; + +static struct retro_system_av_info video_driver_av_info; + +static enum retro_pixel_format video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555; + +static const void *frame_cache_data = NULL; +static unsigned frame_cache_width = 0; +static unsigned frame_cache_height = 0; +static size_t frame_cache_pitch = 0; +static bool video_driver_threaded = false; + +static float video_driver_core_hz = 0.0f; +static float video_driver_aspect_ratio = 0.0f; +static unsigned video_driver_width = 0; +static unsigned video_driver_height = 0; + +static enum rarch_display_type video_driver_display_type = RARCH_DISPLAY_NONE; +static char video_driver_title_buf[64] = {0}; +static char video_driver_window_title[512] = {0}; +static bool video_driver_window_title_update = true; + +static retro_time_t video_driver_frame_time_samples[MEASURE_FRAME_TIME_SAMPLES_COUNT]; +static uint64_t video_driver_frame_time_count = 0; +static uint64_t video_driver_frame_count = 0; + +static void *video_driver_data = NULL; +static video_driver_t *current_video = NULL; + +/* Interface for "poking". */ +static const video_poke_interface_t *video_driver_poke = NULL; + +/* Used for 15-bit -> 16-bit conversions that take place before + * being passed to video driver. */ +static video_pixel_scaler_t *video_driver_scaler_ptr = NULL; + +static struct retro_hw_render_callback hw_render; + +static const struct +retro_hw_render_context_negotiation_interface * +hw_render_context_negotiation = NULL; + +/* Graphics driver requires RGBA byte order data (ABGR on little-endian) + * for 32-bit. + * This takes effect for overlay and shader cores that wants to load + * data into graphics driver. Kinda hackish to place it here, it is only + * used for GLES. + * TODO: Refactor this better. */ +static bool video_driver_use_rgba = false; +static bool video_driver_data_own = false; +static bool video_driver_active = false; + +static video_driver_frame_t frame_bak = NULL; + +/* If set during context deinit, the driver should keep + * graphics context alive to avoid having to reset all + * context state. */ +static bool video_driver_cache_context = false; + +/* Set to true by driver if context caching succeeded. */ +static bool video_driver_cache_context_ack = false; +static uint8_t *video_driver_record_gpu_buffer = NULL; + +#ifdef HAVE_THREADS +static slock_t *display_lock = NULL; +static slock_t *context_lock = NULL; +#endif + +static gfx_ctx_driver_t current_video_context; + +static void *video_context_data = NULL; + +/** + * dynamic.c:dynamic_request_hw_context will try to set flag data when the context + * is in the middle of being rebuilt; in these cases we will save flag + * data and set this to true. + * When the context is reinit, it checks this, reads from + * deferred_flag_data and cleans it. + * + * TODO - Dirty hack, fix it better + */ +static bool deferred_video_context_driver_set_flags = false; +static gfx_ctx_flags_t deferred_flag_data = {0}; + +static bool video_started_fullscreen = false; + +static shader_backend_t *current_shader = NULL; +static void *current_shader_data = NULL; + +struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { + { "4:3", 1.3333f }, + { "16:9", 1.7778f }, + { "16:10", 1.6f }, + { "16:15", 16.0f / 15.0f }, + { "21:9", 21.0f / 9.0f }, + { "1:1", 1.0f }, + { "2:1", 2.0f }, + { "3:2", 1.5f }, + { "3:4", 0.75f }, + { "4:1", 4.0f }, + { "9:16", 0.5625f }, + { "5:4", 1.25f }, + { "6:5", 1.2f }, + { "7:9", 0.7777f }, + { "8:3", 2.6666f }, + { "8:7", 1.1428f }, + { "19:12", 1.5833f }, + { "19:14", 1.3571f }, + { "30:17", 1.7647f }, + { "32:9", 3.5555f }, + { "Config", 0.0f }, + { "Square pixel", 1.0f }, + { "Core provided", 1.0f }, + { "Custom", 0.0f } +}; + +static const video_driver_t *video_drivers[] = { +#ifdef HAVE_OPENGL + &video_gl, +#endif +#ifdef HAVE_VULKAN + &video_vulkan, +#endif +#ifdef HAVE_METAL + &video_metal, +#endif +#ifdef XENON + &video_xenon360, +#endif +#if defined(HAVE_D3D12) + &video_d3d12, +#endif +#if defined(HAVE_D3D11) + &video_d3d11, +#endif +#if defined(HAVE_D3D10) + &video_d3d10, +#endif +#if defined(HAVE_D3D9) + &video_d3d9, +#endif +#if defined(HAVE_D3D8) + &video_d3d8, +#endif +#ifdef HAVE_VITA2D + &video_vita2d, +#endif +#ifdef PSP + &video_psp1, +#endif +#ifdef PS2 + &video_ps2, +#endif +#ifdef _3DS + &video_ctr, +#endif +#ifdef SWITCH + &video_switch, +#endif +#ifdef HAVE_SDL + &video_sdl, +#endif +#ifdef HAVE_SDL2 + &video_sdl2, +#endif +#ifdef HAVE_XVIDEO + &video_xvideo, +#endif +#ifdef GEKKO + &video_gx, +#endif +#ifdef WIIU + &video_wiiu, +#endif +#ifdef HAVE_VG + &video_vg, +#endif +#ifdef HAVE_OMAP + &video_omap, +#endif +#ifdef HAVE_EXYNOS + &video_exynos, +#endif +#ifdef HAVE_DISPMANX + &video_dispmanx, +#endif +#ifdef HAVE_SUNXI + &video_sunxi, +#endif +#ifdef HAVE_PLAIN_DRM + &video_drm, +#endif +#ifdef HAVE_XSHM + &video_xshm, +#endif +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) + &video_gdi, +#endif +#ifdef DJGPP + &video_vga, +#endif +#ifdef HAVE_SIXEL + &video_sixel, +#endif +#ifdef HAVE_CACA + &video_caca, +#endif + &video_null, + NULL, +}; + +static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { +#if defined(ORBIS) + &orbis_ctx, +#endif +#if defined(HAVE_LIBNX) && defined(HAVE_OPENGL) + &switch_ctx, +#endif +#if defined(__CELLOS_LV2__) + &gfx_ctx_ps3, +#endif +#if defined(HAVE_VIDEOCORE) + &gfx_ctx_videocore, +#endif +#if defined(HAVE_MALI_FBDEV) + &gfx_ctx_mali_fbdev, +#endif +#if defined(HAVE_VIVANTE_FBDEV) + &gfx_ctx_vivante_fbdev, +#endif +#if defined(HAVE_OPENDINGUX_FBDEV) + &gfx_ctx_opendingux_fbdev, +#endif +#if defined(_WIN32) && (defined(HAVE_OPENGL) || defined(HAVE_VULKAN)) + &gfx_ctx_wgl, +#endif +#if defined(HAVE_WAYLAND) + &gfx_ctx_wayland, +#endif +#if defined(HAVE_X11) && !defined(HAVE_OPENGLES) +#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) + &gfx_ctx_x, +#endif +#endif +#if defined(HAVE_X11) && defined(HAVE_OPENGL) && defined(HAVE_EGL) + &gfx_ctx_x_egl, +#endif +#if defined(HAVE_KMS) + &gfx_ctx_drm, +#endif +#if defined(ANDROID) + &gfx_ctx_android, +#endif +#if defined(__QNX__) + &gfx_ctx_qnx, +#endif +#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) + &gfx_ctx_cocoagl, +#endif +#if defined(__APPLE__) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE) + &gfx_ctx_cgl, +#endif +#if (defined(HAVE_SDL) || defined(HAVE_SDL2)) && defined(HAVE_OPENGL) + &gfx_ctx_sdl_gl, +#endif +#ifdef HAVE_OSMESA + &gfx_ctx_osmesa, +#endif +#ifdef EMSCRIPTEN + &gfx_ctx_emscripten, +#endif +#if defined(HAVE_VULKAN) && defined(HAVE_VULKAN_DISPLAY) + &gfx_ctx_khr_display, +#endif +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) + &gfx_ctx_gdi, +#endif +#ifdef HAVE_SIXEL + &gfx_ctx_sixel, +#endif + &gfx_ctx_null, + NULL +}; + +static const shader_backend_t *shader_ctx_drivers[] = { +#ifdef HAVE_GLSL + &gl_glsl_backend, +#endif +#ifdef HAVE_CG + &gl_cg_backend, +#endif + &shader_null_backend, + NULL +}; + +bool video_driver_started_fullscreen(void) +{ + return video_started_fullscreen; +} + +/* Stub functions */ + +static void update_window_title_null(void *data, void *data2) +{ +} + +static void swap_buffers_null(void *data, void *data2) +{ +} + +static bool get_metrics_null(void *data, enum display_metric_types type, + float *value) +{ + return false; +} + +static bool set_resize_null(void *a, unsigned b, unsigned c) +{ + return false; +} + +/** + * video_driver_find_handle: + * @idx : index of driver to get handle to. + * + * Returns: handle to video driver at index. Can be NULL + * if nothing found. + **/ +const void *video_driver_find_handle(int idx) +{ + const void *drv = video_drivers[idx]; + if (!drv) + return NULL; + return drv; +} + +/** + * video_driver_find_ident: + * @idx : index of driver to get handle to. + * + * Returns: Human-readable identifier of video driver at index. Can be NULL + * if nothing found. + **/ +const char *video_driver_find_ident(int idx) +{ + const video_driver_t *drv = video_drivers[idx]; + if (!drv) + return NULL; + return drv->ident; +} + +/** + * config_get_video_driver_options: + * + * Get an enumerated list of all video driver names, separated by '|'. + * + * Returns: string listing of all video driver names, separated by '|'. + **/ +const char* config_get_video_driver_options(void) +{ + return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL); +} + +bool video_driver_is_threaded(void) +{ + return video_driver_is_threaded_internal(); +} + +#ifdef HAVE_VULKAN +static bool hw_render_context_is_vulkan(enum retro_hw_context_type type) +{ + return type == RETRO_HW_CONTEXT_VULKAN; +} +#endif + +#if defined(HAVE_OPENGL) +static bool hw_render_context_is_gl(enum retro_hw_context_type type) +{ + switch (type) + { + case RETRO_HW_CONTEXT_OPENGL: + case RETRO_HW_CONTEXT_OPENGLES2: + case RETRO_HW_CONTEXT_OPENGL_CORE: + case RETRO_HW_CONTEXT_OPENGLES3: + case RETRO_HW_CONTEXT_OPENGLES_VERSION: + return true; + default: + break; + } + + return false; +} +#endif + +bool *video_driver_get_threaded(void) +{ + return &video_driver_threaded; +} + +void video_driver_set_threaded(bool val) +{ + video_driver_threaded = val; +} + +/** + * video_driver_get_ptr: + * + * Use this if you need the real video driver + * and driver data pointers. + * + * Returns: video driver's userdata. + **/ +void *video_driver_get_ptr(bool force_nonthreaded_data) +{ +#ifdef HAVE_THREADS + if (video_driver_is_threaded_internal() && !force_nonthreaded_data) + return video_thread_get_ptr(NULL); +#endif + + return video_driver_data; +} + +const char *video_driver_get_ident(void) +{ + return (current_video) ? current_video->ident : NULL; +} + +const video_poke_interface_t *video_driver_get_poke(void) +{ + return video_driver_poke; +} + +static bool video_context_has_focus(void) +{ + return current_video_context.has_focus && current_video_context.has_focus(video_context_data); +} + +static bool video_driver_has_focus(void) +{ + return current_video && current_video->focus && current_video->focus(video_driver_data); +} + +static bool null_driver_has_focus(void) +{ + return true; +} + +static void video_context_driver_reset(void) +{ + if (!current_video_context.get_metrics) + current_video_context.get_metrics = get_metrics_null; + + if (!current_video_context.update_window_title) + current_video_context.update_window_title = update_window_title_null; + + if (!current_video_context.set_resize) + current_video_context.set_resize = set_resize_null; + + if (!current_video_context.swap_buffers) + current_video_context.swap_buffers = swap_buffers_null; + + if (current_video_context.has_focus) + video_driver_cb_has_focus = video_context_has_focus; + +} + +bool video_context_driver_set(const gfx_ctx_driver_t *data) +{ + if (!data) + return false; + current_video_context = *data; + video_context_driver_reset(); + return true; +} + +void video_context_driver_destroy(void) +{ + current_video_context.init = NULL; + current_video_context.bind_api = NULL; + current_video_context.swap_interval = NULL; + current_video_context.set_video_mode = NULL; + current_video_context.get_video_size = NULL; + current_video_context.get_video_output_size = NULL; + current_video_context.get_video_output_prev = NULL; + current_video_context.get_video_output_next = NULL; + current_video_context.get_metrics = get_metrics_null; + current_video_context.translate_aspect = NULL; + current_video_context.update_window_title = update_window_title_null; + current_video_context.check_window = NULL; + current_video_context.set_resize = set_resize_null; + current_video_context.has_focus = NULL; + current_video_context.suppress_screensaver = NULL; + current_video_context.has_windowed = NULL; + current_video_context.swap_buffers = swap_buffers_null; + current_video_context.input_driver = NULL; + current_video_context.get_proc_address = NULL; + current_video_context.image_buffer_init = NULL; + current_video_context.image_buffer_write = NULL; + current_video_context.show_mouse = NULL; + current_video_context.ident = NULL; + current_video_context.get_flags = NULL; + current_video_context.set_flags = NULL; + current_video_context.bind_hw_render = NULL; + current_video_context.get_context_data = NULL; + current_video_context.make_current = NULL; +} + +/** + * video_driver_get_current_framebuffer: + * + * Gets pointer to current hardware renderer framebuffer object. + * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. + * + * Returns: pointer to hardware framebuffer object, otherwise 0. + **/ +uintptr_t video_driver_get_current_framebuffer(void) +{ + if (video_driver_poke && video_driver_poke->get_current_framebuffer) + return video_driver_poke->get_current_framebuffer(video_driver_data); + return 0; +} + +retro_proc_address_t video_driver_get_proc_address(const char *sym) +{ + if (video_driver_poke && video_driver_poke->get_proc_address) + return video_driver_poke->get_proc_address(video_driver_data, sym); + return NULL; +} + +bool video_driver_set_shader(enum rarch_shader_type type, + const char *path) +{ + if (current_video->set_shader) + return current_video->set_shader(video_driver_data, type, path); + return false; +} + +static void video_driver_filter_free(void) +{ + if (video_driver_state_filter) + rarch_softfilter_free(video_driver_state_filter); + video_driver_state_filter = NULL; + + if (video_driver_state_buffer) + { +#ifdef _3DS + linearFree(video_driver_state_buffer); +#else + free(video_driver_state_buffer); +#endif + } + video_driver_state_buffer = NULL; + + video_driver_state_scale = 0; + video_driver_state_out_bpp = 0; + video_driver_state_out_rgb32 = false; +} + +static void video_driver_init_filter(enum retro_pixel_format colfmt_int) +{ + unsigned pow2_x, pow2_y, maxsize; + void *buf = NULL; + settings_t *settings = config_get_ptr(); + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + unsigned width = geom->max_width; + unsigned height = geom->max_height; + /* Deprecated format. Gets pre-converted. */ + enum retro_pixel_format colfmt = + (colfmt_int == RETRO_PIXEL_FORMAT_0RGB1555) ? + RETRO_PIXEL_FORMAT_RGB565 : colfmt_int; + + if (video_driver_is_hw_context()) + { + RARCH_WARN("Cannot use CPU filters when hardware rendering is used.\n"); + return; + } + + video_driver_state_filter = rarch_softfilter_new( + settings->paths.path_softfilter_plugin, + RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height); + + if (!video_driver_state_filter) + { + RARCH_ERR("[Video]: Failed to load filter.\n"); + return; + } + + rarch_softfilter_get_max_output_size(video_driver_state_filter, + &width, &height); + + pow2_x = next_pow2(width); + pow2_y = next_pow2(height); + maxsize = MAX(pow2_x, pow2_y); + video_driver_state_scale = maxsize / RARCH_SCALE_BASE; + video_driver_state_out_rgb32 = rarch_softfilter_get_output_format( + video_driver_state_filter) == + RETRO_PIXEL_FORMAT_XRGB8888; + + video_driver_state_out_bpp = video_driver_state_out_rgb32 ? + sizeof(uint32_t) : + sizeof(uint16_t); + + /* TODO: Aligned output. */ +#ifdef _3DS + buf = linearMemAlign( + width * height * video_driver_state_out_bpp, 0x80); +#else + buf = malloc( + width * height * video_driver_state_out_bpp); +#endif + if (!buf) + { + RARCH_ERR("[Video]: Softfilter initialization failed.\n"); + video_driver_filter_free(); + return; + } + + video_driver_state_buffer = buf; +} + +static void video_driver_init_input(const input_driver_t *tmp) +{ + const input_driver_t **input = input_get_double_ptr(); + if (*input) + return; + + /* Video driver didn't provide an input driver, + * so we use configured one. */ + RARCH_LOG("[Video]: Graphics driver did not initialize an input driver." + " Attempting to pick a suitable driver.\n"); + + if (tmp) + *input = tmp; + else + input_driver_find_driver(); + + /* This should never really happen as tmp (driver.input) is always + * found before this in find_driver_input(), or we have aborted + * in a similar fashion anyways. */ + if (!input_get_ptr()) + goto error; + + if (input_driver_init()) + return; + +error: + RARCH_ERR("[Video]: Cannot initialize input driver. Exiting ...\n"); + retroarch_fail(1, "video_driver_init_input()"); +} + +/** + * video_driver_monitor_compute_fps_statistics: + * + * Computes monitor FPS statistics. + **/ +static void video_driver_monitor_compute_fps_statistics(void) +{ + double avg_fps = 0.0; + double stddev = 0.0; + unsigned samples = 0; + + if (video_driver_frame_time_count < + (2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)) + { + RARCH_LOG( + "[Video]: Does not have enough samples for monitor refresh rate" + " estimation. Requires to run for at least %u frames.\n", + 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT); + return; + } + + if (video_monitor_fps_statistics(&avg_fps, &stddev, &samples)) + { + RARCH_LOG("[Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time" + " deviation, based on %u last samples).\n", + avg_fps, 100.0 * stddev, samples); + } +} + +static void video_driver_pixel_converter_free(void) +{ + if (!video_driver_scaler_ptr) + return; + + scaler_ctx_gen_reset(video_driver_scaler_ptr->scaler); + + if (video_driver_scaler_ptr->scaler) + free(video_driver_scaler_ptr->scaler); + video_driver_scaler_ptr->scaler = NULL; + + if (video_driver_scaler_ptr->scaler_out) + free(video_driver_scaler_ptr->scaler_out); + video_driver_scaler_ptr->scaler_out = NULL; + + if (video_driver_scaler_ptr) + free(video_driver_scaler_ptr); + video_driver_scaler_ptr = NULL; +} + +static void video_driver_free_internal(void) +{ +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); +#endif + + command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); + + if (!video_driver_is_video_cache_context()) + video_driver_free_hw_context(); + + if ( + !input_driver_owns_driver() && + !input_driver_is_data_ptr_same(video_driver_data) + ) + input_driver_deinit(); + + if ( + !video_driver_data_own + && video_driver_data + && current_video && current_video->free + ) + current_video->free(video_driver_data); + + video_driver_pixel_converter_free(); + video_driver_filter_free(); + + command_event(CMD_EVENT_SHADER_DIR_DEINIT, NULL); + +#ifdef HAVE_THREADS + if (is_threaded) + return; +#endif + + video_driver_monitor_compute_fps_statistics(); +} + +static bool video_driver_pixel_converter_init(unsigned size) +{ + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); + void *scalr_out = NULL; + video_pixel_scaler_t *scalr = NULL; + struct scaler_ctx *scalr_ctx = NULL; + + /* If pixel format is not 0RGB1555, we don't need to do + * any internal pixel conversion. */ + if (video_driver_pix_fmt != RETRO_PIXEL_FORMAT_0RGB1555) + return true; + + /* No need to perform pixel conversion for HW rendering contexts. */ + if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) + return true; + + RARCH_WARN("0RGB1555 pixel format is deprecated," + " and will be slower. For 15/16-bit, RGB565" + " format is preferred.\n"); + + scalr = (video_pixel_scaler_t*)calloc(1, sizeof(*scalr)); + + if (!scalr) + goto error; + + video_driver_scaler_ptr = scalr; + + scalr_ctx = (struct scaler_ctx*)calloc(1, sizeof(*scalr_ctx)); + + if (!scalr_ctx) + goto error; + + video_driver_scaler_ptr->scaler = scalr_ctx; + video_driver_scaler_ptr->scaler->scaler_type = SCALER_TYPE_POINT; + video_driver_scaler_ptr->scaler->in_fmt = SCALER_FMT_0RGB1555; + + /* TODO: Pick either ARGB8888 or RGB565 depending on driver. */ + video_driver_scaler_ptr->scaler->out_fmt = SCALER_FMT_RGB565; + + if (!scaler_ctx_gen_filter(scalr_ctx)) + goto error; + + scalr_out = calloc(sizeof(uint16_t), size * size); + + if (!scalr_out) + goto error; + + video_driver_scaler_ptr->scaler_out = scalr_out; + + return true; + +error: + video_driver_pixel_converter_free(); + video_driver_filter_free(); + + return false; +} + +static bool video_driver_init_internal(bool *video_is_threaded) +{ + video_info_t video; + unsigned max_dim, scale, width, height; + video_viewport_t *custom_vp = NULL; + const input_driver_t *tmp = NULL; + rarch_system_info_t *system = NULL; + static uint16_t dummy_pixels[32] = {0}; + settings_t *settings = config_get_ptr(); + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + + if (!string_is_empty(settings->paths.path_softfilter_plugin)) + video_driver_init_filter(video_driver_pix_fmt); + + max_dim = MAX(geom->max_width, geom->max_height); + scale = next_pow2(max_dim) / RARCH_SCALE_BASE; + scale = MAX(scale, 1); + + if (video_driver_state_filter) + scale = video_driver_state_scale; + + /* Update core-dependent aspect ratio values. */ + video_driver_set_viewport_square_pixel(); + video_driver_set_viewport_core(); + video_driver_set_viewport_config(); + + /* Update CUSTOM viewport. */ + custom_vp = video_viewport_get_custom(); + + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; + aspectratio_lut[ASPECT_RATIO_CUSTOM].value = + (custom_vp->width && custom_vp->height) ? + (float)custom_vp->width / custom_vp->height : default_aspect; + } + + video_driver_set_aspect_ratio_value( + aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); + + if (settings->bools.video_fullscreen|| retroarch_is_forced_fullscreen()) + { + width = settings->uints.video_fullscreen_x; + height = settings->uints.video_fullscreen_y; + } + else + { + /* To-Do: remove when the new window resizing core is hooked */ + if (settings->bools.video_window_save_positions && + (settings->uints.window_position_width || settings->uints.window_position_height)) + { + width = settings->uints.window_position_width; + height = settings->uints.window_position_height; + } + else + { + if (settings->bools.video_force_aspect) + { + /* Do rounding here to simplify integer scale correctness. */ + unsigned base_width = + roundf(geom->base_height * video_driver_get_aspect_ratio()); + width = roundf(base_width * settings->floats.video_scale); + } + else + width = roundf(geom->base_width * settings->floats.video_scale); + height = roundf(geom->base_height * settings->floats.video_scale); +} + } + + if (width && height) + RARCH_LOG("[Video]: Video @ %ux%u\n", width, height); + else + RARCH_LOG("[Video]: Video @ fullscreen\n"); + + video_driver_display_type_set(RARCH_DISPLAY_NONE); + video_driver_display_set(0); + video_driver_window_set(0); + + if (!video_driver_pixel_converter_init(RARCH_SCALE_BASE * scale)) + { + RARCH_ERR("[Video]: Failed to initialize pixel converter.\n"); + goto error; + } + + video.width = width; + video.height = height; + video.fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); + video.vsync = settings->bools.video_vsync && !rarch_ctl(RARCH_CTL_IS_NONBLOCK_FORCED, NULL); + video.force_aspect = settings->bools.video_force_aspect; + video.font_enable = settings->bools.video_font_enable; + video.swap_interval = settings->uints.video_swap_interval; +#ifdef GEKKO + video.viwidth = settings->uints.video_viwidth; + video.vfilter = settings->bools.video_vfilter; +#endif + video.smooth = settings->bools.video_smooth; + video.input_scale = scale; + video.rgb32 = video_driver_state_filter ? + video_driver_state_out_rgb32 : + (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); + video.parent = 0; + + video_started_fullscreen = video.fullscreen; + + /* Reset video frame count */ + video_driver_frame_count = 0; + + tmp = input_get_ptr(); + /* Need to grab the "real" video driver interface on a reinit. */ + video_driver_find_driver(); + +#ifdef HAVE_THREADS + video.is_threaded = video_driver_is_threaded_internal(); + *video_is_threaded = video.is_threaded; + + if (video.is_threaded) + { + /* Can't do hardware rendering with threaded driver currently. */ + RARCH_LOG("[Video]: Starting threaded video driver ...\n"); + + if (!video_init_thread((const video_driver_t**)¤t_video, + &video_driver_data, + input_get_double_ptr(), input_driver_get_data_ptr(), + current_video, video)) + { + RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n"); + goto error; + } + } + else +#endif + video_driver_data = current_video->init( + &video, input_get_double_ptr(), + input_driver_get_data_ptr()); + + if (!video_driver_data) + { + RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n"); + goto error; + } + + if (current_video->focus) + video_driver_cb_has_focus = video_driver_has_focus; + + video_driver_poke = NULL; + if (current_video->poke_interface) + current_video->poke_interface(video_driver_data, &video_driver_poke); + + if (current_video->viewport_info && + (!custom_vp->width || + !custom_vp->height)) + { + /* Force custom viewport to have sane parameters. */ + custom_vp->width = width; + custom_vp->height = height; + + video_driver_get_viewport_info(custom_vp); + } + + system = runloop_get_system_info(); + + video_driver_set_rotation( + (settings->uints.video_rotation + system->rotation) % 4); + + current_video->suppress_screensaver(video_driver_data, + settings->bools.ui_suspend_screensaver_enable); + + video_driver_init_input(tmp); + + command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); + command_event(CMD_EVENT_OVERLAY_INIT, NULL); + + if (!core_is_game_loaded()) + video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8); + +#if defined(PSP) + video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f); +#endif + + video_context_driver_reset(); + + video_display_server_init(); + + command_event(CMD_EVENT_SHADER_DIR_INIT, NULL); + + return true; + +error: + retroarch_fail(1, "init_video()"); + return false; +} + +bool video_driver_set_viewport(unsigned width, unsigned height, + bool force_fullscreen, bool allow_rotate) +{ + if (!current_video || !current_video->set_viewport) + return false; + current_video->set_viewport(video_driver_data, width, height, + force_fullscreen, allow_rotate); + return true; +} + +bool video_driver_set_rotation(unsigned rotation) +{ + if (!current_video || !current_video->set_rotation) + return false; + current_video->set_rotation(video_driver_data, rotation); + return true; +} + +bool video_driver_set_video_mode(unsigned width, + unsigned height, bool fullscreen) +{ + gfx_ctx_mode_t mode; + + if (video_driver_poke && video_driver_poke->set_video_mode) + { + video_driver_poke->set_video_mode(video_driver_data, + width, height, fullscreen); + return true; + } + + mode.width = width; + mode.height = height; + mode.fullscreen = fullscreen; + + return video_context_driver_set_video_mode(&mode); +} + +bool video_driver_get_video_output_size(unsigned *width, unsigned *height) +{ + if (!video_driver_poke || !video_driver_poke->get_video_output_size) + return false; + video_driver_poke->get_video_output_size(video_driver_data, + width, height); + return true; +} + +void video_driver_set_osd_msg(const char *msg, const void *data, void *font) +{ + video_frame_info_t video_info; + video_driver_build_info(&video_info); + if (video_driver_poke && video_driver_poke->set_osd_msg) + video_driver_poke->set_osd_msg(video_driver_data, &video_info, msg, data, font); +} + +void video_driver_set_texture_enable(bool enable, bool fullscreen) +{ + if (video_driver_poke && video_driver_poke->set_texture_enable) + video_driver_poke->set_texture_enable(video_driver_data, + enable, fullscreen); +} + +void video_driver_set_texture_frame(const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha) +{ + if (video_driver_poke && video_driver_poke->set_texture_frame) + video_driver_poke->set_texture_frame(video_driver_data, + frame, rgb32, width, height, alpha); +} + +#ifdef HAVE_OVERLAY +bool video_driver_overlay_interface(const video_overlay_interface_t **iface) +{ + if (!current_video || !current_video->overlay_interface) + return false; + current_video->overlay_interface(video_driver_data, iface); + return true; +} +#endif + +void *video_driver_read_frame_raw(unsigned *width, + unsigned *height, size_t *pitch) +{ + if (!current_video || !current_video->read_frame_raw) + return NULL; + return current_video->read_frame_raw(video_driver_data, width, + height, pitch); +} + +void video_driver_set_filtering(unsigned index, bool smooth) +{ + if (video_driver_poke && video_driver_poke->set_filtering) + video_driver_poke->set_filtering(video_driver_data, index, smooth); +} + +void video_driver_cached_frame_set(const void *data, unsigned width, + unsigned height, size_t pitch) +{ + if (data) + frame_cache_data = data; + frame_cache_width = width; + frame_cache_height = height; + frame_cache_pitch = pitch; +} + +void video_driver_cached_frame_get(const void **data, unsigned *width, + unsigned *height, size_t *pitch) +{ + if (data) + *data = frame_cache_data; + if (width) + *width = frame_cache_width; + if (height) + *height = frame_cache_height; + if (pitch) + *pitch = frame_cache_pitch; +} + +void video_driver_get_size(unsigned *width, unsigned *height) +{ +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); + video_driver_threaded_lock(is_threaded); +#endif + if (width) + *width = video_driver_width; + if (height) + *height = video_driver_height; +#ifdef HAVE_THREADS + video_driver_threaded_unlock(is_threaded); +#endif +} + +void video_driver_set_size(unsigned *width, unsigned *height) +{ +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); + video_driver_threaded_lock(is_threaded); +#endif + if (width) + video_driver_width = *width; + if (height) + video_driver_height = *height; +#ifdef HAVE_THREADS + video_driver_threaded_unlock(is_threaded); +#endif +} + +/** + * video_monitor_set_refresh_rate: + * @hz : New refresh rate for monitor. + * + * Sets monitor refresh rate to new value. + **/ +void video_monitor_set_refresh_rate(float hz) +{ + char msg[128]; + settings_t *settings = config_get_ptr(); + + snprintf(msg, sizeof(msg), + "Setting refresh rate to: %.3f Hz.", hz); + runloop_msg_queue_push(msg, 1, 180, false); + RARCH_LOG("%s\n", msg); + + configuration_set_float(settings, + settings->floats.video_refresh_rate, + hz); +} + +/** + * video_monitor_fps_statistics + * @refresh_rate : Monitor refresh rate. + * @deviation : Deviation from measured refresh rate. + * @sample_points : Amount of sampled points. + * + * Gets the monitor FPS statistics based on the current + * runtime. + * + * Returns: true (1) on success. + * false (0) if: + * a) threaded video mode is enabled + * b) less than 2 frame time samples. + * c) FPS monitor enable is off. + **/ +bool video_monitor_fps_statistics(double *refresh_rate, + double *deviation, unsigned *sample_points) +{ + unsigned i; + retro_time_t accum = 0; + retro_time_t avg = 0; + retro_time_t accum_var = 0; + unsigned samples = 0; + +#ifdef HAVE_THREADS + if (video_driver_is_threaded_internal()) + return false; +#endif + + samples = MIN(MEASURE_FRAME_TIME_SAMPLES_COUNT, + (unsigned)video_driver_frame_time_count); + + if (samples < 2) + return false; + + /* Measure statistics on frame time (microsecs), *not* FPS. */ + for (i = 0; i < samples; i++) + { + accum += video_driver_frame_time_samples[i]; +#if 0 + RARCH_LOG("[Video]: Interval #%u: %d usec / frame.\n", + i, (int)frame_time_samples[i]); +#endif + } + + avg = accum / samples; + + /* Drop first measurement. It is likely to be bad. */ + for (i = 0; i < samples; i++) + { + retro_time_t diff = video_driver_frame_time_samples[i] - avg; + accum_var += diff * diff; + } + + *deviation = sqrt((double)accum_var / (samples - 1)) / avg; + + if (refresh_rate) + *refresh_rate = 1000000.0 / avg; + + if (sample_points) + *sample_points = samples; + + return true; +} + +float video_driver_get_aspect_ratio(void) +{ + return video_driver_aspect_ratio; +} + +void video_driver_set_aspect_ratio_value(float value) +{ + video_driver_aspect_ratio = value; +} + +static bool video_driver_frame_filter( + const void *data, + video_frame_info_t *video_info, + unsigned width, unsigned height, + size_t pitch, + unsigned *output_width, unsigned *output_height, + unsigned *output_pitch) +{ + rarch_softfilter_get_output_size(video_driver_state_filter, + output_width, output_height, width, height); + + *output_pitch = (*output_width) * video_driver_state_out_bpp; + + rarch_softfilter_process(video_driver_state_filter, + video_driver_state_buffer, *output_pitch, + data, width, height, pitch); + + if (video_info->post_filter_record && recording_data) + recording_dump_frame(video_driver_state_buffer, + *output_width, *output_height, *output_pitch, + video_info->runloop_is_idle); + + return true; +} + +rarch_softfilter_t *video_driver_frame_filter_get_ptr(void) +{ + return video_driver_state_filter; +} + +enum retro_pixel_format video_driver_get_pixel_format(void) +{ + return video_driver_pix_fmt; +} + +void video_driver_set_pixel_format(enum retro_pixel_format fmt) +{ + video_driver_pix_fmt = fmt; +} + +/** + * video_driver_cached_frame: + * + * Renders the current video frame. + **/ +bool video_driver_cached_frame(void) +{ + void *recording = recording_driver_get_data_ptr(); + + recording_driver_lock(); + + /* Cannot allow recording when pushing duped frames. */ + recording_data = NULL; + + retro_ctx.frame_cb( + (frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID) + ? frame_cache_data : NULL, + frame_cache_width, + frame_cache_height, frame_cache_pitch); + + recording_data = recording; + + recording_driver_unlock(); + + return true; +} + +void video_driver_monitor_adjust_system_rates(void) +{ + float timing_skew = 0.0f; + settings_t *settings = config_get_ptr(); + float video_refresh_rate = settings->floats.video_refresh_rate; + float timing_skew_hz = video_refresh_rate; + const struct retro_system_timing *info = (const struct retro_system_timing*)&video_driver_av_info.timing; + + rarch_ctl(RARCH_CTL_UNSET_NONBLOCK_FORCED, NULL); + + if (!info || info->fps <= 0.0) + return; + + video_driver_core_hz = info->fps; + + if (video_driver_crt_switching_active) + timing_skew_hz = video_driver_core_hz; + timing_skew = fabs( + 1.0f - info->fps / timing_skew_hz); + + if (!settings->bools.vrr_runloop_enable) + { + /* We don't want to adjust pitch too much. If we have extreme cases, + * just don't readjust at all. */ + if (timing_skew <= settings->floats.audio_max_timing_skew) + return; + + RARCH_LOG("[Video]: Timings deviate too much. Will not adjust." + " (Display = %.2f Hz, Game = %.2f Hz)\n", + video_refresh_rate, + (float)info->fps); + } + + if (info->fps <= timing_skew_hz) + return; + + /* We won't be able to do VSync reliably when game FPS > monitor FPS. */ + rarch_ctl(RARCH_CTL_SET_NONBLOCK_FORCED, NULL); + RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n"); +} + +void video_driver_menu_settings(void **list_data, void *list_info_data, + void *group_data, void *subgroup_data, const char *parent_group) +{ +#ifdef HAVE_MENU + rarch_setting_t **list = (rarch_setting_t**)list_data; + rarch_setting_info_t *list_info = (rarch_setting_info_t*)list_info_data; + rarch_setting_group_info_t *group_info = (rarch_setting_group_info_t*)group_data; + rarch_setting_group_info_t *subgroup_info = (rarch_setting_group_info_t*)subgroup_data; + global_t *global = global_get_ptr(); + + (void)list; + (void)list_info; + (void)group_info; + (void)subgroup_info; + (void)global; + +#if defined(__CELLOS_LV2__) + CONFIG_BOOL( + list, list_info, + &global->console.screen.pal60_enable, + MENU_ENUM_LABEL_PAL60_ENABLE, + MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); +#endif +#if defined(GEKKO) || defined(_XBOX360) + CONFIG_UINT( + list, list_info, + &global->console.screen.gamma_correction, + MENU_ENUM_LABEL_VIDEO_GAMMA, + MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, + 0, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_cmd( + list, + list_info, + CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); + menu_settings_list_current_add_range( + list, + list_info, + 0, + MAX_GAMMA_SETTING, + 1, + true, + true); + settings_data_list_current_add_flags(list, list_info, + SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); +#endif +#if defined(_XBOX1) || defined(HW_RVL) + CONFIG_BOOL( + list, list_info, + &global->console.softfilter_enable, + MENU_ENUM_LABEL_VIDEO_SOFT_FILTER, + MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + menu_settings_list_current_add_cmd( + list, + list_info, + CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); +#endif +#ifdef _XBOX1 + CONFIG_UINT( + list, list_info, + &global->console.screen.flicker_filter_index, + MENU_ENUM_LABEL_VIDEO_FILTER_FLICKER, + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, + 0, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_range(list, list_info, + 0, 5, 1, true, true); +#endif +#endif +} + +static void video_driver_lock_new(void) +{ + video_driver_lock_free(); +#ifdef HAVE_THREADS + if (!display_lock) + display_lock = slock_new(); + retro_assert(display_lock); + + if (!context_lock) + context_lock = slock_new(); + retro_assert(context_lock); +#endif +} + +void video_driver_destroy(void) +{ + video_display_server_destroy(); + crt_video_restore(); + + video_driver_cb_has_focus = null_driver_has_focus; + video_driver_use_rgba = false; + video_driver_data_own = false; + video_driver_active = false; + video_driver_cache_context = false; + video_driver_cache_context_ack = false; + video_driver_record_gpu_buffer = NULL; + current_video = NULL; + video_driver_set_cached_frame_ptr(NULL); +} + +void video_driver_set_cached_frame_ptr(const void *data) +{ + if (data) + frame_cache_data = data; +} + +void video_driver_set_stub_frame(void) +{ + frame_bak = current_video->frame; + current_video->frame = video_null.frame; +} + +void video_driver_unset_stub_frame(void) +{ + if (frame_bak != NULL) + current_video->frame = frame_bak; + + frame_bak = NULL; +} + +bool video_driver_is_stub_frame(void) +{ + return current_video->frame == video_null.frame; +} + +bool video_driver_supports_recording(void) +{ + settings_t *settings = config_get_ptr(); + return settings->bools.video_gpu_record + && current_video->read_viewport; +} + +bool video_driver_supports_viewport_read(void) +{ + settings_t *settings = config_get_ptr(); + return (settings->bools.video_gpu_screenshot || + (video_driver_is_hw_context() && !current_video->read_frame_raw)) + && current_video->read_viewport && current_video->viewport_info; +} + +bool video_driver_supports_read_frame_raw(void) +{ + if (current_video->read_frame_raw) + return true; + return false; +} + +void video_driver_set_viewport_config(void) +{ + settings_t *settings = config_get_ptr(); + + if (settings->floats.video_aspect_ratio < 0.0f) + { + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + + if (geom->aspect_ratio > 0.0f && + settings->bools.video_aspect_ratio_auto) + aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio; + else + { + unsigned base_width = geom->base_width; + unsigned base_height = geom->base_height; + + /* Get around division by zero errors */ + if (base_width == 0) + base_width = 1; + if (base_height == 0) + base_height = 1; + aspectratio_lut[ASPECT_RATIO_CONFIG].value = + (float)base_width / base_height; /* 1:1 PAR. */ + } + } + else + { + aspectratio_lut[ASPECT_RATIO_CONFIG].value = + settings->floats.video_aspect_ratio; + } +} + +void video_driver_set_viewport_square_pixel(void) +{ + unsigned len, highest, i, aspect_x, aspect_y; + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + unsigned width = geom->base_width; + unsigned height = geom->base_height; + + if (width == 0 || height == 0) + return; + + len = MIN(width, height); + highest = 1; + + for (i = 1; i < len; i++) + { + if ((width % i) == 0 && (height % i) == 0) + highest = i; + } + + aspect_x = width / highest; + aspect_y = height / highest; + + snprintf(aspectratio_lut[ASPECT_RATIO_SQUARE].name, + sizeof(aspectratio_lut[ASPECT_RATIO_SQUARE].name), + "1:1 PAR (%u:%u DAR)", aspect_x, aspect_y); + + aspectratio_lut[ASPECT_RATIO_SQUARE].value = (float)aspect_x / aspect_y; +} + +void video_driver_set_viewport_core(void) +{ + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + + if (!geom || geom->base_width <= 0.0f || geom->base_height <= 0.0f) + return; + + /* Fallback to 1:1 pixel ratio if none provided */ + if (geom->aspect_ratio > 0.0f) + aspectratio_lut[ASPECT_RATIO_CORE].value = geom->aspect_ratio; + else + aspectratio_lut[ASPECT_RATIO_CORE].value = + (float)geom->base_width / geom->base_height; +} + +void video_driver_reset_custom_viewport(void) +{ + struct video_viewport *custom_vp = video_viewport_get_custom(); + + custom_vp->width = 0; + custom_vp->height = 0; + custom_vp->x = 0; + custom_vp->y = 0; +} + +void video_driver_set_rgba(void) +{ + video_driver_lock(); + video_driver_use_rgba = true; + video_driver_unlock(); +} + +void video_driver_unset_rgba(void) +{ + video_driver_lock(); + video_driver_use_rgba = false; + video_driver_unlock(); +} + +bool video_driver_supports_rgba(void) +{ + bool tmp; + video_driver_lock(); + tmp = video_driver_use_rgba; + video_driver_unlock(); + return tmp; +} + +bool video_driver_get_next_video_out(void) +{ + if (!video_driver_poke) + return false; + + if (!video_driver_poke->get_video_output_next) + return video_context_driver_get_video_output_next(); + video_driver_poke->get_video_output_next(video_driver_data); + return true; +} + +bool video_driver_get_prev_video_out(void) +{ + if (!video_driver_poke) + return false; + + if (!video_driver_poke->get_video_output_prev) + return video_context_driver_get_video_output_prev(); + video_driver_poke->get_video_output_prev(video_driver_data); + return true; +} + +bool video_driver_init(bool *video_is_threaded) +{ + video_driver_lock_new(); + video_driver_filter_free(); + video_driver_set_cached_frame_ptr(NULL); + return video_driver_init_internal(video_is_threaded); +} + +void video_driver_destroy_data(void) +{ + video_driver_data = NULL; +} + +void video_driver_free(void) +{ + video_driver_free_internal(); + video_driver_lock_free(); + video_driver_data = NULL; + video_driver_set_cached_frame_ptr(NULL); +} + +void video_driver_monitor_reset(void) +{ + video_driver_frame_time_count = 0; +} + +void video_driver_set_aspect_ratio(void) +{ + settings_t *settings = config_get_ptr(); + + switch (settings->uints.video_aspect_ratio_idx) + { + case ASPECT_RATIO_SQUARE: + video_driver_set_viewport_square_pixel(); + break; + + case ASPECT_RATIO_CORE: + video_driver_set_viewport_core(); + break; + + case ASPECT_RATIO_CONFIG: + video_driver_set_viewport_config(); + break; + + default: + break; + } + + video_driver_set_aspect_ratio_value( + aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); + + if (!video_driver_poke || !video_driver_poke->set_aspect_ratio) + return; + video_driver_poke->set_aspect_ratio( + video_driver_data, settings->uints.video_aspect_ratio_idx); +} + +void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect) +{ + gfx_ctx_aspect_t aspect_data; + float device_aspect = (float)vp->full_width / vp->full_height; + settings_t* settings = config_get_ptr(); + + aspect_data.aspect = &device_aspect; + aspect_data.width = vp->full_width; + aspect_data.height = vp->full_height; + + video_context_driver_translate_aspect(&aspect_data); + + vp->x = 0; + vp->y = 0; + vp->width = vp->full_width; + vp->height = vp->full_height; + + if (settings->bools.video_scale_integer && !force_full) + { + video_viewport_get_scaled_integer( + vp, vp->full_width, vp->full_height, video_driver_get_aspect_ratio(), keep_aspect); + } + else if (keep_aspect && !force_full) + { + float desired_aspect = video_driver_get_aspect_ratio(); + +#if defined(HAVE_MENU) + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + const struct video_viewport* custom = video_viewport_get_custom(); + + vp->x = custom->x; + vp->y = custom->y; + vp->width = custom->width; + vp->height = custom->height; + } + else +#endif + { + float delta; + + if (fabsf(device_aspect - desired_aspect) < 0.0001f) + { + /* If the aspect ratios of screen and desired aspect + * ratio are sufficiently equal (floating point stuff), + * assume they are actually equal. + */ + } + else if (device_aspect > desired_aspect) + { + delta = (desired_aspect / device_aspect - 1.0f) + / 2.0f + 0.5f; + vp->x = (int)roundf(vp->full_width * (0.5f - delta)); + vp->width = (unsigned)roundf(2.0f * vp->full_width * delta); + vp->y = 0; + vp->height = vp->full_height; + } + else + { + vp->x = 0; + vp->width = vp->full_width; + delta = (device_aspect / desired_aspect - 1.0f) + / 2.0f + 0.5f; + vp->y = (int)roundf(vp->full_height * (0.5f - delta)); + vp->height = (unsigned)roundf(2.0f * vp->full_height * delta); + } + } + } + +#if defined(RARCH_MOBILE) + /* In portrait mode, we want viewport to gravitate to top of screen. */ + if (device_aspect < 1.0f) + vp->y = 0; +#endif +} + +void video_driver_show_mouse(void) +{ + if (video_driver_poke && video_driver_poke->show_mouse) + video_driver_poke->show_mouse(video_driver_data, true); +} + +void video_driver_hide_mouse(void) +{ + if (video_driver_poke && video_driver_poke->show_mouse) + video_driver_poke->show_mouse(video_driver_data, false); +} + +void video_driver_set_nonblock_state(bool toggle) +{ + if (current_video->set_nonblock_state) + current_video->set_nonblock_state(video_driver_data, toggle); +} + +bool video_driver_find_driver(void) +{ + int i; + driver_ctx_info_t drv; + settings_t *settings = config_get_ptr(); + + if (video_driver_is_hw_context()) + { + struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); + + current_video = NULL; + + (void)hwr; + +#if defined(HAVE_VULKAN) + if (hwr && hw_render_context_is_vulkan(hwr->context_type)) + { + RARCH_LOG("[Video]: Using HW render, Vulkan driver forced.\n"); + current_video = &video_vulkan; + } +#endif + +#if defined(HAVE_OPENGL) + if (hwr && hw_render_context_is_gl(hwr->context_type)) + { + RARCH_LOG("[Video]: Using HW render, OpenGL driver forced.\n"); + current_video = &video_gl; + } +#endif + + if (current_video) + return true; + } + + if (frontend_driver_has_get_video_driver_func()) + { + current_video = (video_driver_t*)frontend_driver_get_video_driver(); + + if (current_video) + return true; + RARCH_WARN("Frontend supports get_video_driver() but did not specify one.\n"); + } + + drv.label = "video_driver"; + drv.s = settings->arrays.video_driver; + + driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv); + + i = (int)drv.len; + + if (i >= 0) + current_video = (video_driver_t*)video_driver_find_handle(i); + else + { + if (verbosity_is_enabled()) + { + unsigned d; + RARCH_ERR("Couldn't find any video driver named \"%s\"\n", + settings->arrays.video_driver); + RARCH_LOG_OUTPUT("Available video drivers are:\n"); + for (d = 0; video_driver_find_handle(d); d++) + RARCH_LOG_OUTPUT("\t%s\n", video_driver_find_ident(d)); + RARCH_WARN("Going to default to first video driver...\n"); + } + + current_video = (video_driver_t*)video_driver_find_handle(0); + + if (!current_video) + retroarch_fail(1, "find_video_driver()"); + } + return true; +} + +void video_driver_apply_state_changes(void) +{ + if (video_driver_poke && + video_driver_poke->apply_state_changes) + video_driver_poke->apply_state_changes(video_driver_data); +} + +bool video_driver_read_viewport(uint8_t *buffer, bool is_idle) +{ + if ( current_video->read_viewport + && current_video->read_viewport( + video_driver_data, buffer, is_idle)) + return true; + return false; +} + +bool video_driver_frame_filter_alive(void) +{ + return !!video_driver_state_filter; +} + +bool video_driver_frame_filter_is_32bit(void) +{ + return video_driver_state_out_rgb32; +} + +void video_driver_default_settings(void) +{ + global_t *global = global_get_ptr(); + + if (!global) + return; + + global->console.screen.gamma_correction = DEFAULT_GAMMA; + global->console.flickerfilter_enable = false; + global->console.softfilter_enable = false; + + global->console.screen.resolutions.current.id = 0; +} + +void video_driver_load_settings(config_file_t *conf) +{ + bool tmp_bool = false; + global_t *global = global_get_ptr(); + + if (!conf) + return; + +#ifdef _XBOX + CONFIG_GET_BOOL_BASE(conf, global, + console.screen.gamma_correction, "gamma_correction"); +#else + CONFIG_GET_INT_BASE(conf, global, + console.screen.gamma_correction, "gamma_correction"); +#endif + + if (config_get_bool(conf, "flicker_filter_enable", + &tmp_bool)) + global->console.flickerfilter_enable = tmp_bool; + + if (config_get_bool(conf, "soft_filter_enable", + &tmp_bool)) + global->console.softfilter_enable = tmp_bool; + + CONFIG_GET_INT_BASE(conf, global, + console.screen.soft_filter_index, + "soft_filter_index"); + CONFIG_GET_INT_BASE(conf, global, + console.screen.resolutions.current.id, + "current_resolution_id"); + CONFIG_GET_INT_BASE(conf, global, + console.screen.flicker_filter_index, + "flicker_filter_index"); +} + +void video_driver_save_settings(config_file_t *conf) +{ + global_t *global = global_get_ptr(); + if (!conf) + return; + +#ifdef _XBOX + config_set_bool(conf, "gamma_correction", + global->console.screen.gamma_correction); +#else + config_set_int(conf, "gamma_correction", + global->console.screen.gamma_correction); +#endif + config_set_bool(conf, "flicker_filter_enable", + global->console.flickerfilter_enable); + config_set_bool(conf, "soft_filter_enable", + global->console.softfilter_enable); + + config_set_int(conf, "soft_filter_index", + global->console.screen.soft_filter_index); + config_set_int(conf, "current_resolution_id", + global->console.screen.resolutions.current.id); + config_set_int(conf, "flicker_filter_index", + global->console.screen.flicker_filter_index); +} + +void video_driver_reinit(void) +{ + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); + + if (hwr->cache_context) + video_driver_cache_context = true; + else + video_driver_cache_context = false; + + video_driver_cache_context_ack = false; + command_event(CMD_EVENT_RESET_CONTEXT, NULL); + video_driver_cache_context = false; +} + +void video_driver_set_own_driver(void) +{ + video_driver_data_own = true; +} + +void video_driver_unset_own_driver(void) +{ + video_driver_data_own = false; +} + +bool video_driver_owns_driver(void) +{ + return video_driver_data_own; +} + +bool video_driver_is_hw_context(void) +{ + bool is_hw_context = false; + + video_driver_context_lock(); + is_hw_context = (hw_render.context_type != RETRO_HW_CONTEXT_NONE); + video_driver_context_unlock(); + + return is_hw_context; +} + +void video_driver_free_hw_context(void) +{ + video_driver_context_lock(); + + if (hw_render.context_destroy) + hw_render.context_destroy(); + + memset(&hw_render, 0, sizeof(hw_render)); + + video_driver_context_unlock(); + + hw_render_context_negotiation = NULL; +} + +struct retro_hw_render_callback *video_driver_get_hw_context(void) +{ + return &hw_render; +} + +const struct retro_hw_render_context_negotiation_interface * + video_driver_get_context_negotiation_interface(void) +{ + return hw_render_context_negotiation; +} + +void video_driver_set_context_negotiation_interface( + const struct retro_hw_render_context_negotiation_interface *iface) +{ + hw_render_context_negotiation = iface; +} + +bool video_driver_is_video_cache_context(void) +{ + return video_driver_cache_context; +} + +void video_driver_set_video_cache_context_ack(void) +{ + video_driver_cache_context_ack = true; +} + +void video_driver_unset_video_cache_context_ack(void) +{ + video_driver_cache_context_ack = false; +} + +bool video_driver_is_video_cache_context_ack(void) +{ + return video_driver_cache_context_ack; +} + +void video_driver_set_active(void) +{ + video_driver_active = true; +} + +void video_driver_unset_active(void) +{ + video_driver_active = false; +} + +bool video_driver_is_active(void) +{ + return video_driver_active; +} + +void video_driver_get_record_status( + bool *has_gpu_record, + uint8_t **gpu_buf) +{ + *gpu_buf = video_driver_record_gpu_buffer; + *has_gpu_record = video_driver_record_gpu_buffer != NULL; +} + +bool video_driver_gpu_record_init(unsigned size) +{ + video_driver_record_gpu_buffer = (uint8_t*)malloc(size); + if (!video_driver_record_gpu_buffer) + return false; + return true; +} + +void video_driver_gpu_record_deinit(void) +{ + free(video_driver_record_gpu_buffer); + video_driver_record_gpu_buffer = NULL; +} + +bool video_driver_get_current_software_framebuffer( + struct retro_framebuffer *fb) +{ + if ( + video_driver_poke + && video_driver_poke->get_current_software_framebuffer + && video_driver_poke->get_current_software_framebuffer( + video_driver_data, fb)) + return true; + + return false; +} + +bool video_driver_get_hw_render_interface( + const struct retro_hw_render_interface **iface) +{ + if ( + video_driver_poke + && video_driver_poke->get_hw_render_interface + && video_driver_poke->get_hw_render_interface( + video_driver_data, iface)) + return true; + + return false; +} + +bool video_driver_get_viewport_info(struct video_viewport *viewport) +{ + if (!current_video || !current_video->viewport_info) + return false; + current_video->viewport_info(video_driver_data, viewport); + return true; +} + +void video_driver_set_title_buf(void) +{ + struct retro_system_info info; + core_get_system_info(&info); + + fill_pathname_join_concat_noext( + video_driver_title_buf, + msg_hash_to_str(MSG_PROGRAM), + " ", + info.library_name, + sizeof(video_driver_title_buf)); + strlcat(video_driver_title_buf, + " ", sizeof(video_driver_title_buf)); + strlcat(video_driver_title_buf, + info.library_version, + sizeof(video_driver_title_buf)); +} + +/** + * video_viewport_get_scaled_integer: + * @vp : Viewport handle + * @width : Width. + * @height : Height. + * @aspect_ratio : Aspect ratio (in float). + * @keep_aspect : Preserve aspect ratio? + * + * Gets viewport scaling dimensions based on + * scaled integer aspect ratio. + **/ +void video_viewport_get_scaled_integer(struct video_viewport *vp, + unsigned width, unsigned height, + float aspect_ratio, bool keep_aspect) +{ + int padding_x = 0; + int padding_y = 0; + settings_t *settings = config_get_ptr(); + + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + struct video_viewport *custom = video_viewport_get_custom(); + + if (custom) + { + padding_x = width - custom->width; + padding_y = height - custom->height; + width = custom->width; + height = custom->height; + } + } + else + { + unsigned base_width; + /* Use system reported sizes as these define the + * geometry for the "normal" case. */ + unsigned base_height = + video_driver_av_info.geometry.base_height; + + if (base_height == 0) + base_height = 1; + + /* Account for non-square pixels. + * This is sort of contradictory with the goal of integer scale, + * but it is desirable in some cases. + * + * If square pixels are used, base_height will be equal to + * system->av_info.base_height. */ + base_width = (unsigned)roundf(base_height * aspect_ratio); + + /* Make sure that we don't get 0x scale ... */ + if (width >= base_width && height >= base_height) + { + if (keep_aspect) + { + /* X/Y scale must be same. */ + unsigned max_scale = MIN(width / base_width, + height / base_height); + padding_x = width - base_width * max_scale; + padding_y = height - base_height * max_scale; + } + else + { + /* X/Y can be independent, each scaled as much as possible. */ + padding_x = width % base_width; + padding_y = height % base_height; + } + } + + width -= padding_x; + height -= padding_y; + } + + vp->width = width; + vp->height = height; + vp->x = padding_x / 2; + vp->y = padding_y / 2; +} + +struct retro_system_av_info *video_viewport_get_system_av_info(void) +{ + return &video_driver_av_info; +} + +struct video_viewport *video_viewport_get_custom(void) +{ + settings_t *settings = config_get_ptr(); + return &settings->video_viewport_custom; +} + +unsigned video_pixel_get_alignment(unsigned pitch) +{ + if (pitch & 1) + return 1; + if (pitch & 2) + return 2; + if (pitch & 4) + return 4; + return 8; +} + +/** + * video_driver_frame: + * @data : pointer to data of the video frame. + * @width : width of the video frame. + * @height : height of the video frame. + * @pitch : pitch of the video frame. + * + * Video frame render callback function. + **/ +void video_driver_frame(const void *data, unsigned width, + unsigned height, size_t pitch) +{ + static char video_driver_msg[256]; + static char title[256]; + video_frame_info_t video_info; + static retro_time_t curr_time; + static retro_time_t fps_time; + static float last_fps, frame_time; + unsigned output_width = 0; + unsigned output_height = 0; + unsigned output_pitch = 0; + const char *msg = NULL; + retro_time_t new_time = + cpu_features_get_time_usec(); + + if (!video_driver_active) + return; + + if (video_driver_scaler_ptr && data && + (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_0RGB1555) && + (data != RETRO_HW_FRAME_BUFFER_VALID)) + { + if (video_pixel_frame_scale( + video_driver_scaler_ptr->scaler, + video_driver_scaler_ptr->scaler_out, + data, width, height, pitch)) + { + data = video_driver_scaler_ptr->scaler_out; + pitch = video_driver_scaler_ptr->scaler->out_stride; + } + } + + if (data) + frame_cache_data = data; + frame_cache_width = width; + frame_cache_height = height; + frame_cache_pitch = pitch; + + video_driver_build_info(&video_info); + + /* Get the amount of frames per seconds. */ + if (video_driver_frame_count) + { + unsigned write_index = + video_driver_frame_time_count++ & + (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1); + frame_time = new_time - fps_time; + video_driver_frame_time_samples[write_index] = frame_time; + fps_time = new_time; + + if (video_driver_frame_count == 1) + strlcpy(title, video_driver_window_title, sizeof(title)); + + if ((video_driver_frame_count % FPS_UPDATE_INTERVAL) == 0) + { + char frames_text[64]; + last_fps = TIME_TO_FPS(curr_time, new_time, FPS_UPDATE_INTERVAL); + + if (video_info.fps_show || video_info.framecount_show) + { + if (video_info.fps_show) + { + snprintf(video_info.fps_text, sizeof(video_info.fps_text), + " || FPS: %6.1f ", last_fps); + } + if (video_info.framecount_show) + { + snprintf(frames_text, + sizeof(frames_text), + " || Frames: %" PRIu64, + (uint64_t)video_driver_frame_count); + } + snprintf(video_driver_window_title, sizeof(video_driver_window_title), + "%s%s%s", title, + video_info.fps_show ? video_info.fps_text : "", + video_info.framecount_show ? frames_text : ""); + } + else + { + if (!string_is_equal(video_driver_window_title, title)) + strlcpy(video_driver_window_title, title, sizeof(video_driver_window_title)); + } + + curr_time = new_time; + video_driver_window_title_update = true; + } + + if (video_info.fps_show) + { + if (video_info.framecount_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f || %s: %" PRIu64, + last_fps, + msg_hash_to_str(MSG_FRAMES), + (uint64_t)video_driver_frame_count); + else + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f", + last_fps); + } + + if (video_info.fps_show && video_info.framecount_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f || %s: %" PRIu64, + last_fps, + msg_hash_to_str(MSG_FRAMES), + (uint64_t)video_driver_frame_count); + else if (video_info.framecount_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "%s: %" PRIu64, + msg_hash_to_str(MSG_FRAMES), + (uint64_t)video_driver_frame_count); + else if (video_info.fps_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f", + last_fps); + } + else + { + + curr_time = fps_time = new_time; + + strlcpy(video_driver_window_title, + video_driver_title_buf, + sizeof(video_driver_window_title)); + + if (video_info.fps_show) + strlcpy(video_info.fps_text, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), + sizeof(video_info.fps_text)); + + video_driver_window_title_update = true; + } + + video_info.frame_rate = last_fps; + video_info.frame_time = frame_time / 1000.0f; + video_info.frame_count = (uint64_t) video_driver_frame_count; + + /* Slightly messy code, + * but we really need to do processing before blocking on VSync + * for best possible scheduling. + */ + if ( + ( + !video_driver_state_filter + || !video_info.post_filter_record + || !data + || video_driver_record_gpu_buffer + ) && recording_data + ) + recording_dump_frame(data, width, height, + pitch, video_info.runloop_is_idle); + + if (data && video_driver_state_filter && + video_driver_frame_filter(data, &video_info, width, height, pitch, + &output_width, &output_height, &output_pitch)) + { + data = video_driver_state_buffer; + width = output_width; + height = output_height; + pitch = output_pitch; + } + + video_driver_msg[0] = '\0'; + + if ( video_info.font_enable + && runloop_msg_queue_pull((const char**)&msg) + && msg) + { +#ifdef HAVE_THREADS + /* the msg pointer may point to data modified by another thread */ + runloop_msg_queue_lock(); +#endif + strlcpy(video_driver_msg, msg, sizeof(video_driver_msg)); +#ifdef HAVE_THREADS + runloop_msg_queue_unlock(); +#endif + } + + if (video_info.statistics_show) + { + audio_statistics_t audio_stats = {0.0f}; + double stddev = 0.0; + struct retro_system_av_info *av_info = &video_driver_av_info; + unsigned red = 255; + unsigned green = 255; + unsigned blue = 255; + unsigned alpha = 255; + + video_monitor_fps_statistics(NULL, &stddev, NULL); + + video_info.osd_stat_params.x = 0.010f; + video_info.osd_stat_params.y = 0.950f; + video_info.osd_stat_params.scale = 1.0f; + video_info.osd_stat_params.full_screen = true; + video_info.osd_stat_params.drop_x = -2; + video_info.osd_stat_params.drop_y = -2; + video_info.osd_stat_params.drop_mod = 0.3f; + video_info.osd_stat_params.drop_alpha = 1.0f; + video_info.osd_stat_params.color = COLOR_ABGR( + red, green, blue, alpha); + + compute_audio_buffer_statistics(&audio_stats); + + snprintf(video_info.stat_text, + sizeof(video_info.stat_text), + "Video Statistics:\n -Frame rate: %6.2f fps\n -Frame time: %6.2f ms\n -Frame time deviation: %.3f %%\n" + " -Frame count: %" PRIu64"\n -Viewport: %d x %d x %3.2f\n" + "Audio Statistics:\n -Average buffer saturation: %.2f %%\n -Standard deviation: %.2f %%\n -Time spent close to underrun: %.2f %%\n -Time spent close to blocking: %.2f %%\n -Sample count: %d\n" + "Core Geometry:\n -Size: %u x %u\n -Max Size: %u x %u\n -Aspect: %3.2f\nCore Timing:\n -FPS: %3.2f\n -Sample Rate: %6.2f\n", + video_info.frame_rate, + video_info.frame_time, + 100.0 * stddev, + video_info.frame_count, + video_info.width, + video_info.height, + video_info.refresh_rate, + audio_stats.average_buffer_saturation, + audio_stats.std_deviation_percentage, + audio_stats.close_to_underrun, + audio_stats.close_to_blocking, + audio_stats.samples, + av_info->geometry.base_width, + av_info->geometry.base_height, + av_info->geometry.max_width, + av_info->geometry.max_height, + av_info->geometry.aspect_ratio, + av_info->timing.fps, + av_info->timing.sample_rate); + + /* TODO/FIXME - add OSD chat text here */ +#if 0 + snprintf(video_info.chat_text, sizeof(video_info.chat_text), + "anon: does retroarch netplay have in-game chat?\nradius: I don't know \u2605"); +#endif + } + + video_driver_active = current_video->frame( + video_driver_data, data, width, height, + video_driver_frame_count, + (unsigned)pitch, video_driver_msg, &video_info); + + video_driver_frame_count++; + + /* Display the FPS, with a higher priority. */ + if (video_info.fps_show || video_info.framecount_show) + runloop_msg_queue_push(video_info.fps_text, 2, 1, true); + + /* trigger set resolution*/ + if (video_info.crt_switch_resolution) + { + video_driver_crt_switching_active = true; + + if (video_info.crt_switch_resolution_super == 2560) + width = 2560; + if (video_info.crt_switch_resolution_super == 3840) + width = 3840; + if (video_info.crt_switch_resolution_super == 1920) + width = 1920; + crt_switch_res_core(width, height, video_driver_core_hz, video_info.crt_switch_resolution, video_info.crt_switch_center_adjust, video_info.monitor_index); + } + else if (!video_info.crt_switch_resolution) + video_driver_crt_switching_active = false; + + /* trigger set resolution*/ +} + +void crt_switch_driver_reinit(void) +{ + video_driver_reinit(); +} + +void video_driver_display_type_set(enum rarch_display_type type) +{ + video_driver_display_type = type; +} + +uintptr_t video_driver_display_get(void) +{ + return video_driver_display; +} + +void video_driver_display_set(uintptr_t idx) +{ + video_driver_display = idx; +} + +enum rarch_display_type video_driver_display_type_get(void) +{ + return video_driver_display_type; +} + +void video_driver_window_set(uintptr_t idx) +{ + video_driver_window = idx; +} + +uintptr_t video_driver_window_get(void) +{ + return video_driver_window; +} + +bool video_driver_texture_load(void *data, + enum texture_filter_type filter_type, + uintptr_t *id) +{ + if (!id || !video_driver_poke || !video_driver_poke->load_texture) + return false; + + *id = video_driver_poke->load_texture(video_driver_data, data, + video_driver_is_threaded_internal(), + filter_type); + + return true; +} + +bool video_driver_texture_unload(uintptr_t *id) +{ + if (!video_driver_poke || !video_driver_poke->unload_texture) + return false; + + video_driver_poke->unload_texture(video_driver_data, *id); + *id = 0; + return true; +} + +static void video_shader_driver_use_null(void *data, + void *shader_data, unsigned idx, bool set_active) +{ + (void)data; + (void)idx; + (void)set_active; +} + +static bool video_driver_cb_set_coords(void *handle_data, + void *shader_data, const struct video_coords *coords) +{ + video_shader_ctx_coords_t ctx_coords; + ctx_coords.handle_data = handle_data; + ctx_coords.data = coords; + + video_driver_set_coords(&ctx_coords); + return true; +} + +void video_driver_build_info(video_frame_info_t *video_info) +{ + bool is_perfcnt_enable = false; + bool is_paused = false; + bool is_idle = false; + bool is_slowmotion = false; + settings_t *settings = NULL; + video_viewport_t *custom_vp = NULL; + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); + video_driver_threaded_lock(is_threaded); +#endif + settings = config_get_ptr(); + custom_vp = &settings->video_viewport_custom; + video_info->refresh_rate = settings->floats.video_refresh_rate; + video_info->crt_switch_resolution = settings->uints.crt_switch_resolution; + video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super; + video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust; + video_info->black_frame_insertion = settings->bools.video_black_frame_insertion; + video_info->hard_sync = settings->bools.video_hard_sync; + video_info->hard_sync_frames = settings->uints.video_hard_sync_frames; + video_info->fps_show = settings->bools.video_fps_show; + video_info->statistics_show = settings->bools.video_statistics_show; + video_info->framecount_show = settings->bools.video_framecount_show; + video_info->scale_integer = settings->bools.video_scale_integer; + video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx; + video_info->post_filter_record = settings->bools.video_post_filter_record; + video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons; + video_info->max_swapchain_images = settings->uints.video_max_swapchain_images; + video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen; + video_info->fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); + video_info->monitor_index = settings->uints.video_monitor_index; + video_info->shared_context = settings->bools.video_shared_context; + + if (libretro_get_shared_context() && hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) + video_info->shared_context = true; + + video_info->font_enable = settings->bools.video_font_enable; + video_info->font_msg_pos_x = settings->floats.video_msg_pos_x; + video_info->font_msg_pos_y = settings->floats.video_msg_pos_y; + video_info->font_msg_color_r = settings->floats.video_msg_color_r; + video_info->font_msg_color_g = settings->floats.video_msg_color_g; + video_info->font_msg_color_b = settings->floats.video_msg_color_b; + video_info->custom_vp_x = custom_vp->x; + video_info->custom_vp_y = custom_vp->y; + video_info->custom_vp_width = custom_vp->width; + video_info->custom_vp_height = custom_vp->height; + video_info->custom_vp_full_width = custom_vp->full_width; + video_info->custom_vp_full_height = custom_vp->full_height; + + video_info->fps_text[0] = '\0'; + + video_info->width = video_driver_width; + video_info->height = video_driver_height; + + video_info->use_rgba = video_driver_use_rgba; + + video_info->libretro_running = false; + video_info->msg_bgcolor_enable = settings->bools.video_msg_bgcolor_enable; + +#ifdef HAVE_MENU + video_info->menu_is_alive = menu_driver_is_alive(); + video_info->menu_footer_opacity = settings->floats.menu_footer_opacity; + video_info->menu_header_opacity = settings->floats.menu_header_opacity; + video_info->materialui_color_theme = settings->uints.menu_materialui_color_theme; + video_info->ozone_color_theme = settings->uints.menu_ozone_color_theme; + video_info->menu_shader_pipeline = settings->uints.menu_xmb_shader_pipeline; + video_info->xmb_theme = settings->uints.menu_xmb_theme; + video_info->xmb_color_theme = settings->uints.menu_xmb_color_theme; + video_info->timedate_enable = settings->bools.menu_timedate_enable; + video_info->battery_level_enable = settings->bools.menu_battery_level_enable; + video_info->xmb_shadows_enable = settings->bools.menu_xmb_shadows_enable; + video_info->xmb_alpha_factor = settings->uints.menu_xmb_alpha_factor; + video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity; + video_info->menu_framebuffer_opacity = settings->floats.menu_framebuffer_opacity; + + video_info->libretro_running = core_is_game_loaded(); +#else + video_info->menu_is_alive = false; + video_info->menu_footer_opacity = 0.0f; + video_info->menu_header_opacity = 0.0f; + video_info->materialui_color_theme = 0; + video_info->menu_shader_pipeline = 0; + video_info->xmb_color_theme = 0; + video_info->xmb_theme = 0; + video_info->timedate_enable = false; + video_info->battery_level_enable = false; + video_info->xmb_shadows_enable = false; + video_info->xmb_alpha_factor = 0.0f; + video_info->menu_framebuffer_opacity = 0.0f; + video_info->menu_wallpaper_opacity = 0.0f; +#endif + + runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); + + video_info->is_perfcnt_enable = is_perfcnt_enable; + video_info->runloop_is_paused = is_paused; + video_info->runloop_is_idle = is_idle; + video_info->runloop_is_slowmotion = is_slowmotion; + + video_info->input_driver_nonblock_state = input_driver_is_nonblock_state(); + + video_info->context_data = video_context_data; + video_info->shader_driver = current_shader; + video_info->shader_data = current_shader_data; + + video_info->cb_update_window_title = current_video_context.update_window_title; + video_info->cb_swap_buffers = current_video_context.swap_buffers; + video_info->cb_get_metrics = current_video_context.get_metrics; + video_info->cb_set_resize = current_video_context.set_resize; + + video_info->cb_set_mvp = video_driver_cb_shader_set_mvp; + + video_info->userdata = video_driver_get_ptr(false); + +#ifdef HAVE_THREADS + video_driver_threaded_unlock(is_threaded); +#endif +} + +/** + * video_driver_translate_coord_viewport: + * @mouse_x : Pointer X coordinate. + * @mouse_y : Pointer Y coordinate. + * @res_x : Scaled X coordinate. + * @res_y : Scaled Y coordinate. + * @res_screen_x : Scaled screen X coordinate. + * @res_screen_y : Scaled screen Y coordinate. + * + * Translates pointer [X,Y] coordinates into scaled screen + * coordinates based on viewport info. + * + * Returns: true (1) if successful, false if video driver doesn't support + * viewport info. + **/ +bool video_driver_translate_coord_viewport( + struct video_viewport *vp, + int mouse_x, int mouse_y, + int16_t *res_x, int16_t *res_y, + int16_t *res_screen_x, int16_t *res_screen_y) +{ + int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y; + int norm_vp_width = (int)vp->width; + int norm_vp_height = (int)vp->height; + int norm_full_vp_width = (int)vp->full_width; + int norm_full_vp_height = (int)vp->full_height; + + if (norm_full_vp_width <= 0 || norm_full_vp_height <= 0) + return false; + + if (mouse_x >= 0 && mouse_x <= norm_full_vp_width) + scaled_screen_x = ((2 * mouse_x * 0x7fff) + / norm_full_vp_width) - 0x7fff; + else + scaled_screen_x = -0x8000; /* OOB */ + + if (mouse_y >= 0 && mouse_y <= norm_full_vp_height) + scaled_screen_y = ((2 * mouse_y * 0x7fff) + / norm_full_vp_height) - 0x7fff; + else + scaled_screen_y = -0x8000; /* OOB */ + + mouse_x -= vp->x; + mouse_y -= vp->y; + + if (mouse_x >= 0 && mouse_x <= norm_vp_width) + scaled_x = ((2 * mouse_x * 0x7fff) + / norm_vp_width) - 0x7fff; + else + scaled_x = -0x8000; /* OOB */ + + if (mouse_y >= 0 && mouse_y <= norm_vp_height) + scaled_y = ((2 * mouse_y * 0x7fff) + / norm_vp_height) - 0x7fff; + else + scaled_y = -0x8000; /* OOB */ + + *res_x = scaled_x; + *res_y = scaled_y; + *res_screen_x = scaled_screen_x; + *res_screen_y = scaled_screen_y; + + return true; +} + +void video_driver_get_window_title(char *buf, unsigned len) +{ + if (buf && video_driver_window_title_update) + { + strlcpy(buf, video_driver_window_title, len); + video_driver_window_title_update = false; + } +} + +void video_driver_get_status(uint64_t *frame_count, bool * is_alive, + bool *is_focused) +{ + *frame_count = video_driver_frame_count; + *is_alive = current_video ? + current_video->alive(video_driver_data) : true; + *is_focused = video_driver_cb_has_focus(); +} + +/** + * find_video_context_driver_driver_index: + * @ident : Identifier of resampler driver to find. + * + * Finds graphics context driver index by @ident name. + * + * Returns: graphics context driver index if driver was found, otherwise + * -1. + **/ +static int find_video_context_driver_index(const char *ident) +{ + unsigned i; + for (i = 0; gfx_ctx_drivers[i]; i++) + if (string_is_equal_noncase(ident, gfx_ctx_drivers[i]->ident)) + return i; + return -1; +} + +/** + * find_prev_context_driver: + * + * Finds previous driver in graphics context driver array. + **/ +bool video_context_driver_find_prev_driver(void) +{ + settings_t *settings = config_get_ptr(); + int i = find_video_context_driver_index( + settings->arrays.video_context_driver); + + if (i > 0) + { + strlcpy(settings->arrays.video_context_driver, + gfx_ctx_drivers[i - 1]->ident, + sizeof(settings->arrays.video_context_driver)); + return true; + } + + RARCH_WARN("Couldn't find any previous video context driver.\n"); + return false; +} + +/** + * find_next_context_driver: + * + * Finds next driver in graphics context driver array. + **/ +bool video_context_driver_find_next_driver(void) +{ + settings_t *settings = config_get_ptr(); + int i = find_video_context_driver_index( + settings->arrays.video_context_driver); + + if (i >= 0 && gfx_ctx_drivers[i + 1]) + { + strlcpy(settings->arrays.video_context_driver, + gfx_ctx_drivers[i + 1]->ident, + sizeof(settings->arrays.video_context_driver)); + return true; + } + + RARCH_WARN("Couldn't find any next video context driver.\n"); + return false; +} + +/** + * video_context_driver_init: + * @data : Input data. + * @ctx : Graphics context driver to initialize. + * @ident : Identifier of graphics context driver to find. + * @api : API of higher-level graphics API. + * @major : Major version number of higher-level graphics API. + * @minor : Minor version number of higher-level graphics API. + * @hw_render_ctx : Request a graphics context driver capable of + * hardware rendering? + * + * Initialize graphics context driver. + * + * Returns: graphics context driver if successfully initialized, + * otherwise NULL. + **/ +static const gfx_ctx_driver_t *video_context_driver_init( + void *data, + const gfx_ctx_driver_t *ctx, + const char *ident, + enum gfx_ctx_api api, unsigned major, + unsigned minor, bool hw_render_ctx, + void **ctx_data) +{ + video_frame_info_t video_info; + + if (!ctx->bind_api(data, api, major, minor)) + { + RARCH_WARN("Failed to bind API (#%u, version %u.%u)" + " on context driver \"%s\".\n", + (unsigned)api, major, minor, ctx->ident); + + return NULL; + } + + video_driver_build_info(&video_info); + + if (!(*ctx_data = ctx->init(&video_info, data))) + return NULL; + + if (ctx->bind_hw_render) + ctx->bind_hw_render(*ctx_data, + video_info.shared_context && hw_render_ctx); + + return ctx; +} + +/** + * video_context_driver_init_first: + * @data : Input data. + * @ident : Identifier of graphics context driver to find. + * @api : API of higher-level graphics API. + * @major : Major version number of higher-level graphics API. + * @minor : Minor version number of higher-level graphics API. + * @hw_render_ctx : Request a graphics context driver capable of + * hardware rendering? + * + * Finds first suitable graphics context driver and initializes. + * + * Returns: graphics context driver if found, otherwise NULL. + **/ +const gfx_ctx_driver_t *video_context_driver_init_first(void *data, + const char *ident, enum gfx_ctx_api api, unsigned major, + unsigned minor, bool hw_render_ctx, void **ctx_data) +{ + int i = find_video_context_driver_index(ident); + + if (i >= 0) + { + const gfx_ctx_driver_t *ctx = video_context_driver_init(data, gfx_ctx_drivers[i], ident, + api, major, minor, hw_render_ctx, ctx_data); + if (ctx) + { + video_context_data = *ctx_data; + return ctx; + } + } + + for (i = 0; gfx_ctx_drivers[i]; i++) + { + const gfx_ctx_driver_t *ctx = + video_context_driver_init(data, gfx_ctx_drivers[i], ident, + api, major, minor, hw_render_ctx, ctx_data); + + if (ctx) + { + video_context_data = *ctx_data; + return ctx; + } + } + + return NULL; +} + +bool video_context_driver_init_image_buffer(const video_info_t *data) +{ + if ( + current_video_context.image_buffer_init + && current_video_context.image_buffer_init( + video_context_data, data)) + return true; + return false; +} + +bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img) +{ + if ( + current_video_context.image_buffer_write + && current_video_context.image_buffer_write(video_context_data, + img->frame, img->width, img->height, img->pitch, + img->rgb32, img->index, img->handle)) + return true; + return false; +} + +bool video_context_driver_get_video_output_prev(void) +{ + if (!current_video_context.get_video_output_prev) + return false; + current_video_context.get_video_output_prev(video_context_data); + return true; +} + +bool video_context_driver_get_video_output_next(void) +{ + if (!current_video_context.get_video_output_next) + return false; + current_video_context.get_video_output_next(video_context_data); + return true; +} + +void video_context_driver_make_current(bool release) +{ + if (current_video_context.make_current) + current_video_context.make_current(release); +} + +bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect) +{ + if (!video_context_data || !aspect) + return false; + if (!current_video_context.translate_aspect) + return false; + *aspect->aspect = current_video_context.translate_aspect( + video_context_data, aspect->width, aspect->height); + return true; +} + +void video_context_driver_free(void) +{ + if (current_video_context.destroy) + current_video_context.destroy(video_context_data); + video_context_driver_destroy(); + video_context_data = NULL; +} + +bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data) +{ + if (!size_data) + return false; + if (!current_video_context.get_video_output_size) + return false; + current_video_context.get_video_output_size(video_context_data, + size_data->width, size_data->height); + return true; +} + +bool video_context_driver_swap_interval(int *interval) +{ + gfx_ctx_flags_t flags; + int current_interval = *interval; + settings_t *settings = config_get_ptr(); + bool adaptive_vsync_enabled = video_driver_get_all_flags(&flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && settings->bools.video_adaptive_vsync; + + if (!current_video_context.swap_interval) + return false; + if (adaptive_vsync_enabled && current_interval == 1) + current_interval = -1; + current_video_context.swap_interval(video_context_data, current_interval); + return true; +} + +bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc) +{ + if (!current_video_context.get_proc_address) + return false; + + proc->addr = current_video_context.get_proc_address(proc->sym); + + return true; +} + +bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics) +{ + if ( + current_video_context.get_metrics(video_context_data, + metrics->type, + metrics->value)) + return true; + return false; +} + +bool video_context_driver_get_refresh_rate(float *refresh_rate) +{ + float refresh_holder = 0; + + if (!current_video_context.get_refresh_rate || !refresh_rate) + return false; + if (!video_context_data) + return false; + + if (!video_driver_crt_switching_active) + if (refresh_rate) + *refresh_rate = + current_video_context.get_refresh_rate(video_context_data); + + if (video_driver_crt_switching_active) + { + if (refresh_rate) + refresh_holder = + current_video_context.get_refresh_rate(video_context_data); + if (refresh_holder != video_driver_core_hz) /* Fix for incorrect interlace detsction -- HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/ + *refresh_rate = video_driver_core_hz; + } + + return true; +} + +bool video_context_driver_input_driver(gfx_ctx_input_t *inp) +{ + settings_t *settings = config_get_ptr(); + const char *joypad_name = settings ? + settings->arrays.input_joypad_driver : NULL; + + if (!current_video_context.input_driver) + return false; + current_video_context.input_driver( + video_context_data, joypad_name, + inp->input, inp->input_data); + return true; +} + +bool video_context_driver_suppress_screensaver(bool *bool_data) +{ + if ( video_context_data + && current_video_context.suppress_screensaver( + video_context_data, *bool_data)) + return true; + return false; +} + +bool video_context_driver_get_ident(gfx_ctx_ident_t *ident) +{ + if (!ident) + return false; + ident->ident = current_video_context.ident; + return true; +} + +bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info) +{ + video_frame_info_t video_info; + + if (!current_video_context.set_video_mode) + return false; + + video_driver_build_info(&video_info); + + if (!current_video_context.set_video_mode( + video_context_data, &video_info, mode_info->width, + mode_info->height, mode_info->fullscreen)) + return false; + return true; +} + +bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info) +{ + if (!current_video_context.get_video_size) + return false; + current_video_context.get_video_size(video_context_data, + &mode_info->width, &mode_info->height); + return true; +} + +bool video_context_driver_show_mouse(bool *bool_data) +{ + if (!current_video_context.show_mouse) + return false; + current_video_context.show_mouse(video_context_data, *bool_data); + return true; +} + +static bool video_context_driver_get_flags(gfx_ctx_flags_t *flags) +{ + if (!current_video_context.get_flags) + return false; + + if (deferred_video_context_driver_set_flags) + { + flags->flags = deferred_flag_data.flags; + deferred_video_context_driver_set_flags = false; + return true; + } + + flags->flags = current_video_context.get_flags(video_context_data); + return true; +} + +static bool video_driver_get_flags(gfx_ctx_flags_t *flags) +{ + if (!video_driver_poke || !video_driver_poke->get_flags) + return false; + flags->flags = video_driver_poke->get_flags(video_driver_data); + return true; +} + +bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, enum display_flags flag) +{ + if (!flags) + return false; + + if (video_driver_get_flags(flags)) + if (BIT32_GET(flags->flags, flag)) + return true; + + flags->flags = 0; + + if (video_context_driver_get_flags(flags)) + if (BIT32_GET(flags->flags, flag)) + return true; + + return false; +} + +bool video_context_driver_set_flags(gfx_ctx_flags_t *flags) +{ + if (!flags) + return false; + if (!current_video_context.set_flags) + { + deferred_flag_data.flags = flags->flags; + deferred_video_context_driver_set_flags = true; + return false; + } + + current_video_context.set_flags(video_context_data, flags->flags); + return true; +} + +enum gfx_ctx_api video_context_driver_get_api(void) +{ + enum gfx_ctx_api ctx_api = video_context_data ? + current_video_context.get_api(video_context_data) : GFX_CTX_NONE; + + if (ctx_api == GFX_CTX_NONE) + { + const char *video_driver = video_driver_get_ident(); + if (string_is_equal(video_driver, "d3d9")) + return GFX_CTX_DIRECT3D9_API; + else if (string_is_equal(video_driver, "d3d10")) + return GFX_CTX_DIRECT3D10_API; + else if (string_is_equal(video_driver, "d3d11")) + return GFX_CTX_DIRECT3D11_API; + else if (string_is_equal(video_driver, "d3d12")) + return GFX_CTX_DIRECT3D12_API; + else if (string_is_equal(video_driver, "gx2")) + return GFX_CTX_GX2_API; + else if (string_is_equal(video_driver, "gx")) + return GFX_CTX_GX_API; + else if (string_is_equal(video_driver, "gl")) + return GFX_CTX_OPENGL_API; + else if (string_is_equal(video_driver, "vulkan")) + return GFX_CTX_VULKAN_API; + else if (string_is_equal(video_driver, "metal")) + return GFX_CTX_METAL_API; + + return GFX_CTX_NONE; + } + + return ctx_api; +} + +bool video_driver_has_windowed(void) +{ +#if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE)) + if (video_driver_data && current_video->has_windowed) + return current_video->has_windowed(video_driver_data); + else if (video_context_data && current_video_context.has_windowed) + return current_video_context.has_windowed(video_context_data); +#endif + return false; +} + +bool video_driver_cached_frame_has_valid_framebuffer(void) +{ + if (frame_cache_data) + return (frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID); + return false; +} + +static const shader_backend_t *video_shader_set_backend( + enum rarch_shader_type type) +{ + switch (type) + { + case RARCH_SHADER_CG: + { +#ifdef HAVE_CG + gfx_ctx_flags_t flags; + flags.flags = 0; + video_context_driver_get_flags(&flags); + + if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) + { + RARCH_ERR("[Shader driver]: Cg cannot be used with core" + " GL context. Trying to fall back to GLSL...\n"); + return video_shader_set_backend(RARCH_SHADER_GLSL); + } + + RARCH_LOG("[Shader driver]: Using Cg shader backend.\n"); + return &gl_cg_backend; +#else + break; +#endif + } + case RARCH_SHADER_GLSL: +#ifdef HAVE_GLSL + RARCH_LOG("[Shader driver]: Using GLSL shader backend.\n"); + return &gl_glsl_backend; +#else + break; +#endif + case RARCH_SHADER_HLSL: + case RARCH_SHADER_NONE: + default: + break; + } + + return NULL; +} + +void video_shader_driver_use(video_shader_ctx_info_t *shader_info) +{ + if (current_shader && current_shader->use) + current_shader->use(shader_info->data, current_shader_data, + shader_info->idx, shader_info->set_active); +} + +void video_shader_driver_set_parameter(struct uniform_info *param) +{ + if (current_shader && current_shader->set_uniform_parameter) + current_shader->set_uniform_parameter(current_shader_data, + param, NULL); +} + +void video_shader_driver_set_parameters(video_shader_ctx_params_t *params) +{ + if (current_shader && current_shader->set_params) + current_shader->set_params(params, current_shader_data); +} + +bool video_shader_driver_get_prev_textures( + video_shader_ctx_texture_t *texture) +{ + if (!texture || !current_shader) + return false; + texture->id = current_shader->get_prev_textures(current_shader_data); + + return true; +} + +bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident) +{ + if (!ident || !current_shader) + return false; + ident->ident = current_shader->ident; + return true; +} + +bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader) +{ + void *video_driver = video_driver_get_ptr(true); + const video_poke_interface_t *video_poke = video_driver_get_poke(); + + shader->data = NULL; + if (!video_poke || !video_driver || !video_poke->get_current_shader) + return false; + shader->data = video_poke->get_current_shader(video_driver); + return true; +} + +bool video_shader_driver_direct_get_current_shader( + video_shader_ctx_t *shader) +{ + if (!current_shader) + return false; + + shader->data = current_shader->get_current_shader(current_shader_data); + + return true; +} + +bool video_shader_driver_deinit(void) +{ + if (!current_shader) + return false; + + if (current_shader->deinit) + current_shader->deinit(current_shader_data); + + current_shader_data = NULL; + current_shader = NULL; + return true; +} + +static enum gfx_wrap_type video_shader_driver_wrap_type_null( + void *data, unsigned index) +{ + return RARCH_WRAP_BORDER; +} + +static bool video_driver_cb_set_mvp(void *data, + void *shader_data, const void *mat_data) +{ + video_shader_ctx_mvp_t mvp; + mvp.data = data; + mvp.matrix = mat_data; + + video_driver_set_mvp(&mvp); + return true; +} + +static struct video_shader * +video_shader_driver_get_current_shader_null(void *data) +{ + return NULL; +} + +static void video_shader_driver_set_params_null( + void *data, void *shader_data) +{ +} + +static void video_shader_driver_scale_null(void *data, + unsigned idx, struct gfx_fbo_scale *scale) +{ + (void)idx; + (void)scale; +} + +static bool video_shader_driver_mipmap_input_null( + void *data, unsigned idx) +{ + (void)idx; + return false; +} + +static bool video_shader_driver_filter_type_null( + void *data, unsigned idx, bool *smooth) +{ + (void)idx; + (void)smooth; + return false; +} + +static unsigned video_shader_driver_num_null(void *data) +{ + return 0; +} + +static bool video_shader_driver_get_feedback_pass_null( + void *data, unsigned *idx) +{ + (void)idx; + return false; +} + +static void video_shader_driver_reset_to_defaults(void) +{ + if (!current_shader) + return; + + if (!current_shader->wrap_type) + current_shader->wrap_type = video_shader_driver_wrap_type_null; + if (current_shader->set_mvp) + video_driver_cb_shader_set_mvp = current_shader->set_mvp; + else + { + current_shader->set_mvp = video_driver_cb_set_mvp; + video_driver_cb_shader_set_mvp = video_driver_cb_set_mvp; + } + if (!current_shader->set_coords) + current_shader->set_coords = video_driver_cb_set_coords; + + if (current_shader->use) + video_driver_cb_shader_use = current_shader->use; + else + { + current_shader->use = video_shader_driver_use_null; + video_driver_cb_shader_use = video_shader_driver_use_null; + } + if (!current_shader->set_params) + current_shader->set_params = video_shader_driver_set_params_null; + if (!current_shader->shader_scale) + current_shader->shader_scale = video_shader_driver_scale_null; + if (!current_shader->mipmap_input) + current_shader->mipmap_input = video_shader_driver_mipmap_input_null; + if (!current_shader->filter_type) + current_shader->filter_type = video_shader_driver_filter_type_null; + if (!current_shader->num_shaders) + current_shader->num_shaders = video_shader_driver_num_null; + if (!current_shader->get_current_shader) + current_shader->get_current_shader= video_shader_driver_get_current_shader_null; + if (!current_shader->get_feedback_pass) + current_shader->get_feedback_pass = video_shader_driver_get_feedback_pass_null; +} + +/* Finds first suitable shader context driver. */ +bool video_shader_driver_init_first(void) +{ + current_shader = (shader_backend_t*)shader_ctx_drivers[0]; + video_shader_driver_reset_to_defaults(); + return true; +} + +bool video_shader_driver_init(video_shader_ctx_init_t *init) +{ + void *tmp = NULL; + settings_t *settings = config_get_ptr(); + + if (!init->shader || !init->shader->init) + { + init->shader = video_shader_set_backend(init->shader_type); + + if (!init->shader) + return false; + } + + tmp = init->shader->init(init->data, init->path); + + if (!tmp) + return false; + + if (string_is_equal(settings->arrays.menu_driver, "xmb") + && init->shader->init_menu_shaders) + { + RARCH_LOG("Setting up menu pipeline shaders for XMB ... \n"); + init->shader->init_menu_shaders(tmp); + } + + current_shader_data = tmp; + + RARCH_LOG("Resetting shader to defaults ... \n"); + + current_shader = (shader_backend_t*)init->shader; + video_shader_driver_reset_to_defaults(); + + return true; +} + +bool video_shader_driver_get_feedback_pass(unsigned *data) +{ + return current_shader->get_feedback_pass(current_shader_data, data); +} + +bool video_shader_driver_mipmap_input(unsigned *index) +{ + return current_shader->mipmap_input(current_shader_data, *index); +} + +bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler) +{ + if (!scaler || !scaler->scale) + return false; + + scaler->scale->valid = false; + + current_shader->shader_scale(current_shader_data, + scaler->idx, scaler->scale); + return true; +} + +bool video_shader_driver_info(video_shader_ctx_info_t *shader_info) +{ + if (!shader_info) + return false; + + shader_info->num = current_shader->num_shaders(current_shader_data); + + return true; +} + +bool video_shader_driver_filter_type(video_shader_ctx_filter_t *filter) +{ + if (filter) + return current_shader->filter_type(current_shader_data, + filter->index, filter->smooth); + return false; +} + +bool video_shader_driver_compile_program( + struct shader_program_info *program_info) +{ + if (program_info) + return current_shader->compile_program(program_info->data, + program_info->idx, NULL, program_info); + return false; +} + +bool video_shader_driver_wrap_type(video_shader_ctx_wrap_t *wrap) +{ + wrap->type = current_shader->wrap_type( + current_shader_data, wrap->idx); + return true; +} + +void video_driver_set_coords(video_shader_ctx_coords_t *coords) +{ + if (current_shader && current_shader->set_coords) + current_shader->set_coords(coords->handle_data, + current_shader_data, + (const struct video_coords*)coords->data); + else + { + if (video_driver_poke && video_driver_poke->set_coords) + video_driver_poke->set_coords(coords->handle_data, + current_shader_data, + (const struct video_coords*)coords->data); + } +} + +void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp) +{ + if (!mvp || !mvp->matrix) + return; + + if (current_shader && current_shader->set_mvp) + current_shader->set_mvp(mvp->data, + current_shader_data, mvp->matrix); + else + { + if (video_driver_poke && video_driver_poke->set_mvp) + video_driver_poke->set_mvp(mvp->data, + current_shader_data, mvp->matrix); + } +} + +float video_driver_get_refresh_rate(void) +{ + if (video_driver_poke && video_driver_poke->get_refresh_rate) + return video_driver_poke->get_refresh_rate(video_driver_data); + + return 0.0f; +} diff --git a/gfx/video_driver.h b/gfx/video_driver.h index eea9ef14e4..2e5340ffbf 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -1,1308 +1,1310 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __VIDEO_DRIVER__H -#define __VIDEO_DRIVER__H - -#include -#include -#include - -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#ifdef HAVE_OVERLAY -#include "../input/input_overlay.h" -#endif - -#include "video_defines.h" -#include "video_coord_array.h" -#include "video_filter.h" -#include "video_shader_parse.h" -#include "video_state_tracker.h" - -#include "../input/input_driver.h" - -#define RARCH_SCALE_BASE 256 - -#include "video_shader_parse.h" - -#define VIDEO_SHADER_STOCK_BLEND (GFX_MAX_SHADERS - 1) -#define VIDEO_SHADER_MENU (GFX_MAX_SHADERS - 2) -#define VIDEO_SHADER_MENU_2 (GFX_MAX_SHADERS - 3) -#define VIDEO_SHADER_MENU_3 (GFX_MAX_SHADERS - 4) -#define VIDEO_SHADER_MENU_4 (GFX_MAX_SHADERS - 5) -#define VIDEO_SHADER_MENU_5 (GFX_MAX_SHADERS - 6) -#define VIDEO_SHADER_MENU_6 (GFX_MAX_SHADERS - 7) - -#if defined(_XBOX360) -#define DEFAULT_SHADER_TYPE RARCH_SHADER_HLSL -#elif defined(__PSL1GHT__) || defined(HAVE_OPENGLES2) || defined(HAVE_GLSL) -#define DEFAULT_SHADER_TYPE RARCH_SHADER_GLSL -#elif defined(__CELLOS_LV2__) || defined(HAVE_CG) -#define DEFAULT_SHADER_TYPE RARCH_SHADER_CG -#else -#define DEFAULT_SHADER_TYPE RARCH_SHADER_NONE -#endif - -RETRO_BEGIN_DECLS - -#ifndef MAX_EGLIMAGE_TEXTURES -#define MAX_EGLIMAGE_TEXTURES 32 -#endif - -#define MAX_VARIABLES 64 - -enum -{ - TEXTURES = 8, - TEXTURESMASK = TEXTURES - 1 -}; - -struct LinkInfo -{ - unsigned tex_w, tex_h; - struct video_shader_pass *pass; -}; - -enum gfx_ctx_api -{ - GFX_CTX_NONE = 0, - GFX_CTX_OPENGL_API, - GFX_CTX_OPENGL_ES_API, - GFX_CTX_DIRECT3D8_API, - GFX_CTX_DIRECT3D9_API, - GFX_CTX_DIRECT3D10_API, - GFX_CTX_DIRECT3D11_API, - GFX_CTX_DIRECT3D12_API, - GFX_CTX_OPENVG_API, - GFX_CTX_VULKAN_API, - GFX_CTX_SIXEL_API, - GFX_CTX_METAL_API, - GFX_CTX_GDI_API, - GFX_CTX_GX_API, - GFX_CTX_GX2_API -}; - -enum display_metric_types -{ - DISPLAY_METRIC_NONE = 0, - DISPLAY_METRIC_MM_WIDTH, - DISPLAY_METRIC_MM_HEIGHT, - DISPLAY_METRIC_DPI -}; - -enum display_flags -{ - GFX_CTX_FLAGS_NONE = 0, - GFX_CTX_FLAGS_GL_CORE_CONTEXT, - GFX_CTX_FLAGS_MULTISAMPLING, - GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES, - GFX_CTX_FLAGS_HARD_SYNC, - GFX_CTX_FLAGS_BLACK_FRAME_INSERTION, - GFX_CTX_FLAGS_MENU_FRAME_FILTERING, - GFX_CTX_FLAGS_ADAPTIVE_VSYNC -}; - -enum shader_uniform_type -{ - UNIFORM_1F = 0, - UNIFORM_2F, - UNIFORM_3F, - UNIFORM_4F, - UNIFORM_1FV, - UNIFORM_2FV, - UNIFORM_3FV, - UNIFORM_4FV, - UNIFORM_1I -}; - -enum shader_program_type -{ - SHADER_PROGRAM_VERTEX = 0, - SHADER_PROGRAM_FRAGMENT, - SHADER_PROGRAM_COMBINED -}; - -struct shader_program_info -{ - bool is_file; - const char *vertex; - const char *fragment; - const char *combined; - unsigned idx; - void *data; -}; - -struct uniform_info -{ - bool enabled; - - int32_t location; - int32_t count; - unsigned type; /* shader uniform type */ - - struct - { - enum shader_program_type type; - const char *ident; - uint32_t idx; - bool add_prefix; - bool enable; - } lookup; - - struct - { - struct - { - intptr_t v0; - intptr_t v1; - intptr_t v2; - intptr_t v3; - } integer; - - intptr_t *integerv; - - struct - { - uintptr_t v0; - uintptr_t v1; - uintptr_t v2; - uintptr_t v3; - } unsigned_integer; - - uintptr_t *unsigned_integerv; - - struct - { - float v0; - float v1; - float v2; - float v3; - } f; - - float *floatv; - } result; -}; - -typedef struct shader_backend -{ - void *(*init)(void *data, const char *path); - void (*init_menu_shaders)(void *data); - void (*deinit)(void *data); - - /* Set shader parameters. */ - void (*set_params)(void *data, void *shader_data); - - void (*set_uniform_parameter)(void *data, struct uniform_info *param, - void *uniform_data); - - /* Compile a shader program. */ - bool (*compile_program)(void *data, unsigned idx, - void *program_data, struct shader_program_info *program_info); - - /* Use a shader program specified by variable 'index'. */ - void (*use)(void *data, void *shader_data, unsigned index, bool set_active); - - /* Returns the number of currently loaded shaders. */ - unsigned (*num_shaders)(void *data); - - bool (*filter_type)(void *data, unsigned index, bool *smooth); - enum gfx_wrap_type (*wrap_type)(void *data, unsigned index); - void (*shader_scale)(void *data, - unsigned index, struct gfx_fbo_scale *scale); - bool (*set_coords)(void *handle_data, - void *shader_data, const struct video_coords *coords); - bool (*set_mvp)(void *data, void *shader_data, - const void *mat_data); - unsigned (*get_prev_textures)(void *data); - bool (*get_feedback_pass)(void *data, unsigned *pass); - bool (*mipmap_input)(void *data, unsigned index); - - struct video_shader *(*get_current_shader)(void *data); - - enum rarch_shader_type type; - - /* Human readable string. */ - const char *ident; -} shader_backend_t; - -typedef struct video_shader_ctx_init -{ - enum rarch_shader_type shader_type; - const char *path; - const shader_backend_t *shader; - void *data; - struct - { - bool core_context_enabled; - } gl; -} video_shader_ctx_init_t; - -typedef struct video_shader_ctx_params -{ - unsigned width; - unsigned height; - unsigned tex_width; - unsigned tex_height; - unsigned out_width; - unsigned out_height; - unsigned frame_counter; - unsigned fbo_info_cnt; - void *data; - const void *info; - const void *prev_info; - const void *feedback_info; - const void *fbo_info; -} video_shader_ctx_params_t; - -typedef struct video_shader_ctx_coords -{ - void *handle_data; - const void *data; -} video_shader_ctx_coords_t; - -typedef struct video_shader_ctx_scale -{ - unsigned idx; - struct gfx_fbo_scale *scale; -} video_shader_ctx_scale_t; - -typedef struct video_shader_ctx_info -{ - bool set_active; - unsigned num; - unsigned idx; - void *data; -} video_shader_ctx_info_t; - -typedef struct video_shader_ctx_mvp -{ - void *data; - const void *matrix; -} video_shader_ctx_mvp_t; - -typedef struct video_shader_ctx_filter -{ - unsigned index; - bool *smooth; -} video_shader_ctx_filter_t; - -typedef struct video_shader_ctx_wrap -{ - unsigned idx; - enum gfx_wrap_type type; -} video_shader_ctx_wrap_t; - -typedef struct video_shader_ctx -{ - struct video_shader *data; -} video_shader_ctx_t; - -typedef struct video_shader_ctx_ident -{ - const char *ident; -} video_shader_ctx_ident_t; - -typedef struct video_shader_ctx_texture -{ - unsigned id; -} video_shader_ctx_texture_t; - -typedef void (*gfx_ctx_proc_t)(void); - -typedef struct video_info -{ - /* Launch in fullscreen mode instead of windowed mode. */ - bool fullscreen; - - /* Start with V-Sync enabled. */ - bool vsync; - - /* If true, the output image should have the aspect ratio - * as set in aspect_ratio. */ - bool force_aspect; - - bool font_enable; - - /* Width of window. - * If fullscreen mode is requested, - * a width of 0 means the resolution of the - * desktop should be used. */ - unsigned width; - - /* Height of window. - * If fullscreen mode is requested, - * a height of 0 means the resolutiof the desktop should be used. - */ - unsigned height; - - int swap_interval; - -#ifdef GEKKO - bool vfilter; -#endif - - /* If true, applies bilinear filtering to the image, - * otherwise nearest filtering. */ - bool smooth; - - bool is_threaded; - - /* Use 32bit RGBA rather than native RGB565/XBGR1555. - * - * XRGB1555 format is 16-bit and has byte ordering: 0RRRRRGGGGGBBBBB, - * in native endian. - * - * ARGB8888 is AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB, native endian. - * Alpha channel should be disregarded. - * */ - bool rgb32; - -#ifdef GEKKO - /* TODO - we can't really have driver system-specific - * variables in here. There should be some - * kind of publicly accessible driver implementation - * video struct for specific things like this. - */ - - /* Wii-specific settings. Ignored for everything else. */ - unsigned viwidth; -#endif - - /* - * input_scale defines the maximum size of the picture that will - * ever be used with the frame callback. - * - * The maximum resolution is a multiple of 256x256 size (RARCH_SCALE_BASE), - * so an input scale of 2 means you should allocate a texture or of 512x512. - * - * Maximum input size: RARCH_SCALE_BASE * input_scale - */ - unsigned input_scale; - - uintptr_t parent; -} video_info_t; - -typedef struct video_frame_info -{ - bool input_menu_swap_ok_cancel_buttons; - bool input_driver_nonblock_state; - bool shared_context; - bool black_frame_insertion; - bool hard_sync; - bool fps_show; - bool statistics_show; - bool framecount_show; - bool scale_integer; - bool post_filter_record; - bool windowed_fullscreen; - bool fullscreen; - bool font_enable; - bool use_rgba; - bool libretro_running; - bool xmb_shadows_enable; - bool battery_level_enable; - bool timedate_enable; - bool runloop_is_slowmotion; - bool runloop_is_idle; - bool runloop_is_paused; - bool is_perfcnt_enable; - bool menu_is_alive; - bool msg_bgcolor_enable; - - int custom_vp_x; - int custom_vp_y; - int crt_switch_center_adjust; - - unsigned hard_sync_frames; - unsigned aspect_ratio_idx; - unsigned max_swapchain_images; - unsigned monitor_index; - unsigned crt_switch_resolution; - unsigned crt_switch_resolution_super; - unsigned width; - unsigned height; - unsigned xmb_theme; - unsigned xmb_color_theme; - unsigned menu_shader_pipeline; - unsigned materialui_color_theme; - unsigned ozone_color_theme; - unsigned custom_vp_width; - unsigned custom_vp_height; - unsigned custom_vp_full_width; - unsigned custom_vp_full_height; - - float menu_wallpaper_opacity; - float menu_framebuffer_opacity; - float menu_header_opacity; - float menu_footer_opacity; - float refresh_rate; - float font_msg_pos_x; - float font_msg_pos_y; - float font_msg_color_r; - float font_msg_color_g; - float font_msg_color_b; - float xmb_alpha_factor; - - char fps_text[128]; - char stat_text[512]; - char chat_text[256]; - - uint64_t frame_count; - float frame_time; - float frame_rate; - - struct - { - float x; - float y; - float scale; - /* Drop shadow color multiplier. */ - float drop_mod; - /* Drop shadow offset. - * If both are 0, no drop shadow will be rendered. */ - int drop_x, drop_y; - /* Drop shadow alpha */ - float drop_alpha; - /* ABGR. Use the macros. */ - uint32_t color; - bool full_screen; - enum text_alignment text_align; - } osd_stat_params; - - void (*cb_update_window_title)(void*, void *); - void (*cb_swap_buffers)(void*, void *); - bool (*cb_get_metrics)(void *data, enum display_metric_types type, - float *value); - bool (*cb_set_resize)(void*, unsigned, unsigned); - - bool (*cb_set_mvp)(void *data, void *shader_data, - const void *mat_data); - - void *context_data; - void *shader_data; - void *userdata; - const shader_backend_t *shader_driver; -} video_frame_info_t; - -typedef void (*update_window_title_cb)(void*, void*); -typedef bool (*get_metrics_cb)(void *data, enum display_metric_types type, - float *value); -typedef bool (*set_resize_cb)(void*, unsigned, unsigned); - -typedef struct gfx_ctx_driver -{ - /* The opaque pointer is the underlying video driver data (e.g. gl_t for - * OpenGL contexts). Although not advised, the context driver is allowed - * to hold a pointer to it as the context never outlives the video driver. - * - * The context driver is responsible for it's own data.*/ - void* (*init)(video_frame_info_t *video_info, void *video_driver); - void (*destroy)(void *data); - - enum gfx_ctx_api (*get_api)(void *data); - - /* Which API to bind to. */ - bool (*bind_api)(void *video_driver, enum gfx_ctx_api, - unsigned major, unsigned minor); - - /* Sets the swap interval. */ - void (*swap_interval)(void *data, int); - - /* Sets video mode. Creates a window, etc. */ - bool (*set_video_mode)(void*, video_frame_info_t *video_info, unsigned, unsigned, bool); - - /* Gets current window size. - * If not initialized yet, it returns current screen size. */ - void (*get_video_size)(void*, unsigned*, unsigned*); - - float (*get_refresh_rate)(void*); - - void (*get_video_output_size)(void*, unsigned*, unsigned*); - - void (*get_video_output_prev)(void*); - - void (*get_video_output_next)(void*); - - get_metrics_cb get_metrics; - - /* Translates a window size to an aspect ratio. - * In most cases this will be just width / height, but - * some contexts will better know which actual aspect ratio is used. - * This can be NULL to assume the default behavior. - */ - float (*translate_aspect)(void*, unsigned, unsigned); - - /* Asks driver to update window title (FPS, etc). */ - update_window_title_cb update_window_title; - - /* Queries for resize and quit events. - * Also processes events. */ - void (*check_window)(void*, bool*, bool*, - unsigned*, unsigned*, bool); - - /* Acknowledge a resize event. This is needed for some APIs. - * Most backends will ignore this. */ - set_resize_cb set_resize; - - /* Checks if window has input focus. */ - bool (*has_focus)(void*); - - /* Should the screensaver be suppressed? */ - bool (*suppress_screensaver)(void *data, bool enable); - - /* Checks if context driver has windowed support. */ - bool (*has_windowed)(void*); - - /* Swaps buffers. VBlank sync depends on - * earlier calls to swap_interval. */ - void (*swap_buffers)(void*, void *); - - /* Most video backends will want to use a certain input driver. - * Checks for it here. */ - void (*input_driver)(void*, const char *, const input_driver_t**, void**); - - /* Wraps whatever gl_proc_address() there is. - * Does not take opaque, to avoid lots of ugly wrapper code. */ - gfx_ctx_proc_t (*get_proc_address)(const char*); - - /* Returns true if this context supports EGLImage buffers for - * screen drawing and was initalized correctly. */ - bool (*image_buffer_init)(void*, const video_info_t*); - - /* Writes the frame to the EGLImage and sets image_handle to it. - * Returns true if a new image handle is created. - * Always returns true the first time it's called for a new index. - * The graphics core must handle a change in the handle correctly. */ - bool (*image_buffer_write)(void*, const void *frame, unsigned width, - unsigned height, unsigned pitch, bool rgb32, - unsigned index, void **image_handle); - - /* Shows or hides mouse. Can be NULL if context doesn't - * have a concept of mouse pointer. */ - void (*show_mouse)(void *data, bool state); - - /* Human readable string. */ - const char *ident; - - uint32_t (*get_flags)(void *data); - - void (*set_flags)(void *data, uint32_t flags); - - /* Optional. Binds HW-render offscreen context. */ - void (*bind_hw_render)(void *data, bool enable); - - /* Optional. Gets base data for the context which is used by the driver. - * This is mostly relevant for graphics APIs such as Vulkan - * which do not have global context state. */ - void *(*get_context_data)(void *data); - - /* Optional. Makes driver context (only GLX right now) - * active for this thread. */ - void (*make_current)(bool release); -} gfx_ctx_driver_t; - -typedef struct gfx_ctx_flags -{ - uint32_t flags; -} gfx_ctx_flags_t; - -typedef struct gfx_ctx_size -{ - bool *quit; - bool *resize; - unsigned *width; - unsigned *height; -} gfx_ctx_size_t; - -typedef struct gfx_ctx_mode -{ - unsigned width; - unsigned height; - bool fullscreen; -} gfx_ctx_mode_t; - -typedef struct gfx_ctx_metrics -{ - enum display_metric_types type; - float *value; -} gfx_ctx_metrics_t; - -typedef struct gfx_ctx_aspect -{ - float *aspect; - unsigned width; - unsigned height; -} gfx_ctx_aspect_t; - -typedef struct gfx_ctx_image -{ - const void *frame; - unsigned width; - unsigned height; - unsigned pitch; - unsigned index; - bool rgb32; - void **handle; -} gfx_ctx_image_t; - -typedef struct gfx_ctx_input -{ - const input_driver_t **input; - void **input_data; -} gfx_ctx_input_t; - -typedef struct gfx_ctx_proc_address -{ - const char *sym; - retro_proc_address_t addr; -} gfx_ctx_proc_address_t; - -typedef struct gfx_ctx_ident -{ - const char *ident; -} gfx_ctx_ident_t; - -typedef struct video_viewport -{ - int x; - int y; - unsigned width; - unsigned height; - unsigned full_width; - unsigned full_height; -} video_viewport_t; - -struct aspect_ratio_elem -{ - char name[64]; - float value; -}; - -/* Optionally implemented interface to poke more - * deeply into video driver. */ - -typedef struct video_poke_interface -{ - uint32_t (*get_flags)(void *data); - void (*set_coords)(void *handle_data, void *shader_data, - const struct video_coords *coords); - void (*set_mvp)(void *data, void *shader_data, - const void *mat_data); - uintptr_t (*load_texture)(void *video_data, void *data, - bool threaded, enum texture_filter_type filter_type); - void (*unload_texture)(void *data, uintptr_t id); - void (*set_video_mode)(void *data, unsigned width, - unsigned height, bool fullscreen); - float (*get_refresh_rate)(void *data); - void (*set_filtering)(void *data, unsigned index, bool smooth); - void (*get_video_output_size)(void *data, - unsigned *width, unsigned *height); - - /* Move index to previous resolution */ - void (*get_video_output_prev)(void *data); - - /* Move index to next resolution */ - void (*get_video_output_next)(void *data); - - uintptr_t (*get_current_framebuffer)(void *data); - retro_proc_address_t (*get_proc_address)(void *data, const char *sym); - void (*set_aspect_ratio)(void *data, unsigned aspectratio_index); - void (*apply_state_changes)(void *data); - - /* Update texture. */ - void (*set_texture_frame)(void *data, const void *frame, bool rgb32, - unsigned width, unsigned height, float alpha); - /* Enable or disable rendering. */ - void (*set_texture_enable)(void *data, bool enable, bool full_screen); - void (*set_osd_msg)(void *data, video_frame_info_t *video_info, - const char *msg, - const void *params, void *font); - - void (*show_mouse)(void *data, bool state); - void (*grab_mouse_toggle)(void *data); - - struct video_shader *(*get_current_shader)(void *data); - bool (*get_current_software_framebuffer)(void *data, - struct retro_framebuffer *framebuffer); - bool (*get_hw_render_interface)(void *data, - const struct retro_hw_render_interface **iface); -} video_poke_interface_t; - -/* msg is for showing a message on the screen - * along with the video frame. */ -typedef bool (*video_driver_frame_t)(void *data, - const void *frame, unsigned width, - unsigned height, uint64_t frame_count, - unsigned pitch, const char *msg, video_frame_info_t *video_info); - -typedef struct video_driver -{ - /* Should the video driver act as an input driver as well? - * The video initialization might preinitialize an input driver - * to override the settings in case the video driver relies on - * input driver for event handling. */ - void *(*init)(const video_info_t *video, - const input_driver_t **input, - void **input_data); - - /* Updates frame on the screen. - * Frame can be either XRGB1555, RGB565 or ARGB32 format - * depending on rgb32 setting in video_info_t. - * Pitch is the distance in bytes between two scanlines in memory. - * - * When msg is non-NULL, - * it's a message that should be displayed to the user. */ - video_driver_frame_t frame; - - /* Should we care about syncing to vblank? Fast forwarding. - * - * Requests nonblocking operation. - * - * True = VSync is turned off. - * False = VSync is turned on. - * */ - void (*set_nonblock_state)(void *data, bool toggle); - - /* Is the window still active? */ - bool (*alive)(void *data); - - /* Does the window have focus? */ - bool (*focus)(void *data); - - /* Should the screensaver be suppressed? */ - bool (*suppress_screensaver)(void *data, bool enable); - - /* Does the graphics context support windowed mode? */ - bool (*has_windowed)(void *data); - - /* Sets shader. Might not be implemented. Will be moved to - * poke_interface later. */ - bool (*set_shader)(void *data, enum rarch_shader_type type, - const char *path); - - /* Frees driver. */ - void (*free)(void *data); - - /* Human-readable identifier. */ - const char *ident; - - void (*set_viewport)(void *data, unsigned width, unsigned height, - bool force_full, bool allow_rotate); - - void (*set_rotation)(void *data, unsigned rotation); - void (*viewport_info)(void *data, struct video_viewport *vp); - - /* Reads out in BGR byte order (24bpp). */ - bool (*read_viewport)(void *data, uint8_t *buffer, bool is_idle); - - /* Returns a pointer to a newly allocated buffer that can - * (and must) be passed to free() by the caller, containing a - * copy of the current raw frame in the active pixel format - * and sets width, height and pitch to the correct values. */ - void* (*read_frame_raw)(void *data, unsigned *width, - unsigned *height, size_t *pitch); - -#ifdef HAVE_OVERLAY - void (*overlay_interface)(void *data, - const video_overlay_interface_t **iface); -#endif - void (*poke_interface)(void *data, const video_poke_interface_t **iface); - unsigned (*wrap_type_to_enum)(enum gfx_wrap_type type); -} video_driver_t; - -extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END]; - -bool video_driver_has_windowed(void); - -bool video_driver_cached_frame_has_valid_framebuffer(void); - -void video_driver_destroy(void); -void video_driver_set_cached_frame_ptr(const void *data); -void video_driver_set_stub_frame(void); -void video_driver_unset_stub_frame(void); -bool video_driver_is_stub_frame(void); -bool video_driver_supports_recording(void); -bool video_driver_supports_viewport_read(void); -bool video_driver_supports_read_frame_raw(void); -void video_driver_set_viewport_config(void); -void video_driver_set_viewport_square_pixel(void); -void video_driver_set_viewport_core(void); -void video_driver_reset_custom_viewport(void); -void video_driver_set_rgba(void); -void video_driver_unset_rgba(void); -bool video_driver_supports_rgba(void); -bool video_driver_get_next_video_out(void); -bool video_driver_get_prev_video_out(void); -bool video_driver_init(bool *video_is_threaded); -void video_driver_destroy_data(void); -void video_driver_free(void); -void video_driver_free_hw_context(void); -void video_driver_monitor_reset(void); -void video_driver_set_aspect_ratio(void); -void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect); -void video_driver_show_mouse(void); -void video_driver_hide_mouse(void); -void video_driver_set_nonblock_state(bool toggle); -bool video_driver_find_driver(void); -void video_driver_apply_state_changes(void); -bool video_driver_read_viewport(uint8_t *buffer, bool is_idle); -bool video_driver_cached_frame(void); -bool video_driver_frame_filter_alive(void); -bool video_driver_frame_filter_is_32bit(void); -void video_driver_default_settings(void); -void video_driver_load_settings(config_file_t *conf); -void video_driver_save_settings(config_file_t *conf); -void video_driver_set_own_driver(void); -void video_driver_unset_own_driver(void); -bool video_driver_owns_driver(void); -bool video_driver_is_hw_context(void); -struct retro_hw_render_callback *video_driver_get_hw_context(void); -const struct retro_hw_render_context_negotiation_interface -*video_driver_get_context_negotiation_interface(void); -void video_driver_set_context_negotiation_interface(const struct - retro_hw_render_context_negotiation_interface *iface); -bool video_driver_is_video_cache_context(void); -void video_driver_set_video_cache_context_ack(void); -bool video_driver_is_video_cache_context_ack(void); -void video_driver_set_active(void); -void video_driver_unset_active(void); -bool video_driver_is_active(void); -bool video_driver_gpu_record_init(unsigned size); -void video_driver_gpu_record_deinit(void); -bool video_driver_get_current_software_framebuffer(struct - retro_framebuffer *fb); -bool video_driver_get_hw_render_interface(const struct - retro_hw_render_interface **iface); -bool video_driver_get_viewport_info(struct video_viewport *viewport); -void video_driver_set_title_buf(void); -void video_driver_monitor_adjust_system_rates(void); - -/** - * video_driver_find_handle: - * @index : index of driver to get handle to. - * - * Returns: handle to video driver at index. Can be NULL - * if nothing found. - **/ -const void *video_driver_find_handle(int index); - -/** - * video_driver_find_ident: - * @index : index of driver to get handle to. - * - * Returns: Human-readable identifier of video driver at index. - * Can be NULL if nothing found. - **/ -const char *video_driver_find_ident(int index); - -/** - * config_get_video_driver_options: - * - * Get an enumerated list of all video driver names, separated by '|'. - * - * Returns: string listing of all video driver names, separated by '|'. - **/ -const char* config_get_video_driver_options(void); - -/** - * video_driver_get_ptr: - * - * Use this if you need the real video driver - * and driver data pointers. - * - * Returns: video driver's userdata. - **/ -void *video_driver_get_ptr(bool force_nonthreaded_data); - -/** - * video_driver_get_current_framebuffer: - * - * Gets pointer to current hardware renderer framebuffer object. - * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. - * - * Returns: pointer to hardware framebuffer object, otherwise 0. - **/ -uintptr_t video_driver_get_current_framebuffer(void); - -retro_proc_address_t video_driver_get_proc_address(const char *sym); - -bool video_driver_set_shader(enum rarch_shader_type type, - const char *shader); - -bool video_driver_set_rotation(unsigned rotation); - -bool video_driver_set_video_mode(unsigned width, - unsigned height, bool fullscreen); - -bool video_driver_get_video_output_size( - unsigned *width, unsigned *height); - -void video_driver_set_osd_msg(const char *msg, - const void *params, void *font); - -void video_driver_set_texture_enable(bool enable, bool full_screen); - -void video_driver_set_texture_frame(const void *frame, bool rgb32, - unsigned width, unsigned height, float alpha); - -#ifdef HAVE_OVERLAY -bool video_driver_overlay_interface( - const video_overlay_interface_t **iface); -#endif - -void * video_driver_read_frame_raw(unsigned *width, - unsigned *height, size_t *pitch); - -void video_driver_set_filtering(unsigned index, bool smooth); - -const char *video_driver_get_ident(void); - -bool video_driver_set_viewport(unsigned width, unsigned height, - bool force_fullscreen, bool allow_rotate); - -void video_driver_get_size(unsigned *width, unsigned *height); - -void video_driver_set_size(unsigned *width, unsigned *height); - -void video_driver_unset_video_cache_context_ack(void); - -float video_driver_get_aspect_ratio(void); - -void video_driver_set_aspect_ratio_value(float value); - -rarch_softfilter_t *video_driver_frame_filter_get_ptr(void); - -enum retro_pixel_format video_driver_get_pixel_format(void); - -void video_driver_set_pixel_format(enum retro_pixel_format fmt); - -void video_driver_cached_frame_set(const void *data, unsigned width, - unsigned height, size_t pitch); - -void video_driver_cached_frame_get(const void **data, unsigned *width, - unsigned *height, size_t *pitch); - -void video_driver_menu_settings(void **list_data, void *list_info_data, - void *group_data, void *subgroup_data, const char *parent_group); - -/** - * video_viewport_get_scaled_integer: - * @vp : Viewport handle - * @width : Width. - * @height : Height. - * @aspect_ratio : Aspect ratio (in float). - * @keep_aspect : Preserve aspect ratio? - * - * Gets viewport scaling dimensions based on - * scaled integer aspect ratio. - **/ -void video_viewport_get_scaled_integer(struct video_viewport *vp, - unsigned width, unsigned height, - float aspect_ratio, bool keep_aspect); - -struct retro_system_av_info *video_viewport_get_system_av_info(void); - -struct video_viewport *video_viewport_get_custom(void); - -/** - * video_monitor_set_refresh_rate: - * @hz : New refresh rate for monitor. - * - * Sets monitor refresh rate to new value. - **/ -void video_monitor_set_refresh_rate(float hz); - -/** - * video_monitor_fps_statistics - * @refresh_rate : Monitor refresh rate. - * @deviation : Deviation from measured refresh rate. - * @sample_points : Amount of sampled points. - * - * Gets the monitor FPS statistics based on the current - * runtime. - * - * Returns: true (1) on success. - * false (0) if: - * a) threaded video mode is enabled - * b) less than 2 frame time samples. - * c) FPS monitor enable is off. - **/ -bool video_monitor_fps_statistics(double *refresh_rate, - double *deviation, unsigned *sample_points); - -unsigned video_pixel_get_alignment(unsigned pitch); - -const video_poke_interface_t *video_driver_get_poke(void); - -/** - * video_driver_frame: - * @data : pointer to data of the video frame. - * @width : width of the video frame. - * @height : height of the video frame. - * @pitch : pitch of the video frame. - * - * Video frame render callback function. - **/ -void video_driver_frame(const void *data, unsigned width, - unsigned height, size_t pitch); - -#define video_driver_translate_coord_viewport_wrap(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) \ - (video_driver_get_viewport_info(vp) ? video_driver_translate_coord_viewport(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) : false) - -/** - * video_driver_translate_coord_viewport: - * @mouse_x : Pointer X coordinate. - * @mouse_y : Pointer Y coordinate. - * @res_x : Scaled X coordinate. - * @res_y : Scaled Y coordinate. - * @res_screen_x : Scaled screen X coordinate. - * @res_screen_y : Scaled screen Y coordinate. - * - * Translates pointer [X,Y] coordinates into scaled screen - * coordinates based on viewport info. - * - * Returns: true (1) if successful, false if video driver doesn't support - * viewport info. - **/ -bool video_driver_translate_coord_viewport( - struct video_viewport *vp, - int mouse_x, int mouse_y, - int16_t *res_x, int16_t *res_y, int16_t *res_screen_x, - int16_t *res_screen_y); - -uintptr_t video_driver_display_get(void); - -enum rarch_display_type video_driver_display_type_get(void); - -uintptr_t video_driver_window_get(void); - -void video_driver_display_type_set(enum rarch_display_type type); - -void video_driver_display_set(uintptr_t idx); - -void video_driver_window_set(uintptr_t idx); - -bool video_driver_texture_load(void *data, - enum texture_filter_type filter_type, - uintptr_t *id); - -bool video_driver_texture_unload(uintptr_t *id); - -void video_driver_build_info(video_frame_info_t *video_info); - -void video_driver_reinit(void); - -void video_driver_get_window_title(char *buf, unsigned len); - -void video_driver_get_record_status( - bool *has_gpu_record, - uint8_t **gpu_buf); - -bool *video_driver_get_threaded(void); - -void video_driver_set_threaded(bool val); - -void video_driver_get_status(uint64_t *frame_count, bool * is_alive, - bool *is_focused); - -/** - * video_context_driver_init_first: - * @data : Input data. - * @ident : Identifier of graphics context driver to find. - * @api : API of higher-level graphics API. - * @major : Major version number of higher-level graphics API. - * @minor : Minor version number of higher-level graphics API. - * @hw_render_ctx : Request a graphics context driver capable of - * hardware rendering? - * - * Finds first suitable graphics context driver and initializes. - * - * Returns: graphics context driver if found, otherwise NULL. - **/ -const gfx_ctx_driver_t *video_context_driver_init_first( - void *data, const char *ident, - enum gfx_ctx_api api, unsigned major, unsigned minor, - bool hw_render_ctx, void **ctx_data); - -bool video_context_driver_find_prev_driver(void); - -bool video_context_driver_find_next_driver(void); - -bool video_context_driver_init_image_buffer(const video_info_t *data); - -bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img); - -bool video_context_driver_get_video_output_prev(void); - -bool video_context_driver_get_video_output_next(void); - -bool video_context_driver_bind_hw_render(bool *enable); - -void video_context_driver_make_current(bool restore); - -bool video_context_driver_set(const gfx_ctx_driver_t *data); - -void video_context_driver_destroy(void); - -bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data); - -bool video_context_driver_swap_interval(int *interval); - -bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc); - -bool video_context_driver_suppress_screensaver(bool *bool_data); - -bool video_context_driver_get_ident(gfx_ctx_ident_t *ident); - -bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info); - -bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info); - -bool video_context_driver_get_refresh_rate(float *refresh_rate); - -bool video_context_driver_show_mouse(bool *bool_data); - -bool video_context_driver_set_flags(gfx_ctx_flags_t *flags); - -bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics); - -bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect); - -bool video_context_driver_input_driver(gfx_ctx_input_t *inp); - -enum gfx_ctx_api video_context_driver_get_api(void); - -void video_context_driver_free(void); - -bool video_shader_driver_get_prev_textures(video_shader_ctx_texture_t *texture); - -bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident); - -bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader); - -bool video_shader_driver_direct_get_current_shader(video_shader_ctx_t *shader); - -bool video_shader_driver_deinit(void); - -void video_shader_driver_set_parameter(struct uniform_info *param); - -void video_shader_driver_set_parameters(video_shader_ctx_params_t *params); - -bool video_shader_driver_init_first(void); - -bool video_shader_driver_init(video_shader_ctx_init_t *init); - -bool video_shader_driver_get_feedback_pass(unsigned *data); - -bool video_shader_driver_mipmap_input(unsigned *index); - -void video_driver_set_coords(video_shader_ctx_coords_t *coords); - -bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler); - -bool video_shader_driver_info(video_shader_ctx_info_t *shader_info); - -void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp); - -bool video_shader_driver_filter_type(video_shader_ctx_filter_t *filter); - -bool video_shader_driver_compile_program(struct shader_program_info *program_info); - -void video_shader_driver_use(video_shader_ctx_info_t *shader_info); - -bool video_shader_driver_wrap_type(video_shader_ctx_wrap_t *wrap); - -float video_driver_get_refresh_rate(void); - -extern bool (*video_driver_cb_has_focus)(void); - -bool video_driver_started_fullscreen(void); - -bool video_driver_is_threaded(void); - -bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, - enum display_flags flag); - -extern video_driver_t video_gl; -extern video_driver_t video_vulkan; -extern video_driver_t video_metal; -extern video_driver_t video_psp1; -extern video_driver_t video_vita2d; -extern video_driver_t video_ps2; -extern video_driver_t video_ctr; -extern video_driver_t video_switch; -extern video_driver_t video_d3d8; -extern video_driver_t video_d3d9; -extern video_driver_t video_d3d10; -extern video_driver_t video_d3d11; -extern video_driver_t video_d3d12; -extern video_driver_t video_gx; -extern video_driver_t video_wiiu; -extern video_driver_t video_xenon360; -extern video_driver_t video_xvideo; -extern video_driver_t video_sdl; -extern video_driver_t video_sdl2; -extern video_driver_t video_vg; -extern video_driver_t video_omap; -extern video_driver_t video_exynos; -extern video_driver_t video_dispmanx; -extern video_driver_t video_sunxi; -extern video_driver_t video_drm; -extern video_driver_t video_xshm; -extern video_driver_t video_caca; -extern video_driver_t video_gdi; -extern video_driver_t video_vga; -extern video_driver_t video_sixel; -extern video_driver_t video_null; - -extern const gfx_ctx_driver_t gfx_ctx_osmesa; -extern const gfx_ctx_driver_t gfx_ctx_sdl_gl; -extern const gfx_ctx_driver_t gfx_ctx_x_egl; -extern const gfx_ctx_driver_t gfx_ctx_wayland; -extern const gfx_ctx_driver_t gfx_ctx_x; -extern const gfx_ctx_driver_t gfx_ctx_drm; -extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev; -extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev; -extern const gfx_ctx_driver_t gfx_ctx_android; -extern const gfx_ctx_driver_t gfx_ctx_ps3; -extern const gfx_ctx_driver_t gfx_ctx_wgl; -extern const gfx_ctx_driver_t gfx_ctx_videocore; -extern const gfx_ctx_driver_t gfx_ctx_qnx; -extern const gfx_ctx_driver_t gfx_ctx_cgl; -extern const gfx_ctx_driver_t gfx_ctx_cocoagl; -extern const gfx_ctx_driver_t gfx_ctx_emscripten; -extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; -extern const gfx_ctx_driver_t gfx_ctx_khr_display; -extern const gfx_ctx_driver_t gfx_ctx_gdi; -extern const gfx_ctx_driver_t gfx_ctx_sixel; -extern const gfx_ctx_driver_t switch_ctx; -extern const gfx_ctx_driver_t orbis_ctx; -extern const gfx_ctx_driver_t gfx_ctx_null; - -extern const shader_backend_t gl_glsl_backend; -extern const shader_backend_t gl_cg_backend; -extern const shader_backend_t shader_null_backend; - -RETRO_END_DECLS - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __VIDEO_DRIVER__H +#define __VIDEO_DRIVER__H + +#include +#include +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#ifdef HAVE_OVERLAY +#include "../input/input_overlay.h" +#endif + +#include "video_defines.h" +#include "video_coord_array.h" +#include "video_filter.h" +#include "video_shader_parse.h" +#include "video_state_tracker.h" + +#include "../input/input_driver.h" + +#define RARCH_SCALE_BASE 256 + +#include "video_shader_parse.h" + +#define VIDEO_SHADER_STOCK_BLEND (GFX_MAX_SHADERS - 1) +#define VIDEO_SHADER_MENU (GFX_MAX_SHADERS - 2) +#define VIDEO_SHADER_MENU_2 (GFX_MAX_SHADERS - 3) +#define VIDEO_SHADER_MENU_3 (GFX_MAX_SHADERS - 4) +#define VIDEO_SHADER_MENU_4 (GFX_MAX_SHADERS - 5) +#define VIDEO_SHADER_MENU_5 (GFX_MAX_SHADERS - 6) +#define VIDEO_SHADER_MENU_6 (GFX_MAX_SHADERS - 7) + +#if defined(_XBOX360) +#define DEFAULT_SHADER_TYPE RARCH_SHADER_HLSL +#elif defined(__PSL1GHT__) || defined(HAVE_OPENGLES2) || defined(HAVE_GLSL) +#define DEFAULT_SHADER_TYPE RARCH_SHADER_GLSL +#elif defined(__CELLOS_LV2__) || defined(HAVE_CG) +#define DEFAULT_SHADER_TYPE RARCH_SHADER_CG +#else +#define DEFAULT_SHADER_TYPE RARCH_SHADER_NONE +#endif + +RETRO_BEGIN_DECLS + +#ifndef MAX_EGLIMAGE_TEXTURES +#define MAX_EGLIMAGE_TEXTURES 32 +#endif + +#define MAX_VARIABLES 64 + +enum +{ + TEXTURES = 8, + TEXTURESMASK = TEXTURES - 1 +}; + +struct LinkInfo +{ + unsigned tex_w, tex_h; + struct video_shader_pass *pass; +}; + +enum gfx_ctx_api +{ + GFX_CTX_NONE = 0, + GFX_CTX_OPENGL_API, + GFX_CTX_OPENGL_ES_API, + GFX_CTX_DIRECT3D8_API, + GFX_CTX_DIRECT3D9_API, + GFX_CTX_DIRECT3D10_API, + GFX_CTX_DIRECT3D11_API, + GFX_CTX_DIRECT3D12_API, + GFX_CTX_OPENVG_API, + GFX_CTX_VULKAN_API, + GFX_CTX_SIXEL_API, + GFX_CTX_METAL_API, + GFX_CTX_GDI_API, + GFX_CTX_GX_API, + GFX_CTX_GX2_API +}; + +enum display_metric_types +{ + DISPLAY_METRIC_NONE = 0, + DISPLAY_METRIC_MM_WIDTH, + DISPLAY_METRIC_MM_HEIGHT, + DISPLAY_METRIC_DPI +}; + +enum display_flags +{ + GFX_CTX_FLAGS_NONE = 0, + GFX_CTX_FLAGS_GL_CORE_CONTEXT, + GFX_CTX_FLAGS_MULTISAMPLING, + GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES, + GFX_CTX_FLAGS_HARD_SYNC, + GFX_CTX_FLAGS_BLACK_FRAME_INSERTION, + GFX_CTX_FLAGS_MENU_FRAME_FILTERING, + GFX_CTX_FLAGS_ADAPTIVE_VSYNC +}; + +enum shader_uniform_type +{ + UNIFORM_1F = 0, + UNIFORM_2F, + UNIFORM_3F, + UNIFORM_4F, + UNIFORM_1FV, + UNIFORM_2FV, + UNIFORM_3FV, + UNIFORM_4FV, + UNIFORM_1I +}; + +enum shader_program_type +{ + SHADER_PROGRAM_VERTEX = 0, + SHADER_PROGRAM_FRAGMENT, + SHADER_PROGRAM_COMBINED +}; + +struct shader_program_info +{ + bool is_file; + const char *vertex; + const char *fragment; + const char *combined; + unsigned idx; + void *data; +}; + +struct uniform_info +{ + bool enabled; + + int32_t location; + int32_t count; + unsigned type; /* shader uniform type */ + + struct + { + enum shader_program_type type; + const char *ident; + uint32_t idx; + bool add_prefix; + bool enable; + } lookup; + + struct + { + struct + { + intptr_t v0; + intptr_t v1; + intptr_t v2; + intptr_t v3; + } integer; + + intptr_t *integerv; + + struct + { + uintptr_t v0; + uintptr_t v1; + uintptr_t v2; + uintptr_t v3; + } unsigned_integer; + + uintptr_t *unsigned_integerv; + + struct + { + float v0; + float v1; + float v2; + float v3; + } f; + + float *floatv; + } result; +}; + +typedef struct shader_backend +{ + void *(*init)(void *data, const char *path); + void (*init_menu_shaders)(void *data); + void (*deinit)(void *data); + + /* Set shader parameters. */ + void (*set_params)(void *data, void *shader_data); + + void (*set_uniform_parameter)(void *data, struct uniform_info *param, + void *uniform_data); + + /* Compile a shader program. */ + bool (*compile_program)(void *data, unsigned idx, + void *program_data, struct shader_program_info *program_info); + + /* Use a shader program specified by variable 'index'. */ + void (*use)(void *data, void *shader_data, unsigned index, bool set_active); + + /* Returns the number of currently loaded shaders. */ + unsigned (*num_shaders)(void *data); + + bool (*filter_type)(void *data, unsigned index, bool *smooth); + enum gfx_wrap_type (*wrap_type)(void *data, unsigned index); + void (*shader_scale)(void *data, + unsigned index, struct gfx_fbo_scale *scale); + bool (*set_coords)(void *handle_data, + void *shader_data, const struct video_coords *coords); + bool (*set_mvp)(void *data, void *shader_data, + const void *mat_data); + unsigned (*get_prev_textures)(void *data); + bool (*get_feedback_pass)(void *data, unsigned *pass); + bool (*mipmap_input)(void *data, unsigned index); + + struct video_shader *(*get_current_shader)(void *data); + + enum rarch_shader_type type; + + /* Human readable string. */ + const char *ident; +} shader_backend_t; + +typedef struct video_shader_ctx_init +{ + enum rarch_shader_type shader_type; + const char *path; + const shader_backend_t *shader; + void *data; + struct + { + bool core_context_enabled; + } gl; +} video_shader_ctx_init_t; + +typedef struct video_shader_ctx_params +{ + unsigned width; + unsigned height; + unsigned tex_width; + unsigned tex_height; + unsigned out_width; + unsigned out_height; + unsigned frame_counter; + unsigned fbo_info_cnt; + void *data; + const void *info; + const void *prev_info; + const void *feedback_info; + const void *fbo_info; +} video_shader_ctx_params_t; + +typedef struct video_shader_ctx_coords +{ + void *handle_data; + const void *data; +} video_shader_ctx_coords_t; + +typedef struct video_shader_ctx_scale +{ + unsigned idx; + struct gfx_fbo_scale *scale; +} video_shader_ctx_scale_t; + +typedef struct video_shader_ctx_info +{ + bool set_active; + unsigned num; + unsigned idx; + void *data; +} video_shader_ctx_info_t; + +typedef struct video_shader_ctx_mvp +{ + void *data; + const void *matrix; +} video_shader_ctx_mvp_t; + +typedef struct video_shader_ctx_filter +{ + unsigned index; + bool *smooth; +} video_shader_ctx_filter_t; + +typedef struct video_shader_ctx_wrap +{ + unsigned idx; + enum gfx_wrap_type type; +} video_shader_ctx_wrap_t; + +typedef struct video_shader_ctx +{ + struct video_shader *data; +} video_shader_ctx_t; + +typedef struct video_shader_ctx_ident +{ + const char *ident; +} video_shader_ctx_ident_t; + +typedef struct video_shader_ctx_texture +{ + unsigned id; +} video_shader_ctx_texture_t; + +typedef void (*gfx_ctx_proc_t)(void); + +typedef struct video_info +{ + /* Launch in fullscreen mode instead of windowed mode. */ + bool fullscreen; + + /* Start with V-Sync enabled. */ + bool vsync; + + /* If true, the output image should have the aspect ratio + * as set in aspect_ratio. */ + bool force_aspect; + + bool font_enable; + + /* Width of window. + * If fullscreen mode is requested, + * a width of 0 means the resolution of the + * desktop should be used. */ + unsigned width; + + /* Height of window. + * If fullscreen mode is requested, + * a height of 0 means the resolutiof the desktop should be used. + */ + unsigned height; + + int swap_interval; + +#ifdef GEKKO + bool vfilter; +#endif + + /* If true, applies bilinear filtering to the image, + * otherwise nearest filtering. */ + bool smooth; + + bool is_threaded; + + /* Use 32bit RGBA rather than native RGB565/XBGR1555. + * + * XRGB1555 format is 16-bit and has byte ordering: 0RRRRRGGGGGBBBBB, + * in native endian. + * + * ARGB8888 is AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB, native endian. + * Alpha channel should be disregarded. + * */ + bool rgb32; + +#ifdef GEKKO + /* TODO - we can't really have driver system-specific + * variables in here. There should be some + * kind of publicly accessible driver implementation + * video struct for specific things like this. + */ + + /* Wii-specific settings. Ignored for everything else. */ + unsigned viwidth; +#endif + + /* + * input_scale defines the maximum size of the picture that will + * ever be used with the frame callback. + * + * The maximum resolution is a multiple of 256x256 size (RARCH_SCALE_BASE), + * so an input scale of 2 means you should allocate a texture or of 512x512. + * + * Maximum input size: RARCH_SCALE_BASE * input_scale + */ + unsigned input_scale; + + uintptr_t parent; +} video_info_t; + +typedef struct video_frame_info +{ + bool input_menu_swap_ok_cancel_buttons; + bool input_driver_nonblock_state; + bool shared_context; + bool black_frame_insertion; + bool hard_sync; + bool fps_show; + bool statistics_show; + bool framecount_show; + bool scale_integer; + bool post_filter_record; + bool windowed_fullscreen; + bool fullscreen; + bool font_enable; + bool use_rgba; + bool libretro_running; + bool xmb_shadows_enable; + bool battery_level_enable; + bool timedate_enable; + bool runloop_is_slowmotion; + bool runloop_is_idle; + bool runloop_is_paused; + bool is_perfcnt_enable; + bool menu_is_alive; + bool msg_bgcolor_enable; + + int custom_vp_x; + int custom_vp_y; + int crt_switch_center_adjust; + + unsigned hard_sync_frames; + unsigned aspect_ratio_idx; + unsigned max_swapchain_images; + unsigned monitor_index; + unsigned crt_switch_resolution; + unsigned crt_switch_resolution_super; + unsigned width; + unsigned height; + unsigned xmb_theme; + unsigned xmb_color_theme; + unsigned menu_shader_pipeline; + unsigned materialui_color_theme; + unsigned ozone_color_theme; + unsigned custom_vp_width; + unsigned custom_vp_height; + unsigned custom_vp_full_width; + unsigned custom_vp_full_height; + + float menu_wallpaper_opacity; + float menu_framebuffer_opacity; + float menu_header_opacity; + float menu_footer_opacity; + float refresh_rate; + float font_msg_pos_x; + float font_msg_pos_y; + float font_msg_color_r; + float font_msg_color_g; + float font_msg_color_b; + float xmb_alpha_factor; + + char fps_text[128]; + char stat_text[512]; + char chat_text[256]; + + uint64_t frame_count; + float frame_time; + float frame_rate; + + struct + { + float x; + float y; + float scale; + /* Drop shadow color multiplier. */ + float drop_mod; + /* Drop shadow offset. + * If both are 0, no drop shadow will be rendered. */ + int drop_x, drop_y; + /* Drop shadow alpha */ + float drop_alpha; + /* ABGR. Use the macros. */ + uint32_t color; + bool full_screen; + enum text_alignment text_align; + } osd_stat_params; + + void (*cb_update_window_title)(void*, void *); + void (*cb_swap_buffers)(void*, void *); + bool (*cb_get_metrics)(void *data, enum display_metric_types type, + float *value); + bool (*cb_set_resize)(void*, unsigned, unsigned); + + bool (*cb_set_mvp)(void *data, void *shader_data, + const void *mat_data); + + void *context_data; + void *shader_data; + void *userdata; + const shader_backend_t *shader_driver; +} video_frame_info_t; + +typedef void (*update_window_title_cb)(void*, void*); +typedef bool (*get_metrics_cb)(void *data, enum display_metric_types type, + float *value); +typedef bool (*set_resize_cb)(void*, unsigned, unsigned); + +typedef struct gfx_ctx_driver +{ + /* The opaque pointer is the underlying video driver data (e.g. gl_t for + * OpenGL contexts). Although not advised, the context driver is allowed + * to hold a pointer to it as the context never outlives the video driver. + * + * The context driver is responsible for it's own data.*/ + void* (*init)(video_frame_info_t *video_info, void *video_driver); + void (*destroy)(void *data); + + enum gfx_ctx_api (*get_api)(void *data); + + /* Which API to bind to. */ + bool (*bind_api)(void *video_driver, enum gfx_ctx_api, + unsigned major, unsigned minor); + + /* Sets the swap interval. */ + void (*swap_interval)(void *data, int); + + /* Sets video mode. Creates a window, etc. */ + bool (*set_video_mode)(void*, video_frame_info_t *video_info, unsigned, unsigned, bool); + + /* Gets current window size. + * If not initialized yet, it returns current screen size. */ + void (*get_video_size)(void*, unsigned*, unsigned*); + + float (*get_refresh_rate)(void*); + + void (*get_video_output_size)(void*, unsigned*, unsigned*); + + void (*get_video_output_prev)(void*); + + void (*get_video_output_next)(void*); + + get_metrics_cb get_metrics; + + /* Translates a window size to an aspect ratio. + * In most cases this will be just width / height, but + * some contexts will better know which actual aspect ratio is used. + * This can be NULL to assume the default behavior. + */ + float (*translate_aspect)(void*, unsigned, unsigned); + + /* Asks driver to update window title (FPS, etc). */ + update_window_title_cb update_window_title; + + /* Queries for resize and quit events. + * Also processes events. */ + void (*check_window)(void*, bool*, bool*, + unsigned*, unsigned*, bool); + + /* Acknowledge a resize event. This is needed for some APIs. + * Most backends will ignore this. */ + set_resize_cb set_resize; + + /* Checks if window has input focus. */ + bool (*has_focus)(void*); + + /* Should the screensaver be suppressed? */ + bool (*suppress_screensaver)(void *data, bool enable); + + /* Checks if context driver has windowed support. */ + bool (*has_windowed)(void*); + + /* Swaps buffers. VBlank sync depends on + * earlier calls to swap_interval. */ + void (*swap_buffers)(void*, void *); + + /* Most video backends will want to use a certain input driver. + * Checks for it here. */ + void (*input_driver)(void*, const char *, const input_driver_t**, void**); + + /* Wraps whatever gl_proc_address() there is. + * Does not take opaque, to avoid lots of ugly wrapper code. */ + gfx_ctx_proc_t (*get_proc_address)(const char*); + + /* Returns true if this context supports EGLImage buffers for + * screen drawing and was initalized correctly. */ + bool (*image_buffer_init)(void*, const video_info_t*); + + /* Writes the frame to the EGLImage and sets image_handle to it. + * Returns true if a new image handle is created. + * Always returns true the first time it's called for a new index. + * The graphics core must handle a change in the handle correctly. */ + bool (*image_buffer_write)(void*, const void *frame, unsigned width, + unsigned height, unsigned pitch, bool rgb32, + unsigned index, void **image_handle); + + /* Shows or hides mouse. Can be NULL if context doesn't + * have a concept of mouse pointer. */ + void (*show_mouse)(void *data, bool state); + + /* Human readable string. */ + const char *ident; + + uint32_t (*get_flags)(void *data); + + void (*set_flags)(void *data, uint32_t flags); + + /* Optional. Binds HW-render offscreen context. */ + void (*bind_hw_render)(void *data, bool enable); + + /* Optional. Gets base data for the context which is used by the driver. + * This is mostly relevant for graphics APIs such as Vulkan + * which do not have global context state. */ + void *(*get_context_data)(void *data); + + /* Optional. Makes driver context (only GLX right now) + * active for this thread. */ + void (*make_current)(bool release); +} gfx_ctx_driver_t; + +typedef struct gfx_ctx_flags +{ + uint32_t flags; +} gfx_ctx_flags_t; + +typedef struct gfx_ctx_size +{ + bool *quit; + bool *resize; + unsigned *width; + unsigned *height; +} gfx_ctx_size_t; + +typedef struct gfx_ctx_mode +{ + unsigned width; + unsigned height; + bool fullscreen; +} gfx_ctx_mode_t; + +typedef struct gfx_ctx_metrics +{ + enum display_metric_types type; + float *value; +} gfx_ctx_metrics_t; + +typedef struct gfx_ctx_aspect +{ + float *aspect; + unsigned width; + unsigned height; +} gfx_ctx_aspect_t; + +typedef struct gfx_ctx_image +{ + const void *frame; + unsigned width; + unsigned height; + unsigned pitch; + unsigned index; + bool rgb32; + void **handle; +} gfx_ctx_image_t; + +typedef struct gfx_ctx_input +{ + const input_driver_t **input; + void **input_data; +} gfx_ctx_input_t; + +typedef struct gfx_ctx_proc_address +{ + const char *sym; + retro_proc_address_t addr; +} gfx_ctx_proc_address_t; + +typedef struct gfx_ctx_ident +{ + const char *ident; +} gfx_ctx_ident_t; + +typedef struct video_viewport +{ + int x; + int y; + unsigned width; + unsigned height; + unsigned full_width; + unsigned full_height; +} video_viewport_t; + +struct aspect_ratio_elem +{ + char name[64]; + float value; +}; + +/* Optionally implemented interface to poke more + * deeply into video driver. */ + +typedef struct video_poke_interface +{ + uint32_t (*get_flags)(void *data); + void (*set_coords)(void *handle_data, void *shader_data, + const struct video_coords *coords); + void (*set_mvp)(void *data, void *shader_data, + const void *mat_data); + uintptr_t (*load_texture)(void *video_data, void *data, + bool threaded, enum texture_filter_type filter_type); + void (*unload_texture)(void *data, uintptr_t id); + void (*set_video_mode)(void *data, unsigned width, + unsigned height, bool fullscreen); + float (*get_refresh_rate)(void *data); + void (*set_filtering)(void *data, unsigned index, bool smooth); + void (*get_video_output_size)(void *data, + unsigned *width, unsigned *height); + + /* Move index to previous resolution */ + void (*get_video_output_prev)(void *data); + + /* Move index to next resolution */ + void (*get_video_output_next)(void *data); + + uintptr_t (*get_current_framebuffer)(void *data); + retro_proc_address_t (*get_proc_address)(void *data, const char *sym); + void (*set_aspect_ratio)(void *data, unsigned aspectratio_index); + void (*apply_state_changes)(void *data); + + /* Update texture. */ + void (*set_texture_frame)(void *data, const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha); + /* Enable or disable rendering. */ + void (*set_texture_enable)(void *data, bool enable, bool full_screen); + void (*set_osd_msg)(void *data, video_frame_info_t *video_info, + const char *msg, + const void *params, void *font); + + void (*show_mouse)(void *data, bool state); + void (*grab_mouse_toggle)(void *data); + + struct video_shader *(*get_current_shader)(void *data); + bool (*get_current_software_framebuffer)(void *data, + struct retro_framebuffer *framebuffer); + bool (*get_hw_render_interface)(void *data, + const struct retro_hw_render_interface **iface); +} video_poke_interface_t; + +/* msg is for showing a message on the screen + * along with the video frame. */ +typedef bool (*video_driver_frame_t)(void *data, + const void *frame, unsigned width, + unsigned height, uint64_t frame_count, + unsigned pitch, const char *msg, video_frame_info_t *video_info); + +typedef struct video_driver +{ + /* Should the video driver act as an input driver as well? + * The video initialization might preinitialize an input driver + * to override the settings in case the video driver relies on + * input driver for event handling. */ + void *(*init)(const video_info_t *video, + const input_driver_t **input, + void **input_data); + + /* Updates frame on the screen. + * Frame can be either XRGB1555, RGB565 or ARGB32 format + * depending on rgb32 setting in video_info_t. + * Pitch is the distance in bytes between two scanlines in memory. + * + * When msg is non-NULL, + * it's a message that should be displayed to the user. */ + video_driver_frame_t frame; + + /* Should we care about syncing to vblank? Fast forwarding. + * + * Requests nonblocking operation. + * + * True = VSync is turned off. + * False = VSync is turned on. + * */ + void (*set_nonblock_state)(void *data, bool toggle); + + /* Is the window still active? */ + bool (*alive)(void *data); + + /* Does the window have focus? */ + bool (*focus)(void *data); + + /* Should the screensaver be suppressed? */ + bool (*suppress_screensaver)(void *data, bool enable); + + /* Does the graphics context support windowed mode? */ + bool (*has_windowed)(void *data); + + /* Sets shader. Might not be implemented. Will be moved to + * poke_interface later. */ + bool (*set_shader)(void *data, enum rarch_shader_type type, + const char *path); + + /* Frees driver. */ + void (*free)(void *data); + + /* Human-readable identifier. */ + const char *ident; + + void (*set_viewport)(void *data, unsigned width, unsigned height, + bool force_full, bool allow_rotate); + + void (*set_rotation)(void *data, unsigned rotation); + void (*viewport_info)(void *data, struct video_viewport *vp); + + /* Reads out in BGR byte order (24bpp). */ + bool (*read_viewport)(void *data, uint8_t *buffer, bool is_idle); + + /* Returns a pointer to a newly allocated buffer that can + * (and must) be passed to free() by the caller, containing a + * copy of the current raw frame in the active pixel format + * and sets width, height and pitch to the correct values. */ + void* (*read_frame_raw)(void *data, unsigned *width, + unsigned *height, size_t *pitch); + +#ifdef HAVE_OVERLAY + void (*overlay_interface)(void *data, + const video_overlay_interface_t **iface); +#endif + void (*poke_interface)(void *data, const video_poke_interface_t **iface); + unsigned (*wrap_type_to_enum)(enum gfx_wrap_type type); +} video_driver_t; + +extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END]; + +bool video_driver_has_windowed(void); + +bool video_driver_cached_frame_has_valid_framebuffer(void); + +void video_driver_destroy(void); +void video_driver_set_cached_frame_ptr(const void *data); +void video_driver_set_stub_frame(void); +void video_driver_unset_stub_frame(void); +bool video_driver_is_stub_frame(void); +bool video_driver_supports_recording(void); +bool video_driver_supports_viewport_read(void); +bool video_driver_supports_read_frame_raw(void); +void video_driver_set_viewport_config(void); +void video_driver_set_viewport_square_pixel(void); +void video_driver_set_viewport_core(void); +void video_driver_reset_custom_viewport(void); +void video_driver_set_rgba(void); +void video_driver_unset_rgba(void); +bool video_driver_supports_rgba(void); +bool video_driver_get_next_video_out(void); +bool video_driver_get_prev_video_out(void); +bool video_driver_init(bool *video_is_threaded); +void video_driver_destroy_data(void); +void video_driver_free(void); +void video_driver_free_hw_context(void); +void video_driver_monitor_reset(void); +void video_driver_set_aspect_ratio(void); +void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect); +void video_driver_show_mouse(void); +void video_driver_hide_mouse(void); +void video_driver_set_nonblock_state(bool toggle); +bool video_driver_find_driver(void); +void video_driver_apply_state_changes(void); +bool video_driver_read_viewport(uint8_t *buffer, bool is_idle); +bool video_driver_cached_frame(void); +bool video_driver_frame_filter_alive(void); +bool video_driver_frame_filter_is_32bit(void); +void video_driver_default_settings(void); +void video_driver_load_settings(config_file_t *conf); +void video_driver_save_settings(config_file_t *conf); +void video_driver_set_own_driver(void); +void video_driver_unset_own_driver(void); +bool video_driver_owns_driver(void); +bool video_driver_is_hw_context(void); +struct retro_hw_render_callback *video_driver_get_hw_context(void); +const struct retro_hw_render_context_negotiation_interface +*video_driver_get_context_negotiation_interface(void); +void video_driver_set_context_negotiation_interface(const struct + retro_hw_render_context_negotiation_interface *iface); +bool video_driver_is_video_cache_context(void); +void video_driver_set_video_cache_context_ack(void); +bool video_driver_is_video_cache_context_ack(void); +void video_driver_set_active(void); +void video_driver_unset_active(void); +bool video_driver_is_active(void); +bool video_driver_gpu_record_init(unsigned size); +void video_driver_gpu_record_deinit(void); +bool video_driver_get_current_software_framebuffer(struct + retro_framebuffer *fb); +bool video_driver_get_hw_render_interface(const struct + retro_hw_render_interface **iface); +bool video_driver_get_viewport_info(struct video_viewport *viewport); +void video_driver_set_title_buf(void); +void video_driver_monitor_adjust_system_rates(void); + +/** + * video_driver_find_handle: + * @index : index of driver to get handle to. + * + * Returns: handle to video driver at index. Can be NULL + * if nothing found. + **/ +const void *video_driver_find_handle(int index); + +/** + * video_driver_find_ident: + * @index : index of driver to get handle to. + * + * Returns: Human-readable identifier of video driver at index. + * Can be NULL if nothing found. + **/ +const char *video_driver_find_ident(int index); + +/** + * config_get_video_driver_options: + * + * Get an enumerated list of all video driver names, separated by '|'. + * + * Returns: string listing of all video driver names, separated by '|'. + **/ +const char* config_get_video_driver_options(void); + +/** + * video_driver_get_ptr: + * + * Use this if you need the real video driver + * and driver data pointers. + * + * Returns: video driver's userdata. + **/ +void *video_driver_get_ptr(bool force_nonthreaded_data); + +/** + * video_driver_get_current_framebuffer: + * + * Gets pointer to current hardware renderer framebuffer object. + * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. + * + * Returns: pointer to hardware framebuffer object, otherwise 0. + **/ +uintptr_t video_driver_get_current_framebuffer(void); + +retro_proc_address_t video_driver_get_proc_address(const char *sym); + +bool video_driver_set_shader(enum rarch_shader_type type, + const char *shader); + +bool video_driver_set_rotation(unsigned rotation); + +bool video_driver_set_video_mode(unsigned width, + unsigned height, bool fullscreen); + +bool video_driver_get_video_output_size( + unsigned *width, unsigned *height); + +void video_driver_set_osd_msg(const char *msg, + const void *params, void *font); + +void video_driver_set_texture_enable(bool enable, bool full_screen); + +void video_driver_set_texture_frame(const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha); + +#ifdef HAVE_OVERLAY +bool video_driver_overlay_interface( + const video_overlay_interface_t **iface); +#endif + +void * video_driver_read_frame_raw(unsigned *width, + unsigned *height, size_t *pitch); + +void video_driver_set_filtering(unsigned index, bool smooth); + +const char *video_driver_get_ident(void); + +bool video_driver_set_viewport(unsigned width, unsigned height, + bool force_fullscreen, bool allow_rotate); + +void video_driver_get_size(unsigned *width, unsigned *height); + +void video_driver_set_size(unsigned *width, unsigned *height); + +void video_driver_unset_video_cache_context_ack(void); + +float video_driver_get_aspect_ratio(void); + +void video_driver_set_aspect_ratio_value(float value); + +rarch_softfilter_t *video_driver_frame_filter_get_ptr(void); + +enum retro_pixel_format video_driver_get_pixel_format(void); + +void video_driver_set_pixel_format(enum retro_pixel_format fmt); + +void video_driver_cached_frame_set(const void *data, unsigned width, + unsigned height, size_t pitch); + +void video_driver_cached_frame_get(const void **data, unsigned *width, + unsigned *height, size_t *pitch); + +void video_driver_menu_settings(void **list_data, void *list_info_data, + void *group_data, void *subgroup_data, const char *parent_group); + +/** + * video_viewport_get_scaled_integer: + * @vp : Viewport handle + * @width : Width. + * @height : Height. + * @aspect_ratio : Aspect ratio (in float). + * @keep_aspect : Preserve aspect ratio? + * + * Gets viewport scaling dimensions based on + * scaled integer aspect ratio. + **/ +void video_viewport_get_scaled_integer(struct video_viewport *vp, + unsigned width, unsigned height, + float aspect_ratio, bool keep_aspect); + +struct retro_system_av_info *video_viewport_get_system_av_info(void); + +struct video_viewport *video_viewport_get_custom(void); + +/** + * video_monitor_set_refresh_rate: + * @hz : New refresh rate for monitor. + * + * Sets monitor refresh rate to new value. + **/ +void video_monitor_set_refresh_rate(float hz); + +/** + * video_monitor_fps_statistics + * @refresh_rate : Monitor refresh rate. + * @deviation : Deviation from measured refresh rate. + * @sample_points : Amount of sampled points. + * + * Gets the monitor FPS statistics based on the current + * runtime. + * + * Returns: true (1) on success. + * false (0) if: + * a) threaded video mode is enabled + * b) less than 2 frame time samples. + * c) FPS monitor enable is off. + **/ +bool video_monitor_fps_statistics(double *refresh_rate, + double *deviation, unsigned *sample_points); + +unsigned video_pixel_get_alignment(unsigned pitch); + +const video_poke_interface_t *video_driver_get_poke(void); + +/** + * video_driver_frame: + * @data : pointer to data of the video frame. + * @width : width of the video frame. + * @height : height of the video frame. + * @pitch : pitch of the video frame. + * + * Video frame render callback function. + **/ +void video_driver_frame(const void *data, unsigned width, + unsigned height, size_t pitch); + +void crt_switch_driver_reinit(void); + +#define video_driver_translate_coord_viewport_wrap(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) \ + (video_driver_get_viewport_info(vp) ? video_driver_translate_coord_viewport(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) : false) + +/** + * video_driver_translate_coord_viewport: + * @mouse_x : Pointer X coordinate. + * @mouse_y : Pointer Y coordinate. + * @res_x : Scaled X coordinate. + * @res_y : Scaled Y coordinate. + * @res_screen_x : Scaled screen X coordinate. + * @res_screen_y : Scaled screen Y coordinate. + * + * Translates pointer [X,Y] coordinates into scaled screen + * coordinates based on viewport info. + * + * Returns: true (1) if successful, false if video driver doesn't support + * viewport info. + **/ +bool video_driver_translate_coord_viewport( + struct video_viewport *vp, + int mouse_x, int mouse_y, + int16_t *res_x, int16_t *res_y, int16_t *res_screen_x, + int16_t *res_screen_y); + +uintptr_t video_driver_display_get(void); + +enum rarch_display_type video_driver_display_type_get(void); + +uintptr_t video_driver_window_get(void); + +void video_driver_display_type_set(enum rarch_display_type type); + +void video_driver_display_set(uintptr_t idx); + +void video_driver_window_set(uintptr_t idx); + +bool video_driver_texture_load(void *data, + enum texture_filter_type filter_type, + uintptr_t *id); + +bool video_driver_texture_unload(uintptr_t *id); + +void video_driver_build_info(video_frame_info_t *video_info); + +void video_driver_reinit(void); + +void video_driver_get_window_title(char *buf, unsigned len); + +void video_driver_get_record_status( + bool *has_gpu_record, + uint8_t **gpu_buf); + +bool *video_driver_get_threaded(void); + +void video_driver_set_threaded(bool val); + +void video_driver_get_status(uint64_t *frame_count, bool * is_alive, + bool *is_focused); + +/** + * video_context_driver_init_first: + * @data : Input data. + * @ident : Identifier of graphics context driver to find. + * @api : API of higher-level graphics API. + * @major : Major version number of higher-level graphics API. + * @minor : Minor version number of higher-level graphics API. + * @hw_render_ctx : Request a graphics context driver capable of + * hardware rendering? + * + * Finds first suitable graphics context driver and initializes. + * + * Returns: graphics context driver if found, otherwise NULL. + **/ +const gfx_ctx_driver_t *video_context_driver_init_first( + void *data, const char *ident, + enum gfx_ctx_api api, unsigned major, unsigned minor, + bool hw_render_ctx, void **ctx_data); + +bool video_context_driver_find_prev_driver(void); + +bool video_context_driver_find_next_driver(void); + +bool video_context_driver_init_image_buffer(const video_info_t *data); + +bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img); + +bool video_context_driver_get_video_output_prev(void); + +bool video_context_driver_get_video_output_next(void); + +bool video_context_driver_bind_hw_render(bool *enable); + +void video_context_driver_make_current(bool restore); + +bool video_context_driver_set(const gfx_ctx_driver_t *data); + +void video_context_driver_destroy(void); + +bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data); + +bool video_context_driver_swap_interval(int *interval); + +bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc); + +bool video_context_driver_suppress_screensaver(bool *bool_data); + +bool video_context_driver_get_ident(gfx_ctx_ident_t *ident); + +bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info); + +bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info); + +bool video_context_driver_get_refresh_rate(float *refresh_rate); + +bool video_context_driver_show_mouse(bool *bool_data); + +bool video_context_driver_set_flags(gfx_ctx_flags_t *flags); + +bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics); + +bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect); + +bool video_context_driver_input_driver(gfx_ctx_input_t *inp); + +enum gfx_ctx_api video_context_driver_get_api(void); + +void video_context_driver_free(void); + +bool video_shader_driver_get_prev_textures(video_shader_ctx_texture_t *texture); + +bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident); + +bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader); + +bool video_shader_driver_direct_get_current_shader(video_shader_ctx_t *shader); + +bool video_shader_driver_deinit(void); + +void video_shader_driver_set_parameter(struct uniform_info *param); + +void video_shader_driver_set_parameters(video_shader_ctx_params_t *params); + +bool video_shader_driver_init_first(void); + +bool video_shader_driver_init(video_shader_ctx_init_t *init); + +bool video_shader_driver_get_feedback_pass(unsigned *data); + +bool video_shader_driver_mipmap_input(unsigned *index); + +void video_driver_set_coords(video_shader_ctx_coords_t *coords); + +bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler); + +bool video_shader_driver_info(video_shader_ctx_info_t *shader_info); + +void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp); + +bool video_shader_driver_filter_type(video_shader_ctx_filter_t *filter); + +bool video_shader_driver_compile_program(struct shader_program_info *program_info); + +void video_shader_driver_use(video_shader_ctx_info_t *shader_info); + +bool video_shader_driver_wrap_type(video_shader_ctx_wrap_t *wrap); + +float video_driver_get_refresh_rate(void); + +extern bool (*video_driver_cb_has_focus)(void); + +bool video_driver_started_fullscreen(void); + +bool video_driver_is_threaded(void); + +bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, + enum display_flags flag); + +extern video_driver_t video_gl; +extern video_driver_t video_vulkan; +extern video_driver_t video_metal; +extern video_driver_t video_psp1; +extern video_driver_t video_vita2d; +extern video_driver_t video_ps2; +extern video_driver_t video_ctr; +extern video_driver_t video_switch; +extern video_driver_t video_d3d8; +extern video_driver_t video_d3d9; +extern video_driver_t video_d3d10; +extern video_driver_t video_d3d11; +extern video_driver_t video_d3d12; +extern video_driver_t video_gx; +extern video_driver_t video_wiiu; +extern video_driver_t video_xenon360; +extern video_driver_t video_xvideo; +extern video_driver_t video_sdl; +extern video_driver_t video_sdl2; +extern video_driver_t video_vg; +extern video_driver_t video_omap; +extern video_driver_t video_exynos; +extern video_driver_t video_dispmanx; +extern video_driver_t video_sunxi; +extern video_driver_t video_drm; +extern video_driver_t video_xshm; +extern video_driver_t video_caca; +extern video_driver_t video_gdi; +extern video_driver_t video_vga; +extern video_driver_t video_sixel; +extern video_driver_t video_null; + +extern const gfx_ctx_driver_t gfx_ctx_osmesa; +extern const gfx_ctx_driver_t gfx_ctx_sdl_gl; +extern const gfx_ctx_driver_t gfx_ctx_x_egl; +extern const gfx_ctx_driver_t gfx_ctx_wayland; +extern const gfx_ctx_driver_t gfx_ctx_x; +extern const gfx_ctx_driver_t gfx_ctx_drm; +extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_android; +extern const gfx_ctx_driver_t gfx_ctx_ps3; +extern const gfx_ctx_driver_t gfx_ctx_wgl; +extern const gfx_ctx_driver_t gfx_ctx_videocore; +extern const gfx_ctx_driver_t gfx_ctx_qnx; +extern const gfx_ctx_driver_t gfx_ctx_cgl; +extern const gfx_ctx_driver_t gfx_ctx_cocoagl; +extern const gfx_ctx_driver_t gfx_ctx_emscripten; +extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_khr_display; +extern const gfx_ctx_driver_t gfx_ctx_gdi; +extern const gfx_ctx_driver_t gfx_ctx_sixel; +extern const gfx_ctx_driver_t switch_ctx; +extern const gfx_ctx_driver_t orbis_ctx; +extern const gfx_ctx_driver_t gfx_ctx_null; + +extern const shader_backend_t gl_glsl_backend; +extern const shader_backend_t gl_cg_backend; +extern const shader_backend_t shader_null_backend; + +RETRO_END_DECLS + +#endif