Merge pull request #444 from justinweiss/hires-downscale
authorhizzlekizzle <hizzlekizzle@users.noreply.github.com>
Thu, 13 Aug 2020 23:06:23 +0000 (18:06 -0500)
committerGitHub <noreply@github.com>
Thu, 13 Aug 2020 23:06:23 +0000 (18:06 -0500)
Add an option to downscale hi-res views

frontend/libretro.c
frontend/libretro_core_options.h
frontend/main.c
frontend/menu.c
frontend/plugin_lib.h
plugins/gpu_unai/gpu.h
plugins/gpu_unai/gpu_unai.h
plugins/gpu_unai/gpulib_if.cpp
plugins/gpulib/gpu.h
plugins/gpulib/vout_pl.c

index a8895d8..699cbce 100644 (file)
@@ -1999,6 +1999,17 @@ static void update_variables(bool in_flight)
          pl_rearmed_cbs.gpu_unai.blending = 1;
    }
 
+   var.key = "pcsx_rearmed_gpu_unai_scale_hires";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.scale_hires = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.scale_hires = 1;
+   }
+
    var.key = "pcsx_rearmed_show_gpu_unai_settings";
    var.value = NULL;
 
@@ -2014,17 +2025,18 @@ static void update_variables(bool in_flight)
       {
          unsigned i;
          struct retro_core_option_display option_display;
-         char gpu_unai_option[5][40] = {
+         char gpu_unai_option[6][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"
+            "pcsx_rearmed_gpu_unai_pixel_skip",
+            "pcsx_rearmed_gpu_unai_scale_hires"
          };
 
          option_display.visible = show_advanced_gpu_unai_settings;
 
-         for (i = 0; i < 5; i++)
+         for (i = 0; i < 6; i++)
          {
             option_display.key = gpu_unai_option[i];
             environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
index 92d723e..40aebb4 100644 (file)
@@ -961,6 +961,17 @@ struct retro_core_option_definition option_defs_us[] = {
       },
       "disabled",
    },
+   {
+      "pcsx_rearmed_gpu_unai_scale_hires",
+      "(GPU) Enable Hi-Res Downscaling",
+      "When enabled, will scale hi-res modes to 320x240, skipping unrendered pixels.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
 #endif /* GPU UNAI Advanced Settings */
 
    {
index b1ee4c7..51cb7bf 100644 (file)
@@ -140,6 +140,7 @@ void emu_set_default_config(void)
        pl_rearmed_cbs.gpu_unai.abe_hack =
        pl_rearmed_cbs.gpu_unai.no_light =
        pl_rearmed_cbs.gpu_unai.no_blend = 0;
+       pl_rearmed_cbs.gpu_unai.scale_hires = 0;
        memset(&pl_rearmed_cbs.gpu_peopsgl, 0, sizeof(pl_rearmed_cbs.gpu_peopsgl));
        pl_rearmed_cbs.gpu_peopsgl.iVRamSize = 64;
        pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection = 1;
index f4a45ba..e5c2738 100644 (file)
@@ -432,6 +432,7 @@ static const struct {
        CE_INTVAL_P(gpu_unai.abe_hack),
        CE_INTVAL_P(gpu_unai.no_light),
        CE_INTVAL_P(gpu_unai.no_blend),
+       CE_INTVAL_P(gpu_unai.scale_hires),
        CE_INTVAL_P(gpu_neon.allow_interlace),
        CE_INTVAL_P(gpu_neon.enhancement_enable),
        CE_INTVAL_P(gpu_neon.enhancement_no_main),
index 7570001..114aaad 100644 (file)
@@ -93,6 +93,7 @@ struct rearmed_cbs {
                int   abe_hack;
                int   no_light, no_blend;
                int   lineskip;
+               int   scale_hires;
        } gpu_unai;
        struct {
                int   dwActFixes;
index eade2a8..f5eb69b 100644 (file)
@@ -38,6 +38,10 @@ struct gpu_unai_config_t {
                                  //  Normally 0. Value '1' will skip rendering
                                  //  odd lines.
 
+       uint8_t scale_hires:1;    // If 1, will scale hi-res output to
+                                 //  320x240 when gpulib reads the frame.
+                                 //  Implies pixel_skip and ilace_force
+                                 //  (when height > 240).
        uint8_t lighting:1;
        uint8_t fast_lighting:1;
        uint8_t blending:1;
index 8fb2293..6886eb8 100644 (file)
@@ -138,6 +138,9 @@ struct gpu_unai_t {
        GPUPacket PacketBuffer;
        u16 *vram;
 
+#ifdef USE_GPULIB
+       u16 *downscale_vram;
+#endif
        ////////////////////////////////////////////////////////////////////////////
        // Variables used only by older standalone version of gpu_unai (gpu.cpp)
 #ifndef USE_GPULIB
@@ -307,7 +310,7 @@ static inline bool ProgressiveInterlaceEnabled()
 //       running on higher-res device or a resampling downscaler is enabled.
 static inline bool PixelSkipEnabled()
 {
-       return gpu_unai.config.pixel_skip;
+       return gpu_unai.config.pixel_skip || gpu_unai.config.scale_hires;
 }
 
 static inline bool LineSkipEnabled()
index 78870de..e84eff5 100644 (file)
 
 /////////////////////////////////////////////////////////////////////////////
 
+#define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
+
+INLINE void scale_640_to_320(uint16_t *dest, const uint16_t *src, bool isRGB24) {
+  size_t uCount = 320;
+
+  if(isRGB24) {
+    const uint8_t* src8 = (const uint8_t *)src;
+    uint8_t* dst8 = (uint8_t *)dest;
+
+    do {
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+    } while(--uCount);
+  } else {
+    const uint16_t* src16 = src;
+    uint16_t* dst16 = dest;
+
+    do {
+      *dst16++ = *src16;
+      src16 += 2;
+    } while(--uCount);
+  }
+}
+
+INLINE void scale_512_to_320(uint16_t *dest, const uint16_t *src, bool isRGB24) {
+  size_t uCount = 64;
+
+  if(isRGB24) {
+    const uint8_t* src8 = (const uint8_t *)src;
+    uint8_t* dst8 = (uint8_t *)dest;
+
+    do {
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+    } while(--uCount);
+  } else {
+    const uint16_t* src16 = src;
+    uint16_t* dst16 = dest;
+
+    do {
+      *dst16++ = *src16++;
+      *dst16++ = *src16;
+      src16 += 2;
+      *dst16++ = *src16++;
+      *dst16++ = *src16;
+      src16 += 2;
+      *dst16++ = *src16;
+      src16 += 2;
+    } while(--uCount);
+  }
+}
+
+static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
+{
+  uint16_t *dest = gpu_unai.downscale_vram;
+  const uint16_t *src = gpu_unai.vram;
+  bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
+  int stride = 1024, dstride = 1024, lines = *h, orig_w = *w;
+
+  // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
+  unsigned int fb_mask = 1024 * 512 - 1;
+
+  if (*h > 240) {
+    *h /= 2;
+    stride *= 2;
+    lines = *h;
+
+    // Ensure start at a non-skipped line
+    while (*y & gpu_unai.ilace_mask) ++*y;
+  }
+
+  unsigned int fb_offset_src = (*y * dstride + *x) & fb_mask;
+  unsigned int fb_offset_dest = fb_offset_src;
+
+  if (*w == 512 || *w == 640) {
+    *w = 320;
+  }
+
+  switch(orig_w) {
+  case 640:
+    do {
+      scale_640_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
+      fb_offset_src = (fb_offset_src + stride) & fb_mask;
+      fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
+    } while(--lines);
+
+    break;
+  case 512:
+    do {
+      scale_512_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
+      fb_offset_src = (fb_offset_src + stride) & fb_mask;
+      fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
+    } while(--lines);
+    break;
+  default:
+    size_t size = isRGB24 ? *w * 3 : *w * 2;
+
+    do {
+      memcpy(dest + fb_offset_dest, src + fb_offset_src, size);
+      fb_offset_src = (fb_offset_src + stride) & fb_mask;
+      fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
+    } while(--lines);
+    break;
+  }
+
+  return gpu_unai.downscale_vram;
+}
+
+static void map_downscale_buffer(void)
+{
+  if (gpu_unai.downscale_vram)
+    return;
+
+  gpu_unai.downscale_vram = (uint16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
+
+  if (gpu_unai.downscale_vram == NULL) {
+    fprintf(stderr, "failed to map downscale buffer\n");
+    gpu.get_downscale_buffer = NULL;
+  }
+  else {
+    gpu.get_downscale_buffer = get_downscale_buffer;
+  }
+}
+
+static void unmap_downscale_buffer(void)
+{
+  if (gpu_unai.downscale_vram == NULL)
+    return;
+
+  gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
+  gpu_unai.downscale_vram = NULL;
+  gpu.get_downscale_buffer = NULL;
+}
+
 int renderer_init(void)
 {
   memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
@@ -94,11 +246,16 @@ int renderer_init(void)
   SetupLightLUT();
   SetupDitheringConstants();
 
+  if (gpu_unai.config.scale_hires) {
+    map_downscale_buffer();
+  }
+
   return 0;
 }
 
 void renderer_finish(void)
 {
+  unmap_downscale_buffer();
 }
 
 void renderer_notify_res_change(void)
@@ -227,6 +384,9 @@ int do_cmd_list(u32 *list, int list_len, int *last_cmd)
 #ifdef HAVE_PRE_ARMV7 /* XXX */
   gpu_unai.ilace_mask |= gpu.status.interlace;
 #endif
+  if (gpu_unai.config.scale_hires) {
+    gpu_unai.ilace_mask |= gpu.status.interlace;
+  }
 
   for (; list < list_end; list += 1 + len)
   {
@@ -632,6 +792,14 @@ void renderer_set_config(const struct rearmed_cbs *cbs)
   gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
   gpu_unai.config.blending      = cbs->gpu_unai.blending;
   gpu_unai.config.dithering     = cbs->gpu_unai.dithering;
+  gpu_unai.config.scale_hires   = cbs->gpu_unai.scale_hires;
+
+  gpu.state.downscale_enable    = gpu_unai.config.scale_hires;
+  if (gpu_unai.config.scale_hires) {
+    map_downscale_buffer();
+  } else {
+    unmap_downscale_buffer();
+  }
 }
 
 // vim:shiftwidth=2:expandtab
index 36de7ee..d0f3bf8 100644 (file)
@@ -71,6 +71,8 @@ struct psx_gpu {
     uint32_t blanked:1;
     uint32_t enhancement_enable:1;
     uint32_t enhancement_active:1;
+    uint32_t downscale_enable:1;
+    uint32_t downscale_active:1;
     uint32_t *frame_count;
     uint32_t *hcnt; /* hsync count */
     struct {
@@ -94,6 +96,8 @@ struct psx_gpu {
   int useDithering:1; /* 0 - off , 1 - on */
   uint16_t *(*get_enhancement_bufer)
     (int *x, int *y, int *w, int *h, int *vram_h);
+  uint16_t *(*get_downscale_buffer)
+    (int *x, int *y, int *w, int *h, int *vram_h);
   void *(*mmap)(unsigned int size);
   void  (*munmap)(void *ptr, unsigned int size);
 };
index a9437cb..075e3c3 100644 (file)
@@ -43,6 +43,15 @@ static void check_mode_change(int force)
     h_out *= 2;
   }
 
+  gpu.state.downscale_active =
+    gpu.get_downscale_buffer != NULL && gpu.state.downscale_enable
+    && (w >= 512 || h >= 256);
+
+  if (gpu.state.downscale_active) {
+    w_out = w < 512 ? w : 320;
+    h_out = h < 256 ? h : h / 2;
+  }
+
   // width|rgb24 change?
   if (force || (gpu.status.reg ^ old_status) & ((7<<16)|(1<<21)) || h != old_h)
   {
@@ -69,6 +78,9 @@ void vout_update(void)
   if (gpu.state.enhancement_active)
     vram = gpu.get_enhancement_bufer(&x, &y, &w, &h, &vram_h);
 
+  if (gpu.state.downscale_active)
+    vram = gpu.get_downscale_buffer(&x, &y, &w, &h, &vram_h);
+
   if (y + h > vram_h) {
     if (y + h - vram_h > h / 2) {
       // wrap