(RS90) Add optional approximate 'semi-linear' scaling filter

This commit is contained in:
jdgleaver 2021-07-21 14:11:42 +01:00
parent d4d9129ad4
commit 218286aa99
12 changed files with 545 additions and 183 deletions

View file

@ -420,6 +420,11 @@
* in Dingux devices */
#define DEFAULT_DINGUX_REFRESH_RATE DINGUX_REFRESH_RATE_60HZ
#endif
#if defined(RS90)
/* Sets image filtering method on the RS90
* when integer scaling is disabled */
#define DEFAULT_DINGUX_RS90_SOFTFILTER_TYPE DINGUX_RS90_SOFTFILTER_POINT
#endif
#endif
/* Save configuration file on exit. */

View file

@ -2137,6 +2137,9 @@ static struct config_uint_setting *populate_settings_uint(
#if defined(DINGUX_BETA)
SETTING_UINT("video_dingux_refresh_rate", &settings->uints.video_dingux_refresh_rate, true, DEFAULT_DINGUX_REFRESH_RATE, false);
#endif
#if defined(RS90)
SETTING_UINT("video_dingux_rs90_softfilter_type", &settings->uints.video_dingux_rs90_softfilter_type, true, DEFAULT_DINGUX_RS90_SOFTFILTER_TYPE, false);
#endif
#endif
#ifdef HAVE_MENU

View file

@ -209,6 +209,7 @@ typedef struct settings
unsigned video_3ds_display_mode;
unsigned video_dingux_ipu_filter_type;
unsigned video_dingux_refresh_rate;
unsigned video_dingux_rs90_softfilter_type;
#ifdef HAVE_VIDEO_LAYOUT
unsigned video_layout_selected_view;
#endif

View file

@ -206,16 +206,19 @@ static void xdg_screensaver_inhibit(Window wnd)
RARCH_LOG("[X11]: Suspending screensaver (X11, xdg-screensaver).\n");
/* Make sure the window has a title, even if it's a bogus one, otherwise
* xdg-screensaver will fail and report to stderr, framing RA for its bug.
* A single space character is used so that the title bar stays visibly
* the same, as if there's no title at all. */
video_driver_get_window_title(title, sizeof(title));
if (strlen(title) == 0)
snprintf(title, sizeof(title), " ");
XChangeProperty(g_x11_dpy, g_x11_win, XA_WM_NAME, XA_STRING,
8, PropModeReplace, (const unsigned char*) title,
strlen(title));
if (g_x11_dpy && g_x11_win)
{
/* Make sure the window has a title, even if it's a bogus one, otherwise
* xdg-screensaver will fail and report to stderr, framing RA for its bug.
* A single space character is used so that the title bar stays visibly
* the same, as if there's no title at all. */
video_driver_get_window_title(title, sizeof(title));
if (strlen(title) == 0)
snprintf(title, sizeof(title), " ");
XChangeProperty(g_x11_dpy, g_x11_win, XA_WM_NAME, XA_STRING,
8, PropModeReplace, (const unsigned char*) title,
strlen(title));
}
snprintf(cmd, sizeof(cmd), "xdg-screensaver suspend 0x%x", (int)wnd);

View file

@ -56,11 +56,18 @@
#define SDL_RS90_NUM_FONT_GLYPHS 256
typedef struct sdl_rs90_video
typedef struct sdl_rs90_video sdl_rs90_video_t;
struct sdl_rs90_video
{
retro_time_t last_frame_time;
retro_time_t ff_frame_time_min;
SDL_Surface *screen;
void (*scale_frame16)(sdl_rs90_video_t *vid,
uint16_t *src, unsigned width, unsigned height,
unsigned src_pitch);
void (*scale_frame32)(sdl_rs90_video_t *vid,
uint32_t *src, unsigned width, unsigned height,
unsigned src_pitch);
bitmapfont_lut_t *osd_font;
/* Scaling/padding/cropping parameters */
unsigned content_width;
@ -71,6 +78,7 @@ typedef struct sdl_rs90_video
unsigned frame_padding_y;
unsigned frame_crop_x;
unsigned frame_crop_y;
enum dingux_rs90_softfilter_type softfilter_type;
#if defined(DINGUX_BETA)
enum dingux_refresh_rate refresh_rate;
#endif
@ -85,7 +93,380 @@ typedef struct sdl_rs90_video
bool was_in_menu;
bool quitting;
bool mode_valid;
} sdl_rs90_video_t;
};
/* Image interpolation START */
static void sdl_rs90_scale_frame16_integer(sdl_rs90_video_t *vid,
uint16_t *src, unsigned width, unsigned height,
unsigned src_pitch)
{
/* 16 bit - divide pitch by 2 */
size_t in_stride = (size_t)(src_pitch >> 1);
size_t out_stride = (size_t)(vid->screen->pitch >> 1);
/* Manipulate offsets so that padding/crop
* are applied correctly */
uint16_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride;
uint16_t *out_ptr = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
size_t y = vid->frame_height;
/* TODO/FIXME: Optimize this loop */
do
{
memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint16_t));
in_ptr += in_stride;
out_ptr += out_stride;
}
while (--y);
}
static void sdl_rs90_scale_frame32_integer(sdl_rs90_video_t *vid,
uint32_t *src, unsigned width, unsigned height,
unsigned src_pitch)
{
/* 32 bit - divide pitch by 4 */
size_t in_stride = (size_t)(src_pitch >> 2);
size_t out_stride = (size_t)(vid->screen->pitch >> 2);
/* Manipulate offsets so that padding/crop
* are applied correctly */
uint32_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride;
uint32_t *out_ptr = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
size_t y = vid->frame_height;
/* TODO/FIXME: Optimize this loop */
do
{
memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint32_t));
in_ptr += in_stride;
out_ptr += out_stride;
}
while (--y);
}
/* Approximate nearest-neighbour scaling using
* bitshifts and integer math */
static void sdl_rs90_scale_frame16_point(sdl_rs90_video_t *vid,
uint16_t *src, unsigned width, unsigned height,
unsigned src_pitch)
{
uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width;
uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height;
/* 16 bit - divide pitch by 2 */
size_t in_stride = (size_t)(src_pitch >> 1);
size_t out_stride = (size_t)(vid->screen->pitch >> 1);
/* Apply x/y padding offset */
uint16_t *top_corner = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
/* Temporary pointers */
uint16_t *in_ptr = NULL;
uint16_t *out_ptr = NULL;
uint32_t y = 0;
size_t row;
/* TODO/FIXME: Optimize these loops further.
* Consider saving these computations in an array
* and indexing over them.
* Would likely be slower due to cache (non-)locality,
* but it's worth a shot.
* Tons of -> operations. */
for (row = 0; row < vid->frame_height; row++)
{
size_t col = vid->frame_width;
uint32_t x = 0;
out_ptr = top_corner + out_stride * row;
in_ptr = src + (y >> 16) * in_stride;
do
{
*(out_ptr++) = in_ptr[x >> 16];
x += x_step;
}
while (--col);
y += y_step;
}
}
static void sdl_rs90_scale_frame32_point(sdl_rs90_video_t *vid,
uint32_t *src, unsigned width, unsigned height,
unsigned src_pitch)
{
uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width;
uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height;
/* 32 bit - divide pitch by 4 */
size_t in_stride = (size_t)(src_pitch >> 2);
size_t out_stride = (size_t)(vid->screen->pitch >> 2);
/* Apply x/y padding offset */
uint32_t *top_corner = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
/* Temporary pointers */
uint32_t *in_ptr = NULL;
uint32_t *out_ptr = NULL;
uint32_t y = 0;
size_t row;
/* TODO/FIXME: Optimize these loops further.
* Consider saving these computations in an array
* and indexing over them.
* Would likely be slower due to cache (non-)locality,
* but it's worth a shot.
* Tons of -> operations. */
for (row = 0; row < vid->frame_height; row++)
{
size_t col = vid->frame_width;
uint32_t x = 0;
out_ptr = top_corner + out_stride * row;
in_ptr = src + (y >> 16) * in_stride;
do
{
*(out_ptr++) = in_ptr[x >> 16];
x += x_step;
}
while (--col);
y += y_step;
}
}
/* Produces a 50:50 mix of pixels a and b
* > c.f. "Mixing Packed RGB Pixels Efficiently"
* http://blargg.8bitalley.com/info/rgb_mixing.html */
#define SDL_RS90_PIXEL_AVERAGE_16(a, b) (((a) + (b) + (((a) ^ (b)) & 0x821)) >> 1)
#define SDL_RS90_PIXEL_AVERAGE_32(a, b) (((a) + (b) + (((a) ^ (b)) & 0x10101)) >> 1)
/* Scales a single horizontal line using approximate
* linear scaling
* > c.f. "Image Scaling with Bresenham"
* https://www.drdobbs.com/image-scaling-with-bresenham/184405045 */
static void sdl_rs90_scale_line_bresenham16(uint16_t *target, uint16_t *src,
unsigned src_width, unsigned target_width,
unsigned int_part, unsigned fract_part, unsigned midpoint)
{
unsigned num_pixels = target_width;
unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */
/* If source and target have the same width,
* can perform a fast copy of raw pixel data */
if (src_width == target_width)
{
memcpy(target, src, target_width * sizeof(uint16_t));
return;
}
else if (target_width > src_width)
num_pixels--;
do
{
*(target++) = (E >= midpoint) ?
SDL_RS90_PIXEL_AVERAGE_16(*src, *(src + 1)) : *src;
src += int_part;
E += fract_part;
if (E >= target_width)
{
E -= target_width;
src++;
}
}
while (--num_pixels);
if (target_width > src_width)
*target = *src;
}
static void sdl_rs90_scale_frame16_bresenham_horz(sdl_rs90_video_t *vid,
uint16_t *src, unsigned width, unsigned height,
unsigned src_pitch)
{
/* 16 bit - divide pitch by 2 */
size_t in_stride = (size_t)(src_pitch >> 1);
size_t out_stride = (size_t)(vid->screen->pitch >> 1);
uint16_t *prev_src = NULL;
/* Account for x/y padding */
uint16_t *target = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x +
(out_stride * vid->frame_padding_y);
unsigned target_width = vid->frame_width;
unsigned target_height = vid->frame_height;
unsigned num_lines = target_height;
unsigned int_part = (height / target_height) * in_stride;
unsigned fract_part = height % target_height;
unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */
unsigned col_int_part = width / target_width;
unsigned col_fract_part = width % target_width;
/* Enhance midpoint selection as described in
* https://www.compuphase.com/graphic/scale1errata.htm */
int col_midpoint = (target_width > width) ?
((int)target_width - 3 * ((int)target_width - (int)width)) >> 1 :
(int)(target_width << 1) - (int)width;
/* Clamp lower bound to (target_width / 2) */
if (col_midpoint < (int)(target_width >> 1))
col_midpoint = (int)(target_width >> 1);
while (num_lines--)
{
/* If line is supposed to be identical to
* previous line, just copy it */
if (src == prev_src)
memcpy(target, target - out_stride, target_width * sizeof(uint16_t));
else
{
sdl_rs90_scale_line_bresenham16(target, src, width, target_width,
col_int_part, col_fract_part, (unsigned)col_midpoint);
prev_src = src;
}
target += out_stride;
src += int_part;
E += fract_part;
if (E >= target_height)
{
E -= target_height;
src += in_stride;
}
}
}
static void sdl_rs90_scale_line_bresenham32(uint32_t *target, uint32_t *src,
unsigned src_width, unsigned target_width,
unsigned int_part, unsigned fract_part, unsigned midpoint)
{
unsigned num_pixels = target_width;
unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */
/* If source and target have the same width,
* can perform a fast copy of raw pixel data */
if (src_width == target_width)
{
memcpy(target, src, target_width * sizeof(uint32_t));
return;
}
else if (target_width > src_width)
num_pixels--;
do
{
*(target++) = (E >= midpoint) ?
SDL_RS90_PIXEL_AVERAGE_32(*src, *(src + 1)) : *src;
src += int_part;
E += fract_part;
if (E >= target_width)
{
E -= target_width;
src++;
}
}
while (--num_pixels);
if (target_width > src_width)
*target = *src;
}
static void sdl_rs90_scale_frame32_bresenham_horz(sdl_rs90_video_t *vid,
uint32_t *src, unsigned width, unsigned height,
unsigned src_pitch)
{
/* 32 bit - divide pitch by 4 */
size_t in_stride = (size_t)(src_pitch >> 2);
size_t out_stride = (size_t)(vid->screen->pitch >> 2);
uint32_t *prev_src = NULL;
/* Account for x/y padding */
uint32_t *target = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x +
(out_stride * vid->frame_padding_y);
unsigned target_width = vid->frame_width;
unsigned target_height = vid->frame_height;
unsigned num_lines = target_height;
unsigned int_part = (height / target_height) * in_stride;
unsigned fract_part = height % target_height;
unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */
unsigned col_int_part = width / target_width;
unsigned col_fract_part = width % target_width;
/* Enhance midpoint selection as described in
* https://www.compuphase.com/graphic/scale1errata.htm */
int col_midpoint = (target_width > width) ?
((int)target_width - 3 * ((int)target_width - (int)width)) >> 1 :
(int)(target_width << 1) - (int)width;
/* Clamp lower bound to (target_width / 2) */
if (col_midpoint < (int)(target_width >> 1))
col_midpoint = (int)(target_width >> 1);
while (num_lines--)
{
/* If line is supposed to be identical to
* previous line, just copy it */
if (src == prev_src)
memcpy(target, target - out_stride, target_width * sizeof(uint32_t));
else
{
sdl_rs90_scale_line_bresenham32(target, src, width, target_width,
col_int_part, col_fract_part, (unsigned)col_midpoint);
prev_src = src;
}
target += out_stride;
src += int_part;
E += fract_part;
if (E >= target_height)
{
E -= target_height;
src += in_stride;
}
}
}
static void sdl_rs90_set_scale_frame_functions(sdl_rs90_video_t *vid)
{
/* Set integer scaling by default */
vid->scale_frame16 = sdl_rs90_scale_frame16_integer;
vid->scale_frame32 = sdl_rs90_scale_frame32_integer;
if (!vid->scale_integer)
{
switch (vid->softfilter_type)
{
case DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ:
vid->scale_frame16 = sdl_rs90_scale_frame16_bresenham_horz;
vid->scale_frame32 = sdl_rs90_scale_frame32_bresenham_horz;
break;
case DINGUX_RS90_SOFTFILTER_POINT:
default:
vid->scale_frame16 = sdl_rs90_scale_frame16_point;
vid->scale_frame32 = sdl_rs90_scale_frame32_point;
break;
}
}
}
/* Image interpolation END */
static void sdl_rs90_init_font_color(sdl_rs90_video_t *vid)
{
@ -496,6 +877,8 @@ static void *sdl_rs90_gfx_init(const video_info_t *video,
vid->vsync = video->vsync;
vid->keep_aspect = settings->bools.video_dingux_ipu_keep_aspect;
vid->scale_integer = settings->bools.video_scale_integer;
vid->softfilter_type = (enum dingux_rs90_softfilter_type)
settings->uints.video_dingux_rs90_softfilter_type;
vid->menu_active = false;
vid->was_in_menu = false;
vid->quitting = false;
@ -520,6 +903,9 @@ static void *sdl_rs90_gfx_init(const video_info_t *video,
goto error;
}
/* Assign frame scaling function pointers */
sdl_rs90_set_scale_frame_functions(vid);
return vid;
error:
@ -638,82 +1024,6 @@ static void sdl_rs90_set_output(
}
}
/* Approximate nearest-neighbour scaling using
* bitshifts and integer math */
static void sdl_rs90_blit_frame16_scale(sdl_rs90_video_t *vid,
uint16_t* src, unsigned width, unsigned height,
unsigned src_pitch)
{
uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width;
uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height;
/* 16 bit - divide pitch by 2 */
size_t in_stride = (size_t)(src_pitch >> 1);
size_t out_stride = (size_t)(vid->screen->pitch >> 1);
/* Apply x/y padding offset */
uint16_t *top_corner = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
/* Temporary pointers */
uint16_t *in_ptr = NULL;
uint16_t *out_ptr = NULL;
uint32_t y = 0;
size_t row;
/* TODO/FIXME: Optimize these loops further.
* Consider saving these computations in an array
* and indexing over them.
* Would likely be slower due to cache (non-)locality,
* but it's worth a shot.
* Tons of -> operations. */
for (row = 0; row < vid->frame_height; row++)
{
size_t col = vid->frame_width;
uint32_t x = 0;
out_ptr = top_corner + out_stride * row;
in_ptr = src + (y >> 16) * in_stride;
do
{
*out_ptr = in_ptr[x >> 16];
x += x_step;
out_ptr++;
}
while (--col);
y += y_step;
}
}
static void sdl_rs90_blit_frame16_no_scale(sdl_rs90_video_t *vid,
uint16_t* src, unsigned width, unsigned height,
unsigned src_pitch)
{
/* 16 bit - divide pitch by 2 */
size_t in_stride = (size_t)(src_pitch >> 1);
size_t out_stride = (size_t)(vid->screen->pitch >> 1);
/* Manipulate offsets so that padding/crop
* are applied correctly */
uint16_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride;
uint16_t *out_ptr = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
size_t y = vid->frame_height;
/* TODO/FIXME: Optimize this loop */
do
{
memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint16_t));
in_ptr += in_stride;
out_ptr += out_stride;
}
while (--y);
}
static void sdl_rs90_blit_frame16(sdl_rs90_video_t *vid,
uint16_t* src, unsigned width, unsigned height,
unsigned src_pitch)
@ -726,88 +1036,7 @@ static void sdl_rs90_blit_frame16(sdl_rs90_video_t *vid,
height == SDL_RS90_HEIGHT)
memcpy(vid->screen->pixels, src, src_pitch * SDL_RS90_HEIGHT);
else
{
if (vid->scale_integer)
sdl_rs90_blit_frame16_no_scale(
vid, src, width, height, src_pitch);
else
sdl_rs90_blit_frame16_scale(
vid, src, width, height, src_pitch);
}
}
static void sdl_rs90_blit_frame32_scale(sdl_rs90_video_t *vid,
uint32_t* src, unsigned width, unsigned height,
unsigned src_pitch)
{
uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width;
uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height;
/* 32 bit - divide pitch by 4 */
size_t in_stride = (size_t)(src_pitch >> 2);
size_t out_stride = (size_t)(vid->screen->pitch >> 2);
/* Apply x/y padding offset */
uint32_t *top_corner = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
/* Temporary pointers */
uint32_t *in_ptr = NULL;
uint32_t *out_ptr = NULL;
uint32_t y = 0;
size_t row;
/* TODO/FIXME: Optimize these loops further.
* Consider saving these computations in an array
* and indexing over them.
* Would likely be slower due to cache (non-)locality,
* but it's worth a shot.
* Tons of -> operations. */
for (row = 0; row < vid->frame_height; row++)
{
size_t col = vid->frame_width;
uint32_t x = 0;
out_ptr = top_corner + out_stride * row;
in_ptr = src + (y >> 16) * in_stride;
do
{
*out_ptr = in_ptr[x >> 16];
x += x_step;
out_ptr++;
}
while (--col);
y += y_step;
}
}
static void sdl_rs90_blit_frame32_no_scale(sdl_rs90_video_t *vid,
uint32_t* src, unsigned width, unsigned height,
unsigned src_pitch)
{
/* 32 bit - divide pitch by 4 */
size_t in_stride = (size_t)(src_pitch >> 2);
size_t out_stride = (size_t)(vid->screen->pitch >> 2);
/* Manipulate offsets so that padding/crop
* are applied correctly */
uint32_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride;
uint32_t *out_ptr = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x +
out_stride * vid->frame_padding_y;
size_t y = vid->frame_height;
/* TODO/FIXME: Optimize this loop */
do
{
memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint32_t));
in_ptr += in_stride;
out_ptr += out_stride;
}
while (--y);
vid->scale_frame16(vid, src, width, height, src_pitch);
}
static void sdl_rs90_blit_frame32(sdl_rs90_video_t *vid,
@ -822,14 +1051,7 @@ static void sdl_rs90_blit_frame32(sdl_rs90_video_t *vid,
(height == SDL_RS90_HEIGHT))
memcpy(vid->screen->pixels, src, src_pitch * SDL_RS90_HEIGHT);
else
{
if (vid->scale_integer)
sdl_rs90_blit_frame32_no_scale(
vid, src, width, height, src_pitch);
else
sdl_rs90_blit_frame32_scale(
vid, src, width, height, src_pitch);
}
vid->scale_frame32(vid, src, width, height, src_pitch);
}
static bool sdl_rs90_gfx_frame(void *data, const void *frame,
@ -1096,6 +1318,25 @@ static float sdl_rs90_get_refresh_rate(void *data)
return 60.0f;
}
static void sdl_rs90_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling)
{
sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data;
settings_t *settings = config_get_ptr();
enum dingux_rs90_softfilter_type softfilter_type = (settings) ?
(enum dingux_rs90_softfilter_type)settings->uints.video_dingux_rs90_softfilter_type :
DINGUX_RS90_SOFTFILTER_POINT;
if (!vid || !settings)
return;
/* Update software filter setting, if required */
if (vid->softfilter_type != softfilter_type)
{
vid->softfilter_type = softfilter_type;
sdl_rs90_set_scale_frame_functions(vid);
}
}
static void sdl_rs90_apply_state_changes(void *data)
{
sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data;
@ -1112,12 +1353,17 @@ static void sdl_rs90_apply_state_changes(void *data)
vid->keep_aspect = keep_aspect;
vid->scale_integer = integer_scaling;
/* Reassign frame scaling function pointers */
sdl_rs90_set_scale_frame_functions(vid);
/* Aspect/scaling changes require all frame
* dimension/padding/cropping parameters to
* be recalculated. Easiest method is to just
* (re-)set the current output video mode */
* (re-)set the current output video mode
* Note: If menu is active, colour depth is
* overridden to 16 bit */
sdl_rs90_set_output(vid, vid->content_width,
vid->content_height, vid->rgb32);
vid->content_height, vid->menu_active ? false : vid->rgb32);
}
}
@ -1132,7 +1378,7 @@ static const video_poke_interface_t sdl_rs90_poke_interface = {
NULL,
NULL,
sdl_rs90_get_refresh_rate,
NULL, /* set_filtering */
sdl_rs90_set_filtering,
NULL, /* get_video_output_size */
NULL, /* get_video_output_prev */
NULL, /* get_video_output_next */

View file

@ -3181,6 +3181,12 @@ MSG_HASH(
"video_dingux_refresh_rate"
)
#endif
#if defined(RS90)
MSG_HASH(
MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
"video_dingux_rs90_softfilter_type"
)
#endif
#endif
MSG_HASH(
MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION,

View file

@ -1373,6 +1373,24 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_IPU_FILTER_NEAREST,
"Nearest Neighbor"
)
#if defined(RS90)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
"Image Interpolation"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
"Specify image interpolation method when 'Integer Scale' is disabled. 'Nearest Neighbor' has the least performance impact."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT,
"Nearest Neighbor"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ,
"Semi-Linear"
)
#endif
#endif
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DELAY,

