Merge pull request #369 from negativeExponent/switch
[pcsx_rearmed.git] / frontend / libretro.c
index c4d6133..ab85421 100644 (file)
 #include <sys/syscall.h>
 #endif
 
+#ifdef SWITCH
+#include <switch.h>
+#endif
+
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/psxcounters.h"
 #include "../libpcsxcore/psxmem_map.h"
 #include "../plugins/dfinput/externals.h"
 #include "cspace.h"
 #include "main.h"
+#include "menu.h"
 #include "plugin.h"
 #include "plugin_lib.h"
 #include "arm_features.h"
 #include "revision.h"
-#include "libretro.h"
+
+#include <libretro.h>
+#include "libretro_core_options.h"
 
 #ifdef _3DS
 #include "3ds/3ds_utils.h"
@@ -50,6 +57,8 @@
 
 #define ISHEXDEC ((buf[cursor]>='0') && (buf[cursor]<='9')) || ((buf[cursor]>='a') && (buf[cursor]<='f')) || ((buf[cursor]>='A') && (buf[cursor]<='F'))
 
+#define INTERNAL_FPS_SAMPLE_PERIOD 64
+
 //hack to prevent retroarch freezing when reseting in the menu but not while running with the hot key
 static int rebootemu = 0;
 
@@ -69,6 +78,14 @@ static int vout_doffs_old, vout_fb_dirty;
 static bool vout_can_dupe;
 static bool duping_enable;
 static bool found_bios;
+static bool display_internal_fps = false;
+static unsigned frame_count = 0;
+static bool libretro_supports_bitmasks = false;
+static int show_advanced_gpu_peops_settings = -1;
+static int show_advanced_gpu_unai_settings  = -1;
+
+static unsigned previous_width = 0;
+static unsigned previous_height = 0;
 
 static int plugins_opened;
 static int is_pal_mode;
@@ -122,6 +139,16 @@ static int snd_init(void){return 0;}
 static void snd_finish(void){}
 static int snd_busy(void){return 0;}
 
+#define GPU_PEOPS_ODD_EVEN_BIT         (1 << 0)
+#define GPU_PEOPS_EXPAND_SCREEN_WIDTH  (1 << 1)
+#define GPU_PEOPS_IGNORE_BRIGHTNESS    (1 << 2)
+#define GPU_PEOPS_DISABLE_COORD_CHECK  (1 << 3)
+#define GPU_PEOPS_LAZY_SCREEN_UPDATE   (1 << 6)
+#define GPU_PEOPS_OLD_FRAME_SKIP       (1 << 7)
+#define GPU_PEOPS_REPEATED_TRIANGLES   (1 << 8)
+#define GPU_PEOPS_QUADS_WITH_TRIANGLES (1 << 9)
+#define GPU_PEOPS_FAKE_BUSY_STATE      (1 << 10)
+
 static void init_memcard(char *mcd_data)
 {
        unsigned off = 0;
@@ -174,6 +201,16 @@ static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp)
   vout_width = w;
   vout_height = h;
 
+       if (previous_width != vout_width || previous_height != vout_height)
+       {
+               previous_width = vout_width;
+               previous_height = vout_height;
+
+       struct retro_system_av_info info;
+       retro_get_system_av_info(&info);
+       environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry);
+       }
+
   set_vout_fb();
 }
 
