From bd56e1e29c9de65a23cb00b03e72a17eadb53441 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Wed, 23 Jan 2019 16:44:20 +0000 Subject: [PATCH] (RGUI) Allow selection of thumbnail downscaling method --- config.def.h | 2 ++ configuration.c | 1 + configuration.h | 1 + intl/msg_hash_lbl.h | 2 ++ intl/msg_hash_us.h | 16 +++++++++ menu/drivers/rgui.c | 76 +++++++++++++++++++++++++++++++++-------- menu/menu_displaylist.c | 4 +++ menu/menu_driver.h | 8 +++++ menu/menu_setting.c | 49 ++++++++++++++++++++++++++ msg_hash.h | 5 +++ 10 files changed, 149 insertions(+), 15 deletions(-) diff --git a/config.def.h b/config.def.h index 98c1c33740..2ed6bfb5ab 100644 --- a/config.def.h +++ b/config.def.h @@ -752,6 +752,8 @@ static const unsigned menu_timedate_style = 5; static const bool xmb_vertical_thumbnails = false; +static unsigned rgui_thumbnail_downscaler = RGUI_THUMB_SCALE_POINT; + #ifdef IOS static const bool ui_companion_start_on_boot = false; #else diff --git a/configuration.c b/configuration.c index 3eff180dd7..45e69835f2 100644 --- a/configuration.c +++ b/configuration.c @@ -1654,6 +1654,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("menu_thumbnails", &settings->uints.menu_thumbnails, true, menu_thumbnails_default, false); SETTING_UINT("menu_timedate_style", &settings->uints.menu_timedate_style, true, menu_timedate_style, false); SETTING_UINT("rgui_menu_color_theme", &settings->uints.menu_rgui_color_theme, true, rgui_color_theme, false); + SETTING_UINT("rgui_thumbnail_downscaler", &settings->uints.menu_rgui_thumbnail_downscaler, true, rgui_thumbnail_downscaler, false); #ifdef HAVE_LIBNX SETTING_UINT("split_joycon_p1", &settings->uints.input_split_joycon[0], true, 0, false); SETTING_UINT("split_joycon_p2", &settings->uints.input_split_joycon[1], true, 0, false); diff --git a/configuration.h b/configuration.h index 464885a58f..cbe6f7888f 100644 --- a/configuration.h +++ b/configuration.h @@ -403,6 +403,7 @@ typedef struct settings unsigned menu_timedate_style; unsigned menu_thumbnails; unsigned menu_left_thumbnails; + unsigned menu_rgui_thumbnail_downscaler; unsigned menu_dpi_override_value; unsigned menu_entry_normal_color; unsigned menu_entry_hover_color; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index aef8983686..0dcb5bb540 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1117,6 +1117,8 @@ MSG_HASH(MENU_ENUM_LABEL_LEFT_THUMBNAILS, "left thumbnails") MSG_HASH(MENU_ENUM_LABEL_XMB_VERTICAL_THUMBNAILS, "xmb_vertical_thumbnails") +MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, + "rgui_thumbnail_downscaler") MSG_HASH(MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY, "thumbnails_directory") MSG_HASH(MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0615dca690..04877b9445 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2934,6 +2934,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, "Thumbnails Vertical Disposition" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DOWNSCALER, + "Thumbnail Downscaling Method" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_POINT, + "Nearest Neighbour (Fast)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_BILINEAR, + "Bilinear" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_SINC, + "Sinc/Lanczos3 (Slow)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, "Thumbnails" diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 49a05eef45..b6147583d1 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -53,6 +53,7 @@ /* Thumbnail additions */ #include #include "../../tasks/tasks_internal.h" +#include #define RGUI_TERM_START_X(width) (width / 21) #define RGUI_TERM_START_Y(height) (height / 9) @@ -422,6 +423,7 @@ typedef struct char *thumbnail_path; char *thumbnail_playlist; uint32_t thumbnail_queue_size; + struct scaler_ctx image_scaler; } rgui_t; #define THUMB_MAX_WIDTH 320 @@ -589,14 +591,12 @@ static void request_thumbnail(rgui_t *rgui, const char *path) } } -static bool downscale_thumbnail(struct texture_image *image_src, struct texture_image *image_dst) +static bool downscale_thumbnail(rgui_t *rgui, struct texture_image *image_src, struct texture_image *image_dst) { - uint32_t x_ratio, y_ratio; - unsigned x_src, y_src; - unsigned x_dst, y_dst; - static const float display_aspect_ratio = (float)THUMB_MAX_WIDTH / (float)THUMB_MAX_HEIGHT; + settings_t *settings = config_get_ptr(); /* Determine output dimensions */ + static const float display_aspect_ratio = (float)THUMB_MAX_WIDTH / (float)THUMB_MAX_HEIGHT; float aspect_ratio = (float)image_src->width / (float)image_src->height; if (aspect_ratio > display_aspect_ratio) { @@ -620,19 +620,65 @@ static bool downscale_thumbnail(struct texture_image *image_src, struct texture_ if (!image_dst->pixels) return false; - /* Perform nearest neighbour resampling */ - x_ratio = ((image_src->width << 16) / image_dst->width); - y_ratio = ((image_src->height << 16) / image_dst->height); - - for (y_dst = 0; y_dst < image_dst->height; y_dst++) + /* Determine scaling method */ + if (settings->uints.menu_rgui_thumbnail_downscaler == RGUI_THUMB_SCALE_POINT) { - y_src = (y_dst * y_ratio) >> 16; - for (x_dst = 0; x_dst < image_dst->width; x_dst++) + uint32_t x_ratio, y_ratio; + unsigned x_src, y_src; + unsigned x_dst, y_dst; + + /* Perform nearest neighbour resampling + * > Fastest method, minimal performance impact */ + x_ratio = ((image_src->width << 16) / image_dst->width); + y_ratio = ((image_src->height << 16) / image_dst->height); + + for (y_dst = 0; y_dst < image_dst->height; y_dst++) { - x_src = (x_dst * x_ratio) >> 16; - image_dst->pixels[(y_dst * image_dst->width) + x_dst] = image_src->pixels[(y_src * image_src->width) + x_src]; + y_src = (y_dst * y_ratio) >> 16; + for (x_dst = 0; x_dst < image_dst->width; x_dst++) + { + x_src = (x_dst * x_ratio) >> 16; + image_dst->pixels[(y_dst * image_dst->width) + x_dst] = image_src->pixels[(y_src * image_src->width) + x_src]; + } } } + else + { + /* Perform either bilinear or sinc (Lanczos3) resampling + * using libretro-common scaler + * > Better quality, but substantially higher performance + * impact - although not an issue on desktop-class + * hardware */ + rgui->image_scaler.in_width = image_src->width; + rgui->image_scaler.in_height = image_src->height; + rgui->image_scaler.in_stride = image_src->width * sizeof(uint32_t); + rgui->image_scaler.in_fmt = SCALER_FMT_ARGB8888; + + rgui->image_scaler.out_width = image_dst->width; + rgui->image_scaler.out_height = image_dst->height; + rgui->image_scaler.out_stride = image_dst->width * sizeof(uint32_t); + rgui->image_scaler.out_fmt = SCALER_FMT_ARGB8888; + + rgui->image_scaler.scaler_type = (settings->uints.menu_rgui_thumbnail_downscaler == RGUI_THUMB_SCALE_SINC) ? + SCALER_TYPE_SINC : SCALER_TYPE_BILINEAR; + + /* This reset is redundant, since scaler_ctx_gen_filter() + * calls it - but do it anyway in case the + * scaler_ctx_gen_filter() internals ever change... */ + scaler_ctx_gen_reset(&rgui->image_scaler); + if(!scaler_ctx_gen_filter(&rgui->image_scaler)) + { + /* Could be leftovers if scaler_ctx_gen_filter() + * fails, so reset just in case... */ + scaler_ctx_gen_reset(&rgui->image_scaler); + return false; + } + + scaler_ctx_scale(&rgui->image_scaler, image_dst->pixels, image_src->pixels); + /* Reset again - don't want to leave anything hanging around + * if the user switches back to nearest neighbour scaling */ + scaler_ctx_gen_reset(&rgui->image_scaler); + } return true; } @@ -668,7 +714,7 @@ static void process_thumbnail(rgui_t *rgui, struct texture_image *image_src) /* Downscale thumbnail if it exceeds maximum size limits */ if ((image_src->width > THUMB_MAX_WIDTH) || (image_src->height > THUMB_MAX_HEIGHT)) { - if (!downscale_thumbnail(image_src, &image_resampled)) + if (!downscale_thumbnail(rgui, image_src, &image_resampled)) return; image = &image_resampled; } diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index e809799bfb..118e8cbde5 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -6119,6 +6119,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist MENU_ENUM_LABEL_XMB_VERTICAL_THUMBNAILS, PARSE_ONLY_BOOL, false) == 0) count++; + if (menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, + PARSE_ONLY_UINT, false) == 0) + count++; if (count == 0) menu_entries_append_enum(info->list, diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 681ac785a3..81282c1d4d 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -383,6 +383,14 @@ enum menu_toggle_reason MENU_TOGGLE_REASON_MESSAGE }; +enum rgui_thumbnail_scaler +{ + RGUI_THUMB_SCALE_POINT = 0, + RGUI_THUMB_SCALE_BILINEAR, + RGUI_THUMB_SCALE_SINC, + RGUI_THUMB_SCALE_LAST +}; + typedef uintptr_t menu_texture_item; typedef struct menu_display_ctx_clearcolor diff --git a/menu/menu_setting.c b/menu/menu_setting.c index d3c6cbf54c..048a09d360 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -786,6 +786,36 @@ static void setting_get_string_representation_uint_rgui_menu_color_theme( } } +static void setting_get_string_representation_uint_rgui_thumbnail_scaler( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (!setting) + return; + + switch (*setting->value.target.unsigned_integer) + { + case RGUI_THUMB_SCALE_POINT: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_POINT), + len); + break; + case RGUI_THUMB_SCALE_BILINEAR: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_BILINEAR), + len); + break; + case RGUI_THUMB_SCALE_SINC: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_SINC), + len); + break; + } +} + static void setting_get_string_representation_uint_xmb_icon_theme( rarch_setting_t *setting, char *s, size_t len) @@ -8741,6 +8771,25 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0, 3, 1, true, true); } + if (string_is_equal(settings->arrays.menu_driver, "rgui")) + { + CONFIG_UINT( + list, list_info, + &settings->uints.menu_rgui_thumbnail_downscaler, + MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, + MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DOWNSCALER, + rgui_thumbnail_downscaler, + &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_rgui_thumbnail_scaler; + menu_settings_list_current_add_range(list, list_info, 0, RGUI_THUMB_SCALE_LAST-1, 1, true, true); + } + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) { CONFIG_UINT( diff --git a/msg_hash.h b/msg_hash.h index a1226afcd2..d72ee9c761 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -883,6 +883,7 @@ enum msg_hash_enums MENU_LABEL(THUMBNAILS), MENU_LABEL(LEFT_THUMBNAILS), MENU_LABEL(XMB_VERTICAL_THUMBNAILS), + MENU_LABEL(MENU_RGUI_THUMBNAIL_DOWNSCALER), MENU_LABEL(TIMEDATE_ENABLE), MENU_LABEL(TIMEDATE_STYLE), MENU_LABEL(BATTERY_LEVEL_ENABLE), @@ -1943,6 +1944,10 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_POINT, + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_BILINEAR, + MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_SINC, + /* Callback strings */ MENU_ENUM_LABEL_CB_CORE_CONTENT_DIRS_LIST, MENU_ENUM_LABEL_CB_CORE_CONTENT_DOWNLOAD,