diff options
author | Justin Weiss | 2020-08-02 22:04:52 -0700 |
---|---|---|
committer | Justin Weiss | 2020-08-13 08:56:50 -0700 |
commit | 43047988e507799d7d5bbcd926c5d0b5b94fcdc1 (patch) | |
tree | 40cdd3800bfb51ca35efc795417e9daa8d33296f | |
parent | ab323c13064ac483e66682556ae3bf387df0f29d (diff) | |
download | pcsx_rearmed-43047988e507799d7d5bbcd926c5d0b5b94fcdc1.tar.gz pcsx_rearmed-43047988e507799d7d5bbcd926c5d0b5b94fcdc1.tar.bz2 pcsx_rearmed-43047988e507799d7d5bbcd926c5d0b5b94fcdc1.zip |
Add an option to downscale hi-res views
Some older devices that use gpu_unai don't have a high enough
resolution to display all of the pixels in high-res mode. There's a
setting in unai to skip rendering of these pixels, but it's not
connected to the libretro frontend, and does not appear to be used in
the gpulib implementation at all.
This commit adds a gpu_unai setting, Enable Hi-Res Downscaling, that
will enable pixel skipping and blit only the pixels actually rendered
into a buffer no larger than 384x240. This buffer is then treated as
the actual framebuffer by gpulib and the libretro frontend.
-rw-r--r-- | frontend/libretro.c | 18 | ||||
-rw-r--r-- | frontend/libretro_core_options.h | 11 | ||||
-rw-r--r-- | frontend/main.c | 1 | ||||
-rw-r--r-- | frontend/menu.c | 1 | ||||
-rw-r--r-- | frontend/plugin_lib.h | 1 | ||||
-rw-r--r-- | plugins/gpu_unai/gpu.h | 4 | ||||
-rw-r--r-- | plugins/gpu_unai/gpu_unai.h | 5 | ||||
-rw-r--r-- | plugins/gpu_unai/gpulib_if.cpp | 168 | ||||
-rw-r--r-- | plugins/gpulib/gpu.h | 4 | ||||
-rw-r--r-- | plugins/gpulib/vout_pl.c | 12 |
10 files changed, 221 insertions, 4 deletions
diff --git a/frontend/libretro.c b/frontend/libretro.c index 50392a9..8dc6bc3 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -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); diff --git a/frontend/libretro_core_options.h b/frontend/libretro_core_options.h index 95544f0..283abc6 100644 --- a/frontend/libretro_core_options.h +++ b/frontend/libretro_core_options.h @@ -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 */ { diff --git a/frontend/main.c b/frontend/main.c index b1ee4c7..51cb7bf 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -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; diff --git a/frontend/menu.c b/frontend/menu.c index f4a45ba..e5c2738 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -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), diff --git a/frontend/plugin_lib.h b/frontend/plugin_lib.h index 09cc4c5..ee03169 100644 --- a/frontend/plugin_lib.h +++ b/frontend/plugin_lib.h @@ -91,6 +91,7 @@ struct rearmed_cbs { int abe_hack; int no_light, no_blend; int lineskip; + int scale_hires; } gpu_unai; struct { int dwActFixes; diff --git a/plugins/gpu_unai/gpu.h b/plugins/gpu_unai/gpu.h index eade2a8..f5eb69b 100644 --- a/plugins/gpu_unai/gpu.h +++ b/plugins/gpu_unai/gpu.h @@ -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; diff --git a/plugins/gpu_unai/gpu_unai.h b/plugins/gpu_unai/gpu_unai.h index 8fb2293..6886eb8 100644 --- a/plugins/gpu_unai/gpu_unai.h +++ b/plugins/gpu_unai/gpu_unai.h @@ -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() diff --git a/plugins/gpu_unai/gpulib_if.cpp b/plugins/gpu_unai/gpulib_if.cpp index 78870de..e84eff5 100644 --- a/plugins/gpu_unai/gpulib_if.cpp +++ b/plugins/gpu_unai/gpulib_if.cpp @@ -51,6 +51,158 @@ ///////////////////////////////////////////////////////////////////////////// +#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 diff --git a/plugins/gpulib/gpu.h b/plugins/gpulib/gpu.h index 7e1d18b..009297d 100644 --- a/plugins/gpulib/gpu.h +++ b/plugins/gpulib/gpu.h @@ -68,6 +68,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 { @@ -91,6 +93,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); }; diff --git a/plugins/gpulib/vout_pl.c b/plugins/gpulib/vout_pl.c index a9437cb..075e3c3 100644 --- a/plugins/gpulib/vout_pl.c +++ b/plugins/gpulib/vout_pl.c @@ -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 |