@@ -464,54 +501,12 @@ void out_register_libretro(struct out_driver *drv)
 /* libretro */
 void retro_set_environment(retro_environment_t cb)
 {
-   static const struct retro_variable vars[] = {
-      { "pcsx_rearmed_frameskip", "Frameskip; 0|1|2|3" },
-      { "pcsx_rearmed_bios", "Use BIOS; auto|HLE" },
-      { "pcsx_rearmed_region", "Region; auto|NTSC|PAL" },
-      { "pcsx_rearmed_memcard2", "Enable second memory card; disabled|enabled" },
-      { "pcsx_rearmed_pad1type", "Pad 1 Type; standard|analog|dualshock|negcon|none" },
-      { "pcsx_rearmed_pad2type", "Pad 2 Type; standard|analog|dualshock|negcon|none" },
-      { "pcsx_rearmed_pad3type", "Pad 3 Type; none|standard|analog|dualshock|negcon" },
-      { "pcsx_rearmed_pad4type", "Pad 4 Type; none|standard|analog|dualshock|negcon" },
-      { "pcsx_rearmed_pad5type", "Pad 5 Type; none|standard|analog|dualshock|negcon" },
-      { "pcsx_rearmed_pad6type", "Pad 6 Type; none|standard|analog|dualshock|negcon" },
-      { "pcsx_rearmed_pad7type", "Pad 7 Type; none|standard|analog|dualshock|negcon" },
-      { "pcsx_rearmed_pad8type", "Pad 8 Type; none|standard|analog|dualshock|negcon" },
-      { "pcsx_rearmed_multitap1", "Multitap 1; auto|disabled|enabled" },
-      { "pcsx_rearmed_multitap2", "Multitap 2; auto|disabled|enabled" },
-      { "pcsx_rearmed_negcon_deadzone", "NegCon Twist Deadzone (percent); 0|5|10|15|20|25|30" },
-      { "pcsx_rearmed_negcon_response", "NegCon Twist Response; linear|quadratic|cubic" },
-      { "pcsx_rearmed_vibration", "Enable Vibration; enabled|disabled" },
-      { "pcsx_rearmed_dithering", "Enable Dithering; enabled|disabled" },
-#ifndef DRC_DISABLE
-      { "pcsx_rearmed_drc", "Dynamic recompiler; enabled|disabled" },
-#ifdef HAVE_PRE_ARMV7
-      { "pcsx_rearmed_psxclock", "PSX cpu clock (default 50); 50|51|52|53|54|55|5657|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49" },
-#else
-      { "pcsx_rearmed_psxclock", "PSX cpu clock (default 57); 57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56" },
-#endif
-#endif
-#ifdef __ARM_NEON__
-      { "pcsx_rearmed_neon_interlace_enable", "Enable interlacing mode(s); disabled|enabled" },
-      { "pcsx_rearmed_neon_enhancement_enable", "Enhanced resolution (slow); disabled|enabled" },
-      { "pcsx_rearmed_neon_enhancement_no_main", "Enhanced resolution speed hack; disabled|enabled" },
-#endif
-      { "pcsx_rearmed_duping_enable", "Frame duping; enabled|disabled" },
-      { "pcsx_rearmed_show_bios_bootlogo", "Show Bios Bootlogo(Breaks some games); disabled|enabled" },
-      { "pcsx_rearmed_spu_reverb", "Sound: Reverb; enabled|disabled" },
-      { "pcsx_rearmed_spu_interpolation", "Sound: Interpolation; simple|gaussian|cubic|off" },
-      { "pcsx_rearmed_idiablofix", "Diablo Music Fix; disabled|enabled" },
-      { "pcsx_rearmed_pe2_fix", "Parasite Eve 2/Vandal Hearts 1/2 Fix; disabled|enabled" },
-      { "pcsx_rearmed_inuyasha_fix", "InuYasha Sengoku Battle Fix; disabled|enabled" },
-      { NULL, NULL },
-   };
-
-    if (cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging))
-        log_cb = logging.log;
-
    environ_cb = cb;
 
-   cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
+   if (cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging))
+      log_cb = logging.log;
+
+   libretro_set_core_options(environ_cb);
 }
 
 void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
@@ -581,6 +576,8 @@ static void update_controller_port_variable(unsigned port)
                        in_type[port] = PSE_PAD_TYPE_ANALOGPAD;
                else if (strcmp(var.value, "negcon") == 0)
                        in_type[port] = PSE_PAD_TYPE_NEGCON;
+               else if (strcmp(var.value, "guncon") == 0)
+                       in_type[port] = PSE_PAD_TYPE_GUNCON;
                else if (strcmp(var.value, "none") == 0)
                        in_type[port] = PSE_PAD_TYPE_NONE;
                // else 'default' case, do nothing
@@ -691,17 +688,21 @@ void retro_get_system_info(struct retro_system_info *info)
 #define GIT_VERSION ""
 #endif
        info->library_version = "r22" GIT_VERSION;
