From a53e7ace2311886fe2163e5aa4d53dc796851497 Mon Sep 17 00:00:00 2001 From: negativeExponent Date: Thu, 27 Feb 2020 20:23:08 +0800 Subject: [PATCH] Move overscan after rendering the NTSC frame, add ntsc scanlines - do overscan cropping after the ntsc frame is generated. this allows removing left and right screen artifacts when using horizontal crop like what you would see happen in TV when adjusting horizontal size (HSIZE). - add core option that implements NTSC scanline effects. This requires framebuffer to double the height, so a define is added (NTSC_SCANLINES at the top of libretro.c) to disable this on some low-memory platforms or just disable NTSC filters altogether. - some minor cleanups --- src/drivers/libretro/libretro.c | 126 +++++++++++++------ src/drivers/libretro/libretro_core_options.h | 13 ++ src/ppu.c | 2 +- 3 files changed, 102 insertions(+), 39 deletions(-) diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c index 8825218..ee6f37c 100644 --- a/src/drivers/libretro/libretro.c +++ b/src/drivers/libretro/libretro.c @@ -30,6 +30,14 @@ #include "libretro-common/include/streams/memory_stream.h" #include "libretro_dipswitch.h" + +#ifdef HAVE_NTSC_FILTER +#define NTSC_SCANLINES /* enables scanline effect and doubles height(required) */ +#if defined(VITA) /* do no disable double-height for these devices */ +#undef NTSC_SCANLINES +#endif +#endif + #include "libretro_core_options.h" #define MAX_PLAYERS 4 /* max supported players */ @@ -587,10 +595,11 @@ struct st_palettes palettes[] = { #define NTSC_WIDTH 602 static unsigned use_ntsc = 0; +static unsigned use_ntsc_scanlines = 0; static unsigned burst_phase; static nes_ntsc_t nes_ntsc; static nes_ntsc_setup_t ntsc_setup; -static uint8_t *ntsc_video_out = NULL; /* for ntsc blit buffer */ +static uint16_t *ntsc_video_out = NULL; /* for ntsc blit buffer */ static void NTSCFilter_Cleanup(void) { @@ -603,7 +612,7 @@ static void NTSCFilter_Init(void) { memset(&nes_ntsc, 0, sizeof(nes_ntsc)); memset(&ntsc_setup, 0, sizeof(ntsc_setup)); - ntsc_video_out = (uint8_t*)malloc(NTSC_WIDTH * NES_HEIGHT * sizeof(uint16_t)); + ntsc_video_out = (uint16_t *)malloc(NTSC_WIDTH * NES_HEIGHT * sizeof(uint16_t)); } static void NTSCFilter_Setup(void) @@ -917,7 +926,7 @@ void retro_get_system_info(struct retro_system_info *info) void retro_get_system_av_info(struct retro_system_av_info *info) { - unsigned width, height, maxwidth; + unsigned width, height, maxwidth, maxheight; #ifdef PSP width = NES_WIDTH - (use_overscan ? 16 : 0); height = NES_HEIGHT - (use_overscan ? 16 : 0); @@ -927,13 +936,18 @@ void retro_get_system_av_info(struct retro_system_av_info *info) #endif #ifdef HAVE_NTSC_FILTER maxwidth = NTSC_WIDTH; + maxheight = NES_HEIGHT; +#ifdef NTSC_SCANLINES + maxheight = NES_HEIGHT * 2; +#endif #else maxwidth = NES_WIDTH; + maxheight = NES_HEIGHT; #endif info->geometry.base_width = width; info->geometry.base_height = height; info->geometry.max_width = maxwidth; - info->geometry.max_height = NES_HEIGHT; + info->geometry.max_height = maxheight; info->geometry.aspect_ratio = (float)(use_par ? NES_8_7_PAR : NES_4_3); info->timing.sample_rate = (float)sndsamplerate; if (FSettings.PAL || dendy) @@ -1134,7 +1148,7 @@ static void check_variables(bool startup) #ifdef HAVE_NTSC_FILTER var.key = "fceumm_ntsc_filter"; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { unsigned orig_value = use_ntsc; if (strcmp(var.value, "disabled") == 0) @@ -1150,7 +1164,20 @@ static void check_variables(bool startup) if (use_ntsc != orig_value) palette_updated = true; } -#endif + +#ifdef NTSC_SCANLINES + var.key = "fceumm_ntsc_scanlines"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + unsigned orig_value = use_ntsc_scanlines; + if (strcmp(var.value, "enabled") == 0) + use_ntsc_scanlines = 1; + else + use_ntsc_scanlines = 0; + } +#endif /* NTSC_SCANLINES */ +#endif /* HAVE_NTSC_FILTER */ var.key = "fceumm_palette"; @@ -1835,49 +1862,62 @@ static void retro_run_blit(uint8_t *gfx) #ifdef HAVE_NTSC_FILTER if (use_ntsc) { - uint8_t *deemp; - unsigned out_width, out_height, out_pitch; - int y; + int h_offset, v_offset; burst_phase ^= 1; - if (ntsc_setup.merge_fields) burst_phase = 0; + if (ntsc_setup.merge_fields) + burst_phase = 0; - width = overscan_h ? 240 : 256; - height = overscan_v ? 224 : 240; - out_width = overscan_h ? 560 : 602; - out_height = height; - out_pitch = out_width * sizeof(uint16_t); - gfx += (overscan_v ? ((overscan_h ? 8 : 0) + 256 * 8) : (overscan_h ? 8 : 0)); - deemp = XDBuf + (gfx - XBuf); /* get colour emphasis */ + nes_ntsc_blit(&nes_ntsc, (NES_NTSC_IN_T *)gfx, (NES_NTSC_IN_T *)XDBuf, + NES_WIDTH, burst_phase, NES_WIDTH, NES_HEIGHT, + ntsc_video_out, NTSC_WIDTH * sizeof(uint16)); - nes_ntsc_blit(&nes_ntsc, (unsigned char const*)gfx, (unsigned char const*)deemp, NES_WIDTH, burst_phase, width, height, ntsc_video_out, out_pitch); -#if 0 - if (!retain_height) + h_offset = overscan_h ? NES_NTSC_OUT_WIDTH(8) : 0; + v_offset = overscan_v ? 8 : 0; + width = overscan_h ? 560 : 602; + height = overscan_v ? 224 : 240; + pitch = width * sizeof(uint16_t); + +#ifdef NTSC_SCANLINES + if (use_ntsc_scanlines == 0) +#endif { - /* this doubles the height for proper scaling, disabled for performance reasons. - * NOTE: buffer height needs to be doubled as well */ - out_height <<= 1; - for (y = out_height / 2; --y >= 0;) + const uint16_t *in = ntsc_video_out + h_offset + NTSC_WIDTH * v_offset; + uint16_t *out = fceu_video_out; + int y; + + for (y = 0; y < height; y++) { - uint8_t const *in = ntsc_video_out + y * out_pitch; - uint8_t *out = ntsc_video_out + y * 2 * out_pitch; + memcpy(out, in, width * sizeof(uint16_t)); + in += NTSC_WIDTH; + out += width; + } + } +#ifdef NTSC_SCANLINES + else + { + int y; + height <<= 1; + for (y = (NES_HEIGHT - v_offset); --y >= v_offset;) + { + uint16_t const *in = ntsc_video_out + y * NTSC_WIDTH; + uint16_t *out = fceu_video_out + (y - v_offset) * 2 * width; int n; - for (n = out_width; n; --n) + for (n = width; n; --n) { - unsigned prev = *(uint16_t *)in; - unsigned next = *(uint16_t *)(in + out_pitch); + unsigned prev = *(in + h_offset); + unsigned next = *(in + h_offset + NTSC_WIDTH); /* mix 16-bit rgb without losing low bits */ unsigned mixed = prev + next + ((prev ^ next) & 0x0821); /* darken by 12% */ - *(uint16_t *)out = prev; - *(uint16_t *)(out + out_pitch) = (mixed >> 1) - (mixed >> 4 & 0x18E3); - in += 2; - out += 2; + *out = prev; + *(out + width) = (mixed >> 1) - (mixed >> 4 & 0x18E3); + in++; + out++; } } } -#endif - video_cb(ntsc_video_out, out_width, out_height, out_pitch); +#endif /* NTSC_SCANLINES */ } else #endif /* HAVE_NTSC_FILTER */ @@ -1901,9 +1941,8 @@ static void retro_run_blit(uint8_t *gfx) for (x = 0; x < width; x++, gfx++) fceu_video_out[y * width + x] = retro_palette[*gfx]; } - video_cb(fceu_video_out, width, height, pitch); } - + video_cb(fceu_video_out, width, height, pitch); #endif } @@ -2342,7 +2381,18 @@ bool retro_load_game(const struct retro_game_info *game) #if defined(_3DS) fceu_video_out = (uint16_t*)linearMemAlign(256 * 240 * sizeof(uint16_t), 128); #elif !defined(PSP) - fceu_video_out = (uint16_t*)malloc(256 * 240 * sizeof(uint16_t)); +#ifdef HAVE_NTSC_FILTER +#define FB_WIDTH 602 +#ifdef NTSC_SCANLINES +#define FB_HEIGHT 480 +#else +#define FB_HEIGHT 240 +#endif +#else /* !HAVE_NTSC_FILTER */ +#define FB_WIDTH 256 +#define FB_HEIGHT 240 +#endif + fceu_video_out = (uint16_t*)malloc(FB_WIDTH * FB_HEIGHT * sizeof(uint16_t)); #endif environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); diff --git a/src/drivers/libretro/libretro_core_options.h b/src/drivers/libretro/libretro_core_options.h index 35ce4c9..3d37d07 100644 --- a/src/drivers/libretro/libretro_core_options.h +++ b/src/drivers/libretro/libretro_core_options.h @@ -92,6 +92,19 @@ struct retro_core_option_definition option_defs_common[] = { }, "disabled" }, +#ifdef NTSC_SCANLINES + { + "fceumm_ntsc_scanlines", + "NTSC Scanlines", + "Enable scanlines when using NTSC filters.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL }, + }, + "disabled" + }, +#endif /* NTSC_SCANLINES */ #endif { "fceumm_palette", diff --git a/src/ppu.c b/src/ppu.c index 187a96c..cc44e7b 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -702,7 +702,7 @@ static void DoLine(void) for (x = 63; x >= 0; x--) *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0x80808080; - //write the actual colour emphasis + /* write the actual colour emphasis */ colour_emphasis = ((PPU[1] >> 5) << 24) | ((PPU[1] >> 5) << 16) | ((PPU[1] >> 5) << 8) | ((PPU[1] >> 5) << 0); for (x = 63; x >= 0; x--) *(uint32*)&dtarget[x << 2] = colour_emphasis;