View file

@ -872,6 +872,9 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_dingux_ipu_filter_type,
#if defined(DINGUX_BETA)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_dingux_refresh_rate, MENU_ENUM_SUBLABEL_VIDEO_DINGUX_REFRESH_RATE)
#endif
#if defined(RS90)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_dingux_rs90_softfilter_type, MENU_ENUM_SUBLABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE)
#endif
#endif
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_height, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_width, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH)
@ -1968,6 +1971,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_dingux_refresh_rate);
break;
#endif
#if defined(RS90)
case MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_dingux_rs90_softfilter_type);
break;
#endif
#endif
case MENU_ENUM_LABEL_CORE_INFORMATION:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_information);

View file

@ -416,6 +416,15 @@ enum quit_on_close_content_type
QUIT_ON_CLOSE_CONTENT_LAST
};
#if defined(DINGUX) && defined(RS90)
enum dingux_rs90_softfilter_type
{
DINGUX_RS90_SOFTFILTER_POINT = 0,
DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ,
DINGUX_RS90_SOFTFILTER_LAST
};
#endif
RETRO_END_DECLS
#endif

View file

@ -6028,6 +6028,12 @@ unsigned menu_displaylist_build_list(
MENU_ENUM_LABEL_VIDEO_DINGUX_IPU_FILTER_TYPE,
PARSE_ONLY_UINT, false) == 0)
count++;
#if defined(RS90)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
PARSE_ONLY_UINT, false) == 0)
count++;
#endif
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SHADER_DELAY,