-       info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u";
+       info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u|chd";
        info->need_fullpath = true;
 }
 
 void retro_get_system_av_info(struct retro_system_av_info *info)
 {
+
+       unsigned geom_height = vout_height > 0 ? vout_height : 240;
+       unsigned geom_width = vout_width > 0 ? vout_width : 320;
+
        memset(info, 0, sizeof(*info));
        info->timing.fps            = is_pal_mode ? 50 : 60;
        info->timing.sample_rate    = 44100;
-       info->geometry.base_width   = 320;
-       info->geometry.base_height  = 240;
+       info->geometry.base_width   = geom_width;
+       info->geometry.base_height  = geom_height;
        info->geometry.max_width    = VOUT_MAX_WIDTH;
        info->geometry.max_height   = VOUT_MAX_HEIGHT;
        info->geometry.aspect_ratio = 4.0 / 3.0;
@@ -978,11 +979,11 @@ static struct retro_disk_control_callback disk_control = {
 #define PATH_MAX  4096
 #endif
 
-static char base_dir[PATH_MAX];
+static char base_dir[1024];
 
 static bool read_m3u(const char *file)
 {
-       char line[PATH_MAX];
+       char line[1024];
        char name[PATH_MAX];
        FILE *f = fopen(file, "r");
        if (!f)
@@ -1055,6 +1056,20 @@ strcasestr(const char *s, const char*find)
 }
 #endif
 
+static void set_retro_memmap(void)
+{
+       struct retro_memory_map retromap = { 0 };
+       struct retro_memory_descriptor mmap =
+       {
+               0, psxM, 0, 0, 0, 0, 0x200000
+       };
+
+       retromap.descriptors = &mmap;
+       retromap.num_descriptors = 1;
+
+    environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &retromap);
+}
+
 bool retro_load_game(const struct retro_game_info *info)
 {
        size_t i;
@@ -1233,6 +1248,8 @@ bool retro_load_game(const struct retro_game_info *info)
       { 0 },
    };
 
+        frame_count = 0;
+
    environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
 
 #ifdef FRONTEND_SUPPORTS_RGB565
@@ -1314,6 +1331,8 @@ bool retro_load_game(const struct retro_game_info *info)
                }
        }
 
+       set_retro_memmap();
+
        return true;
 }
 
@@ -1326,6 +1345,8 @@ void *retro_get_memory_data(unsigned id)
 {
        if (id == RETRO_MEMORY_SAVE_RAM)
                return Mcd1Data;
+       else if (id == RETRO_MEMORY_SYSTEM_RAM)
+               return psxM;
        else
                return NULL;
 }
@@ -1334,6 +1355,8 @@ size_t retro_get_memory_size(unsigned id)
 {
        if (id == RETRO_MEMORY_SAVE_RAM)
                return MCD_SIZE;
+       else if (id == RETRO_MEMORY_SYSTEM_RAM)
+               return 0x200000;
        else
                return 0;
 }
@@ -1369,6 +1392,7 @@ static void update_variables(bool in_flight)
 {
    struct retro_variable var;
    int i;
+   int gpu_peops_fix = 0;
 
    var.value = NULL;
    var.key = "pcsx_rearmed_frameskip";
@@ -1432,6 +1456,7 @@ static void update_variables(bool in_flight)
       if (strcmp(var.value, "disabled") == 0) {
          pl_rearmed_cbs.gpu_peops.iUseDither = 0;
          pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 0;
+         pl_rearmed_cbs.gpu_unai.dithering = 0;
 #ifdef __ARM_NEON__
          pl_rearmed_cbs.gpu_neon.allow_dithering = 0;
 #endif
@@ -1439,6 +1464,7 @@ static void update_variables(bool in_flight)
       else if (strcmp(var.value, "enabled") == 0) {
          pl_rearmed_cbs.gpu_peops.iUseDither = 1;
          pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 1;
+         pl_rearmed_cbs.gpu_unai.dithering = 1;
 #ifdef __ARM_NEON__
          pl_rearmed_cbs.gpu_neon.allow_dithering = 1;
 #endif
@@ -1491,6 +1517,17 @@ static void update_variables(bool in_flight)
          duping_enable = true;
    }
 
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_display_internal_fps";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         display_internal_fps = false;
+      else if (strcmp(var.value, "enabled") == 0)
+         display_internal_fps = true;
+   }
+
 #ifndef DRC_DISABLE
    var.value = NULL;
    var.key = "pcsx_rearmed_drc";
@@ -1577,6 +1614,284 @@ static void update_variables(bool in_flight)
          Config.VSyncWA = 1;
    }
 
