From c4bb2f5ad7153b171f39a4f95e23fa35818f3108 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Wed, 5 Jun 2019 17:04:23 +0100 Subject: [PATCH] (XMB/Ozone) Add optional thumbnail upscaling --- config.def.h | 2 + configuration.c | 1 + configuration.h | 1 + intl/msg_hash_lbl.h | 2 + intl/msg_hash_us.h | 8 ++++ menu/cbs/menu_cbs_ok.c | 2 +- menu/cbs/menu_cbs_sublabel.c | 4 ++ menu/drivers/materialui.c | 2 +- menu/drivers/ozone/ozone.c | 12 ++---- menu/drivers/rgui.c | 4 +- menu/drivers/stripes.c | 10 ++--- menu/drivers/xmb.c | 18 ++++---- menu/menu_displaylist.c | 1 + menu/menu_setting.c | 17 ++++++++ msg_hash.h | 1 + tasks/task_image.c | 80 +++++++++++++++++++++++++++++++++++- tasks/tasks_internal.h | 2 +- 17 files changed, 137 insertions(+), 30 deletions(-) diff --git a/config.def.h b/config.def.h index 1613d04ecf..ca556e9caa 100644 --- a/config.def.h +++ b/config.def.h @@ -821,6 +821,8 @@ static const unsigned menu_thumbnails_default = 3; static const unsigned menu_left_thumbnails_default = 0; +static const unsigned menu_thumbnail_upscale_threshold = 0; + static const unsigned menu_timedate_style = 5; static const bool xmb_vertical_thumbnails = false; diff --git a/configuration.c b/configuration.c index 29de8f4491..3afd257805 100644 --- a/configuration.c +++ b/configuration.c @@ -1740,6 +1740,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, #ifdef HAVE_MENU SETTING_UINT("dpi_override_value", &settings->uints.menu_dpi_override_value, true, menu_dpi_override_value, false); SETTING_UINT("menu_thumbnails", &settings->uints.menu_thumbnails, true, menu_thumbnails_default, false); + SETTING_UINT("menu_thumbnail_upscale_threshold", &settings->uints.menu_thumbnail_upscale_threshold, true, menu_thumbnail_upscale_threshold, false); SETTING_UINT("menu_timedate_style", &settings->uints.menu_timedate_style, true, menu_timedate_style, false); SETTING_UINT("menu_ticker_type", &settings->uints.menu_ticker_type, true, menu_ticker_type, false); #ifdef HAVE_RGUI diff --git a/configuration.h b/configuration.h index d3c6a1e61d..b98957d165 100644 --- a/configuration.h +++ b/configuration.h @@ -457,6 +457,7 @@ typedef struct settings unsigned menu_timedate_style; unsigned menu_thumbnails; unsigned menu_left_thumbnails; + unsigned menu_thumbnail_upscale_threshold; unsigned menu_rgui_thumbnail_downscaler; unsigned menu_rgui_thumbnail_delay; unsigned menu_dpi_override_value; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 13d2b5d714..8cc91688c5 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1151,6 +1151,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_THUMBNAIL_UPSCALE_THRESHOLD, + "menu_thumbnail_upscale_threshold") MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, "rgui_thumbnail_downscaler") MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 4912e6b0b4..87ee4c3b3f 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3034,6 +3034,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_XMB_VERTICAL_THUMBNAILS, "Thumbnails Vertical Disposition" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_THUMBNAIL_UPSCALE_THRESHOLD, + "Thumbnail Upscaling Threshold" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD, + "Automatically upscale thumbnail images with a width/height smaller than the specified value. Improves picture quality. Has a moderate performance impact." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_INLINE_THUMBNAILS, "Show Playlist Thumbnails" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 74172cbb81..3464603ba7 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1388,7 +1388,7 @@ static int generic_action_ok(const char *path, action_path, sizeof(settings->paths.path_menu_wallpaper)); task_push_image_load(action_path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); } break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 0df61f1b55..da17b32fa0 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -357,6 +357,7 @@ default_sublabel_macro(action_bind_sublabel_thumbnails_rgui, MENU_ default_sublabel_macro(action_bind_sublabel_left_thumbnails, MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS) default_sublabel_macro(action_bind_sublabel_left_thumbnails_rgui, MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_RGUI) default_sublabel_macro(action_bind_sublabel_left_thumbnails_ozone, MENU_ENUM_SUBLABEL_LEFT_THUMBNAILS_OZONE) +default_sublabel_macro(action_bind_sublabel_menu_thumbnail_upscale_threshold, MENU_ENUM_SUBLABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD) default_sublabel_macro(action_bind_sublabel_timedate_enable, MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE) default_sublabel_macro(action_bind_sublabel_timedate_style, MENU_ENUM_SUBLABEL_TIMEDATE_STYLE) default_sublabel_macro(action_bind_sublabel_battery_level_enable, MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE) @@ -1719,6 +1720,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_left_thumbnails); } break; + case MENU_ENUM_LABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_thumbnail_upscale_threshold); + break; case MENU_ENUM_LABEL_MOUSE_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_mouse_enable); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 8ac2baa5d4..fbe6a0795d 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -1885,7 +1885,7 @@ static void materialui_context_reset(void *data, bool is_threaded) if (path_is_valid(settings->paths.path_menu_wallpaper)) task_push_image_load(settings->paths.path_menu_wallpaper, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); } diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index ad9a85633f..0b2b9cdfd1 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -392,6 +392,7 @@ static void ozone_update_thumbnail_path(void *data, unsigned i, char pos) static void ozone_update_thumbnail_image(void *data) { + settings_t *settings = config_get_ptr(); ozone_handle_t *ozone = (ozone_handle_t*)data; const char *right_thumbnail_path = NULL; const char *left_thumbnail_path = NULL; @@ -404,14 +405,14 @@ static void ozone_update_thumbnail_image(void *data) bool thumbnails_missing = false; #endif - if (!ozone) + if (!ozone || !settings) return; if (menu_thumbnail_get_path(ozone->thumbnail_path_data, MENU_THUMBNAIL_RIGHT, &right_thumbnail_path)) { if (path_is_valid(right_thumbnail_path)) task_push_image_load(right_thumbnail_path, - supports_rgba, + supports_rgba, settings->uints.menu_thumbnail_upscale_threshold, menu_display_handle_thumbnail_upload, NULL); else { @@ -428,7 +429,7 @@ static void ozone_update_thumbnail_image(void *data) { if (path_is_valid(left_thumbnail_path)) task_push_image_load(left_thumbnail_path, - supports_rgba, + supports_rgba, settings->uints.menu_thumbnail_upscale_threshold, menu_display_handle_left_thumbnail_upload, NULL); else { @@ -445,11 +446,6 @@ static void ozone_update_thumbnail_image(void *data) /* On demand thumbnail downloads */ if (thumbnails_missing) { - settings_t *settings = config_get_ptr(); - - if (!settings) - return; - if (settings->bools.network_on_demand_thumbnails) { const char *system = NULL; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 57990cdfd4..ea49adcb1b 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -1602,7 +1602,7 @@ static bool request_thumbnail( /* Would like to cancel any existing image load tasks * here, but can't see how to do it... */ if(task_push_image_load(thumbnail->path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, (thumbnail_id == MENU_THUMBNAIL_LEFT) ? menu_display_handle_left_thumbnail_upload : menu_display_handle_thumbnail_upload, NULL)) { @@ -2204,7 +2204,7 @@ end: * here - in general, wallpaper is loaded once per session * and then forgotten, so performance issues are not a concern */ task_push_image_load(wallpaper_path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); } } diff --git a/menu/drivers/stripes.c b/menu/drivers/stripes.c index a238a67d2b..b318237c36 100644 --- a/menu/drivers/stripes.c +++ b/menu/drivers/stripes.c @@ -1065,7 +1065,7 @@ static void stripes_update_thumbnail_image(void *data) { if (path_is_valid(stripes->thumbnail_file_path)) task_push_image_load(stripes->thumbnail_file_path, - supports_rgba, + supports_rgba, 0, menu_display_handle_thumbnail_upload, NULL); else video_driver_texture_unload(&stripes->thumbnail); @@ -1078,7 +1078,7 @@ static void stripes_update_thumbnail_image(void *data) { if (path_is_valid(stripes->left_thumbnail_file_path)) task_push_image_load(stripes->left_thumbnail_file_path, - supports_rgba, + supports_rgba, 0, menu_display_handle_left_thumbnail_upload, NULL); else video_driver_texture_unload(&stripes->left_thumbnail); @@ -1142,7 +1142,7 @@ static void stripes_update_savestate_thumbnail_image(void *data) if (path_is_valid(stripes->savestate_thumbnail_file_path)) task_push_image_load(stripes->savestate_thumbnail_file_path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_savestate_thumbnail_upload, NULL); else video_driver_texture_unload(&stripes->savestate_thumbnail); @@ -1519,7 +1519,7 @@ static void stripes_list_switch_new(stripes_handle_t *stripes, if (path_is_valid(path)) { task_push_image_load(path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); if (!string_is_empty(stripes->bg_file_path)) free(stripes->bg_file_path); @@ -3681,7 +3681,7 @@ static void stripes_context_reset_background(const char *iconpath) if (path_is_valid(path)) task_push_image_load(path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); if (path) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 7842666331..0afd29078e 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1008,6 +1008,7 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) static void xmb_update_thumbnail_image(void *data) { + settings_t *settings = config_get_ptr(); xmb_handle_t *xmb = (xmb_handle_t*)data; const char *right_thumbnail_path = NULL; const char *left_thumbnail_path = NULL; @@ -1020,14 +1021,14 @@ static void xmb_update_thumbnail_image(void *data) bool thumbnails_missing = false; #endif - if (!xmb) + if (!xmb || !settings) return; if (menu_thumbnail_get_path(xmb->thumbnail_path_data, MENU_THUMBNAIL_RIGHT, &right_thumbnail_path)) { if (path_is_valid(right_thumbnail_path)) task_push_image_load(right_thumbnail_path, - supports_rgba, + supports_rgba, settings->uints.menu_thumbnail_upscale_threshold, menu_display_handle_thumbnail_upload, NULL); else { @@ -1044,7 +1045,7 @@ static void xmb_update_thumbnail_image(void *data) { if (path_is_valid(left_thumbnail_path)) task_push_image_load(left_thumbnail_path, - supports_rgba, + supports_rgba, settings->uints.menu_thumbnail_upscale_threshold, menu_display_handle_left_thumbnail_upload, NULL); else { @@ -1061,11 +1062,6 @@ static void xmb_update_thumbnail_image(void *data) /* On demand thumbnail downloads */ if (thumbnails_missing) { - settings_t *settings = config_get_ptr(); - - if (!settings) - return; - if (settings->bools.network_on_demand_thumbnails) { const char *system = NULL; @@ -1234,7 +1230,7 @@ static void xmb_update_savestate_thumbnail_image(void *data) if (path_is_valid(xmb->savestate_thumbnail_file_path)) task_push_image_load(xmb->savestate_thumbnail_file_path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_savestate_thumbnail_upload, NULL); else video_driver_texture_unload(&xmb->savestate_thumbnail); @@ -1690,7 +1686,7 @@ static void xmb_list_switch_new(xmb_handle_t *xmb, if (path_is_valid(path)) { task_push_image_load(path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); if (!string_is_empty(xmb->bg_file_path)) free(xmb->bg_file_path); @@ -5065,7 +5061,7 @@ static void xmb_context_reset_background(const char *iconpath) if (path_is_valid(path)) task_push_image_load(path, - video_driver_supports_rgba(), + video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); #ifdef ORBIS diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 47b3c238cc..9188faf6bc 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4462,6 +4462,7 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct {MENU_ENUM_LABEL_THUMBNAILS, PARSE_ONLY_UINT }, {MENU_ENUM_LABEL_LEFT_THUMBNAILS, PARSE_ONLY_UINT }, {MENU_ENUM_LABEL_XMB_VERTICAL_THUMBNAILS, PARSE_ONLY_BOOL }, + {MENU_ENUM_LABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD, PARSE_ONLY_UINT }, {MENU_ENUM_LABEL_MENU_RGUI_SWAP_THUMBNAILS, PARSE_ONLY_BOOL }, {MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, PARSE_ONLY_UINT }, {MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY, PARSE_ONLY_UINT }, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 0bacca3e79..a20374b5de 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -12289,6 +12289,23 @@ static bool setting_append_list( SD_FLAG_NONE); } + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) + { + CONFIG_UINT( + list, list_info, + &settings->uints.menu_thumbnail_upscale_threshold, + MENU_ENUM_LABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD, + MENU_ENUM_LABEL_VALUE_MENU_THUMBNAIL_UPSCALE_THRESHOLD, + menu_thumbnail_upscale_threshold, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + menu_settings_list_current_add_range(list, list_info, 0, 1024, 256, true, true); + } + if (string_is_equal(settings->arrays.menu_driver, "rgui")) { CONFIG_UINT( diff --git a/msg_hash.h b/msg_hash.h index 9e8001daa2..8815ccc147 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -935,6 +935,7 @@ enum msg_hash_enums MENU_LABEL(LEFT_THUMBNAILS_RGUI), MENU_LABEL(LEFT_THUMBNAILS_OZONE), MENU_LABEL(XMB_VERTICAL_THUMBNAILS), + MENU_LABEL(MENU_THUMBNAIL_UPSCALE_THRESHOLD), MENU_LABEL(MENU_RGUI_INLINE_THUMBNAILS), MENU_LABEL(MENU_RGUI_SWAP_THUMBNAILS), MENU_LABEL(MENU_RGUI_THUMBNAIL_DOWNSCALER), diff --git a/tasks/task_image.c b/tasks/task_image.c index 48c1944a67..cbe7fe41e9 100644 --- a/tasks/task_image.c +++ b/tasks/task_image.c @@ -49,6 +49,7 @@ struct nbio_image_handle int processing_final_state; unsigned frame_duration; size_t size; + unsigned upscale_threshold; void *handle; transfer_cb_t cb; struct texture_image ti; @@ -226,6 +227,48 @@ static int cb_nbio_image_thumbnail(void *data, size_t len) return 0; } +static bool upscale_image( + unsigned scale_factor, + 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; + + /* Sanity check */ + if ((scale_factor < 1) || !image_src || !image_dst) + return false; + + if (!image_src->pixels || (image_src->width < 1) || (image_src->height < 1)) + return false; + + /* Get output dimensions */ + image_dst->width = image_src->width * scale_factor; + image_dst->height = image_src->height * scale_factor; + + /* Allocate pixel buffer */ + image_dst->pixels = (uint32_t*)calloc(image_dst->width * image_dst->height, sizeof(uint32_t)); + 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++) + { + 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]; + } + } + + return true; +} + bool task_image_load_handler(retro_task_t *task) { nbio_handle_t *nbio = (nbio_handle_t*)task->state; @@ -286,6 +329,40 @@ bool task_image_load_handler(retro_task_t *task) if (img) { + /* Upscale image, if required */ + if (image->upscale_threshold > 0) + { + if (((image->ti.width > 0) && (image->ti.height > 0)) && + ((image->ti.width < image->upscale_threshold) || + (image->ti.height < image->upscale_threshold))) + { + unsigned min_size = (image->ti.width < image->ti.height) ? + image->ti.width : image->ti.height; + float scale_factor = (float)image->upscale_threshold / + (float)min_size; + unsigned scale_factor_int = (unsigned)scale_factor; + struct texture_image img_resampled = { + 0, + 0, + NULL, + false + }; + + if (scale_factor - (float)scale_factor_int > 0.0f) + scale_factor_int += 1; + + if (upscale_image(scale_factor_int, &image->ti, &img_resampled)) + { + image->ti.width = img_resampled.width; + image->ti.height = img_resampled.height; + + if (image->ti.pixels) + free(image->ti.pixels); + image->ti.pixels = img_resampled.pixels; + } + } + } + img->width = image->ti.width; img->height = image->ti.height; img->pixels = image->ti.pixels; @@ -301,7 +378,7 @@ bool task_image_load_handler(retro_task_t *task) } bool task_push_image_load(const char *fullpath, - bool supports_rgba, + bool supports_rgba, unsigned upscale_threshold, retro_task_callback_t cb, void *user_data) { nbio_handle_t *nbio = NULL; @@ -350,6 +427,7 @@ bool task_push_image_load(const char *fullpath, image->processing_final_state = 0; image->frame_duration = 0; image->size = 0; + image->upscale_threshold = upscale_threshold; image->handle = NULL; image->ti.width = 0; diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index e68d7fe219..4a1cd58fde 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -74,7 +74,7 @@ bool task_push_pl_entry_thumbnail_download( #endif bool task_push_image_load(const char *fullpath, - bool supports_rgba, + bool supports_rgba, unsigned upscale_threshold, retro_task_callback_t cb, void *userdata); #ifdef HAVE_LIBRETRODB