View file

@ -5200,6 +5200,32 @@ static void setting_get_string_representation_uint_video_dingux_refresh_rate(
}
}
#endif
#if defined(RS90)
static void setting_get_string_representation_uint_video_dingux_rs90_softfilter_type(
rarch_setting_t *setting,
char *s, size_t len)
{
if (!setting)
return;
switch (*setting->value.target.unsigned_integer)
{
case DINGUX_RS90_SOFTFILTER_POINT:
strlcpy(s,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT),
len);
break;
case DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ:
strlcpy(s,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ),
len);
break;
}
}
#endif
#endif
static void setting_get_string_representation_uint_input_auto_game_focus(
@ -7615,10 +7641,14 @@ static void general_write_handler(rarch_setting_t *setting)
case MENU_ENUM_LABEL_VIDEO_CTX_SCALING:
#if defined(DINGUX)
case MENU_ENUM_LABEL_VIDEO_DINGUX_IPU_FILTER_TYPE:
#if defined(RS90)
case MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE:
#endif
#endif
{
settings_t *settings = config_get_ptr();
video_driver_set_filtering(1, settings->bools.video_ctx_scaling, settings->bools.video_ctx_scaling);
video_driver_set_filtering(1, settings->bools.video_smooth,
settings->bools.video_ctx_scaling);
}
break;
case MENU_ENUM_LABEL_VIDEO_ROTATION:
@ -11482,7 +11512,28 @@ static bool setting_append_list(
menu_settings_list_current_add_range(list, list_info, 0, DINGUX_IPU_FILTER_LAST - 1, 1, true, true);
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;
}
else if (!string_is_equal(settings->arrays.video_driver, "sdl_rs90"))
#if defined(RS90)
else if (string_is_equal(settings->arrays.video_driver, "sdl_rs90"))
{
CONFIG_UINT(
list, list_info,
&settings->uints.video_dingux_rs90_softfilter_type,
MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
DEFAULT_DINGUX_RS90_SOFTFILTER_TYPE,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_uint_video_dingux_rs90_softfilter_type;
menu_settings_list_current_add_range(list, list_info, 0, DINGUX_RS90_SOFTFILTER_LAST - 1, 1, true, true);
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;
}
#endif
else
#endif
{
CONFIG_BOOL(

View file

@ -2474,6 +2474,12 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_REFRESH_RATE_60HZ,
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_REFRESH_RATE_50HZ,
#endif
#if defined(RS90)
MENU_LABEL(VIDEO_DINGUX_RS90_SOFTFILTER_TYPE),
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT,
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ,
#endif
#endif
MENU_LABEL(VIDEO_VFILTER),
MENU_LABEL(VIDEO_GPU_RECORD),