+   var.value = NULL;
+   var.key = "pcsx_rearmed_noxadecoding";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.Xa = 1;
+      else
+         Config.Xa = 0;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_nocdaudio";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.Cdda = 1;
+      else
+         Config.Cdda = 0;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_spuirq";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.SpuIrq = 0;
+      else
+         Config.SpuIrq = 1;
+   }
+
+#ifndef DRC_DISABLE
+   var.value = NULL;
+   var.key = "pcsx_rearmed_nosmccheck";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         new_dynarec_hacks |= NDHACK_NO_SMC_CHECK;
+      else
+         new_dynarec_hacks &= ~NDHACK_NO_SMC_CHECK;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gteregsunneeded";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         new_dynarec_hacks |= NDHACK_GTE_UNNEEDED;
+      else
+         new_dynarec_hacks &= ~NDHACK_GTE_UNNEEDED;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_nogteflags";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         new_dynarec_hacks |= NDHACK_GTE_NO_FLAGS;
+      else
+         new_dynarec_hacks &= ~NDHACK_GTE_NO_FLAGS;
+   }
+#endif
+
+#ifdef GPU_PEOPS
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_odd_even_bit";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_ODD_EVEN_BIT;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_expand_screen_width";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_EXPAND_SCREEN_WIDTH;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_ignore_brightness";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_IGNORE_BRIGHTNESS;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_disable_coord_check";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_DISABLE_COORD_CHECK;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_lazy_screen_update";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_LAZY_SCREEN_UPDATE;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_old_frame_skip";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_OLD_FRAME_SKIP;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_repeated_triangles";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_REPEATED_TRIANGLES;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_quads_with_triangles";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_QUADS_WITH_TRIANGLES;
+   }
+
+   var.value = "NULL";
+   var.key = "pcsx_rearmed_gpu_peops_fake_busy_state";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_FAKE_BUSY_STATE;
+   }
+
+   if (pl_rearmed_cbs.gpu_peops.dwActFixes != gpu_peops_fix)
+      pl_rearmed_cbs.gpu_peops.dwActFixes = gpu_peops_fix;
+
+
+   /* Show/hide core options */
+
+   var.key = "pcsx_rearmed_show_gpu_peops_settings";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      int show_advanced_gpu_peops_settings_prev = show_advanced_gpu_peops_settings;
+
+      show_advanced_gpu_peops_settings = 1;
+      if (strcmp(var.value, "disabled") == 0)
+         show_advanced_gpu_peops_settings = 0;
+
+      if (show_advanced_gpu_peops_settings != show_advanced_gpu_peops_settings_prev)
+      {
+         unsigned i;
+         struct retro_core_option_display option_display;
+         char gpu_peops_option[9][45] = {
+            "pcsx_rearmed_gpu_peops_odd_even_bit",
+            "pcsx_rearmed_gpu_peops_expand_screen_width",
+            "pcsx_rearmed_gpu_peops_ignore_brightness",
+            "pcsx_rearmed_gpu_peops_disable_coord_check",
+            "pcsx_rearmed_gpu_peops_lazy_screen_update",
+            "pcsx_rearmed_gpu_peops_old_frame_skip",
+            "pcsx_rearmed_gpu_peops_repeated_triangles",
+            "pcsx_rearmed_gpu_peops_quads_with_triangles",
+            "pcsx_rearmed_gpu_peops_fake_busy_state",
+         };
+
+         option_display.visible = show_advanced_gpu_peops_settings;
+
+         for (i = 0; i < 9; i++)
+         {
+            option_display.key = gpu_peops_option[i];
+            environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
+         }
+      }
+   }
+#endif
+
+#ifdef GPU_UNAI
+   var.key = "pcsx_rearmed_gpu_unai_ilace_force";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.ilace_force = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.ilace_force = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_pixel_skip";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.pixel_skip = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.pixel_skip = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_lighting";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.lighting = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.lighting = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_fast_lighting";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.fast_lighting = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.fast_lighting = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_blending";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.blending = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.blending = 1;
+   }
+
+   var.key = "pcsx_rearmed_show_gpu_unai_settings";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      int show_advanced_gpu_unai_settings_prev = show_advanced_gpu_unai_settings;
+
+      show_advanced_gpu_unai_settings = 1;
+      if (strcmp(var.value, "disabled") == 0)
+         show_advanced_gpu_unai_settings = 0;
+
+      if (show_advanced_gpu_unai_settings != show_advanced_gpu_unai_settings_prev)
+      {
+         unsigned i;
+         struct retro_core_option_display option_display;
+         char gpu_unai_option[5][40] = {
+            "pcsx_rearmed_gpu_unai_blending",
+            "pcsx_rearmed_gpu_unai_lighting",
+            "pcsx_rearmed_gpu_unai_fast_lighting",
+            "pcsx_rearmed_gpu_unai_ilace_force",
+            "pcsx_rearmed_gpu_unai_pixel_skip",
+         };
+
+         option_display.visible = show_advanced_gpu_unai_settings;
+
+         for (i = 0; i < 5; i++)
+         {
+            option_display.key = gpu_unai_option[i];
+            environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
+         }
+      }
+   }
+#endif // GPU_UNAI
+
    if (in_flight) {
       // inform core things about possible config changes
       plugin_call_rearmed_cbs();
@@ -1588,7 +1903,8 @@ static void update_variables(bool in_flight)
 
       dfinput_activate();
    }
-   else{
+   else
+   {
       //not yet running
 
       //bootlogo display hack
@@ -1597,10 +1913,13 @@ static void update_variables(bool in_flight)
          var.key = "pcsx_rearmed_show_bios_bootlogo";
          if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
          {
+            Config.SlowBoot = 0;
+            rebootemu = 0;
             if (strcmp(var.value, "enabled") == 0)
+            {
                Config.SlowBoot = 1;
-            else
-               Config.SlowBoot = 0;
+               rebootemu = 1;
+            }
          }
       }
 #ifndef DRC_DISABLE
@@ -1616,15 +1935,13 @@ static void update_variables(bool in_flight)
 }
 
 // Taken from beetle-psx-libretro
-static uint16_t get_analog_button(retro_input_state_t input_state_cb, int player_index, int id)
+static uint16_t get_analog_button(int16_t ret, retro_input_state_t input_state_cb, int player_index, int id)
 {
-       uint16_t button;
-
        // NOTE: Analog buttons were added Nov 2017. Not all front-ends support this
        // feature (or pre-date it) so we need to handle this in a graceful way.
 
        // First, try and get an analog value using the new libretro API constant
-       button = input_state_cb(player_index,
+       uint16_t button = input_state_cb(player_index,
                                                                        RETRO_DEVICE_ANALOG,
                                                                        RETRO_DEVICE_INDEX_ANALOG_BUTTON,
                                                                        id);
@@ -1638,10 +1955,7 @@ static uint16_t get_analog_button(retro_input_state_t input_state_cb, int player
 
                // NOTE: If we're really just not holding the button, we're still going to get zero.
 
-               button = input_state_cb(player_index,
-                                                                               RETRO_DEVICE_JOYPAD,
-                                                                               0,
-                                                                               id) ? 255 : 0;
+               button = (ret & (1 << id)) ? 255 : 0;
        }
 
        return button;
@@ -1660,6 +1974,31 @@ void retro_run(void)
                }
        }
 
+       if (display_internal_fps) {
+               frame_count++;
+
+               if (frame_count % INTERNAL_FPS_SAMPLE_PERIOD == 0) {
+                       unsigned internal_fps = pl_rearmed_cbs.flip_cnt * (is_pal_mode ? 50 : 60) / INTERNAL_FPS_SAMPLE_PERIOD;
+                       char str[64];
+                       const char *strc = (const char*)str;
+                       struct retro_message msg =
+                       {
+                               strc,
+                               180
+                       };
+
+                       str[0] = '\0';
+
+                       snprintf(str, sizeof(str), "Internal FPS: %2d", internal_fps);
+
+                       pl_rearmed_cbs.flip_cnt = 0;
+
+                       environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
+               }
+       }
+   else
+               frame_count = 0;
+
        input_poll_cb();
 
        bool updated = false;
@@ -1673,48 +2012,141 @@ void retro_run(void)
        float negcon_twist_amplitude;
        int negcon_i_rs;
        int negcon_ii_rs;
-       for(i = 0; i < PORTS_NUMBER; i++) {
+       for(i = 0; i < PORTS_NUMBER; i++)
+   {
+      int16_t ret    = 0;
                in_keystate[i] = 0;
 
                if (in_type[i] == PSE_PAD_TYPE_NONE)
                        continue;
 
+      if (libretro_supports_bitmasks)
+         ret = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
+      else
+      {
+         unsigned j;
+         for (j = 0; j < (RETRO_DEVICE_ID_JOYPAD_R3+1); j++)
+         {
+            if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, j))
+               ret |= (1 << j);
+         }
+      }
+
+               if (in_type[i] == PSE_PAD_TYPE_GUNCON)
+               {
+                       //ToDo move across to:
+                       //RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X
+                       //RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y   
+                       //RETRO_DEVICE_ID_LIGHTGUN_TRIGGER
+                       //RETRO_DEVICE_ID_LIGHTGUN_RELOAD
+                       //RETRO_DEVICE_ID_LIGHTGUN_AUX_A 
+                       //RETRO_DEVICE_ID_LIGHTGUN_AUX_B
+                       //Though not sure these are hooked up properly on the Pi
+                       
+                       //ToDo
+                       //Put the controller index back to i instead of hardcoding to 1 when the libretro overlay crash bug is fixed
+                       //This is required for 2 player
+                       
+                       //GUNCON has 3 controls, Trigger,A,B which equal Circle,Start,Cross
+                       
+                       // Trigger
+                       //The 1 is hardcoded instead of i to prevent the overlay mouse button libretro crash bug
+                       if (input_state_cb(1, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT)){
+                               in_keystate[i] |= (1 << DKEY_CIRCLE);
+                       }
+                       
+                       // A
+                       if (input_state_cb(1, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT)){
+                               in_keystate[i] |= (1 << DKEY_START);
+                       }
+                       
+                       // B
+                       if (input_state_cb(1, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE)){
+                               in_keystate[i] |= (1 << DKEY_CROSS);
+                       }
+                       
+                       //The 1 is hardcoded instead of i to prevent the overlay mouse button libretro crash bug
+                       int gunx = input_state_cb(1, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
+                       int guny = input_state_cb(1, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
+                       
+                       //This adjustment process gives the user the ability to manually align the mouse up better 
+                       //with where the shots are in the emulator.
+                       
+                       //Percentage distance of screen to adjust 
+                       int GunconAdjustX = 0;
+                       int GunconAdjustY = 0;
+                       
+                       //Used when out by a percentage
+                       float GunconAdjustRatioX = 1;
+                       float GunconAdjustRatioY = 1;
+                               
+                       struct retro_variable var;
+                       var.value = NULL;
+                       var.key = "pcsx_rearmed_gunconadjustx";
+                       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+                       {
+                               GunconAdjustX = atoi(var.value);        
+                       }
+                       
+                       var.value = NULL;
+                       var.key = "pcsx_rearmed_gunconadjusty";
+                       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+                       {
+                               GunconAdjustY = atoi(var.value);        
+                       } 
+                       
+                       
+                       var.value = NULL;
+                       var.key = "pcsx_rearmed_gunconadjustratiox";
+                       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+                       {
+                               GunconAdjustRatioX = atof(var.value);   
+                       } 
+                       
+                       
+                       var.value = NULL;
+                       var.key = "pcsx_rearmed_gunconadjustratioy";
+                       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+                       {
+                               GunconAdjustRatioY = atof(var.value);   
+                       } 
+                       
+                       //Mouse range is -32767 -> 32767
+                       //1% is about 655
+                       //Use the left analog stick field to store the absolute coordinates
+                       in_analog_left[0][0] = (gunx*GunconAdjustRatioX) + (GunconAdjustX * 655);
+                       in_analog_left[0][1] = (guny*GunconAdjustRatioY) + (GunconAdjustY * 655);
+                       
+                       
+               }
                if (in_type[i] == PSE_PAD_TYPE_NEGCON)
                {
                        // Query digital inputs
                        //
                        // > Pad-Up
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_UP))
                                in_keystate[i] |= (1 << DKEY_UP);
-                       }
                        // > Pad-Right
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT))
                                in_keystate[i] |= (1 << DKEY_RIGHT);
-                       }
                        // > Pad-Down
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN))
                                in_keystate[i] |= (1 << DKEY_DOWN);
-                       }
                        // > Pad-Left
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT))
                                in_keystate[i] |= (1 << DKEY_LEFT);
-                       }
                        // > Start
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_START))
                                in_keystate[i] |= (1 << DKEY_START);
-                       }
                        // > neGcon A
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A))
                                in_keystate[i] |= (1 << DKEY_CIRCLE);
-                       }
                        // > neGcon B
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X))
                                in_keystate[i] |= (1 << DKEY_TRIANGLE);
-                       }
                        // > neGcon R shoulder (digital)
-                       if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R)){
+                       if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R))
                                in_keystate[i] |= (1 << DKEY_R1);
-                       }
                        // Query analog inputs
                        //
                        // From studying 'libpcsxcore/plugins.c' and 'frontend/plugin.c':
@@ -1728,24 +2160,23 @@ void retro_run(void)
                        // > NeGcon twist
                        // >> Get raw analog stick value and account for deadzone
                        lsx = input_state_cb(i, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
-                       if (lsx > negcon_deadzone){
+                       if (lsx > negcon_deadzone)
                                lsx = lsx - negcon_deadzone;
-                       } else if (lsx < -negcon_deadzone){
+                       else if (lsx < -negcon_deadzone)
                                lsx = lsx + negcon_deadzone;
-                       } else {
+                       else
                                lsx = 0;
-                       }
                        // >> Convert to an 'amplitude' [-1.0,1.0] and adjust response
                        negcon_twist_amplitude = (float)lsx / (float)(NEGCON_RANGE - negcon_deadzone);
-                       if (negcon_linearity == 2){
-                               if (negcon_twist_amplitude < 0.0){
+                       if (negcon_linearity == 2)
+         {
+                               if (negcon_twist_amplitude < 0.0)
                                        negcon_twist_amplitude = -(negcon_twist_amplitude * negcon_twist_amplitude);
-                               } else {
+            else
                                        negcon_twist_amplitude = negcon_twist_amplitude * negcon_twist_amplitude;
-                               }
-                       } else if (negcon_linearity == 3){
-                               negcon_twist_amplitude = negcon_twist_amplitude * negcon_twist_amplitude * negcon_twist_amplitude;
                        }
+         else if (negcon_linearity == 3)
+                               negcon_twist_amplitude = negcon_twist_amplitude * negcon_twist_amplitude * negcon_twist_amplitude;
                        // >> Convert to final 'in_analog' integer value [0,255]
                        in_analog_right[i][0] = MAX(MIN((int)(negcon_twist_amplitude * 128.0f) + 128, 255), 0);
                        // > NeGcon I + II
@@ -1760,48 +2191,45 @@ void retro_run(void)
                                // (Note: have never encountered a gamepad with significant differences
                                // in deadzone between left/right analog sticks, so use the regular 'twist'
                                // deadzone here)
-                               if (rsy > negcon_deadzone){
+                               if (rsy > negcon_deadzone)
                                        rsy = rsy - negcon_deadzone;
-                               } else {
+            else
                                        rsy = 0;
-                               }
                                // Convert to 'in_analog' integer value [0,255]
                                negcon_ii_rs = MIN((int)(((float)rsy / (float)(NEGCON_RANGE - negcon_deadzone)) * 255.0f), 255);
                        } else {
-                               if (rsy < -negcon_deadzone){
+                               if (rsy < -negcon_deadzone)
                                        rsy = -1 * (rsy + negcon_deadzone);
-                               } else {
+            else
                                        rsy = 0;
-                               }
                                negcon_i_rs = MIN((int)(((float)rsy / (float)(NEGCON_RANGE - negcon_deadzone)) * 255.0f), 255);
                        }
                        // >> NeGcon I
                        in_analog_right[i][1] = MAX(
                                MAX(
-                                       get_analog_button(input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_R2),
-                                       get_analog_button(input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_B)
+                                       get_analog_button(ret, input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_R2),
+                                       get_analog_button(ret, input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_B)
                                ),
                                negcon_i_rs
                        );
                        // >> NeGcon II
                        in_analog_left[i][0] = MAX(
                                MAX(
-                                       get_analog_button(input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_L2),
-                                       get_analog_button(input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_Y)
+                                       get_analog_button(ret, input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_L2),
+                                       get_analog_button(ret, input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_Y)
                                ),
                                negcon_ii_rs
                        );
                        // > NeGcon L
-                       in_analog_left[i][1] = get_analog_button(input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_L);
+                       in_analog_left[i][1] = get_analog_button(ret, input_state_cb, i, RETRO_DEVICE_ID_JOYPAD_L);
                }
-               else
+               if (in_type[i] != PSE_PAD_TYPE_NEGCON && in_type[i] != PSE_PAD_TYPE_GUNCON)
                {
                        // Query digital inputs
-                       for (j = 0; j < RETRO_PSX_MAP_LEN; j++){
-                               if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, j)){
+                       for (j = 0; j < RETRO_PSX_MAP_LEN; j++)
+                               if (ret & (1 << j))
                                        in_keystate[i] |= retro_psx_map[j];
-                               }
-                       }
+
                        // Query analog inputs
                        if (in_type[i] == PSE_PAD_TYPE_ANALOGJOY || in_type[i] == PSE_PAD_TYPE_ANALOGPAD)
                        {
@@ -1862,7 +2290,7 @@ static bool find_any_bios(const char *dirpath, char *path, size_t path_size)
                return false;
 
        while ((ent = readdir(dir))) {
-               if (strncasecmp(ent->d_name, "scph", 4) != 0)
+               if ((strncasecmp(ent->d_name, "scph", 4) != 0) && (strncasecmp(ent->d_name, "psx", 3) != 0))
                        continue;
 
                snprintf(path, path_size, "%s%c%s", dirpath, SLASH, ent->d_name);
@@ -1924,10 +2352,11 @@ static int init_memcards(void)
 static void loadPSXBios(void)
 {
        const char *dir;
-       char path[256];
+       char path[PATH_MAX];
        unsigned useHLE = 0;
 
        const char *bios[] = {
+               "PSXONPSP660", "psxonpsp660",
                "SCPH101", "scph101",
                "SCPH5501", "scph5501",
                "SCPH7001", "scph7001",
@@ -2016,7 +2445,7 @@ void retro_init(void)
 
 #ifdef _3DS
    vout_buf = linearMemAlign(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2, 0x80);
-#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) && !defined(VITA)
+#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) && !defined(VITA) && !defined(__SWITCH__)
        posix_memalign(&vout_buf, 16, VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
 #else
        vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
@@ -2041,6 +2470,7 @@ void retro_init(void)
        cycle_multiplier = 200;
 #endif
        pl_rearmed_cbs.gpu_peops.iUseDither = 1;
+       pl_rearmed_cbs.gpu_peops.dwActFixes = GPU_PEOPS_OLD_FRAME_SKIP;
        spu_config.iUseFixedUpdates = 1;
 
        SaveFuncs.open = save_open;
@@ -2049,12 +2479,16 @@ void retro_init(void)
        SaveFuncs.seek = save_seek;
        SaveFuncs.close = save_close;
 
+   if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
+      libretro_supports_bitmasks = true;
+
        update_variables(false);
        check_system_specs();
 }
 
 void retro_deinit(void)
 {
+       ClosePlugins();
        SysClose();
 #ifdef _3DS
    linearFree(vout_buf);
@@ -2066,6 +2500,7 @@ void retro_deinit(void)
 #ifdef VITA
   deinit_vita_mmap();
 #endif
+   libretro_supports_bitmasks = false;
 }
 
 #ifdef VITA
@@ -2075,3 +2510,15 @@ int usleep (unsigned long us)
    sceKernelDelayThread(us);
 }
 #endif
+
+void SysPrintf(const char *fmt, ...) {
+       va_list list;
+       char msg[512];
+
+       va_start(list, fmt);
+       vsprintf(msg, fmt, list);
+       va_end(list);
+
+       if (log_cb)
+               log_cb(RETRO_LOG_INFO, "%s", msg);
+}