From a446f8ad515877d4e10becdf4dd4e248c15db852 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Fri, 12 Apr 2019 15:50:27 +0100 Subject: [PATCH] (RGUI) Add optional delay when loading thumbnails --- config.def.h | 1 + configuration.c | 1 + configuration.h | 1 + intl/msg_hash_lbl.h | 2 + intl/msg_hash_us.h | 8 + menu/cbs/menu_cbs_sublabel.c | 4 + menu/drivers/rgui.c | 283 ++++++++++++++++++++--------------- menu/menu_displaylist.c | 4 + menu/menu_setting.c | 13 ++ msg_hash.h | 1 + 10 files changed, 201 insertions(+), 117 deletions(-) diff --git a/config.def.h b/config.def.h index 3b779d0b4d..9c41045d8b 100644 --- a/config.def.h +++ b/config.def.h @@ -387,6 +387,7 @@ static unsigned rgui_color_theme = RGUI_THEME_CLASSIC_GREEN; static bool rgui_inline_thumbnails = false; static bool rgui_swap_thumbnails = false; static unsigned rgui_thumbnail_downscaler = RGUI_THUMB_SCALE_POINT; +static unsigned rgui_thumbnail_delay = 0; static unsigned rgui_internal_upscale_level = RGUI_UPSCALE_NONE; static bool rgui_full_width_layout = true; static unsigned rgui_aspect = RGUI_ASPECT_RATIO_4_3; diff --git a/configuration.c b/configuration.c index d4bdb2f3ba..fa2043859d 100644 --- a/configuration.c +++ b/configuration.c @@ -1699,6 +1699,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, #ifdef HAVE_RGUI 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); + SETTING_UINT("rgui_thumbnail_delay", &settings->uints.menu_rgui_thumbnail_delay, true, rgui_thumbnail_delay, false); SETTING_UINT("rgui_internal_upscale_level", &settings->uints.menu_rgui_internal_upscale_level, true, rgui_internal_upscale_level, false); SETTING_UINT("rgui_aspect_ratio", &settings->uints.menu_rgui_aspect_ratio, true, rgui_aspect, false); SETTING_UINT("rgui_aspect_ratio_lock", &settings->uints.menu_rgui_aspect_ratio_lock, true, rgui_aspect_lock, false); diff --git a/configuration.h b/configuration.h index 25852cac04..291f4c879a 100644 --- a/configuration.h +++ b/configuration.h @@ -435,6 +435,7 @@ typedef struct settings unsigned menu_thumbnails; unsigned menu_left_thumbnails; unsigned menu_rgui_thumbnail_downscaler; + unsigned menu_rgui_thumbnail_delay; unsigned menu_dpi_override_value; unsigned menu_rgui_color_theme; unsigned menu_xmb_layout; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 9955b7a197..f03d5d9131 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1131,6 +1131,8 @@ 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_MENU_RGUI_THUMBNAIL_DELAY, + "rgui_thumbnail_delay") MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_INLINE_THUMBNAILS, "rgui_inline_thumbnails") MSG_HASH(MENU_ENUM_LABEL_MENU_RGUI_SWAP_THUMBNAILS, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 07b0f84885..15e1e7295d 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3002,6 +3002,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_SWAP_THUMBNAILS, "Swaps the display positions of 'Top Thumbnail' and 'Bottom Thumbnail'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DELAY, + "Thumbnail Delay (ms)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_THUMBNAIL_DELAY, + "Applies a time delay between selecting a playlist entry and loading its associated thumbnails. Setting this to a value of at least 256 ms enables fast lag-free scrolling on even the slowest devices." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DOWNSCALER, "Thumbnail Downscaling Method" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index f79dadc8d0..fb69ad4c2b 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -532,6 +532,7 @@ default_sublabel_macro(action_bind_sublabel_menu_rgui_shadows, default_sublabel_macro(action_bind_sublabel_menu_rgui_inline_thumbnails, MENU_ENUM_SUBLABEL_MENU_RGUI_INLINE_THUMBNAILS) default_sublabel_macro(action_bind_sublabel_menu_rgui_swap_thumbnails, MENU_ENUM_SUBLABEL_MENU_RGUI_SWAP_THUMBNAILS) default_sublabel_macro(action_bind_sublabel_menu_rgui_thumbnail_downscaler, MENU_ENUM_SUBLABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER) +default_sublabel_macro(action_bind_sublabel_menu_rgui_thumbnail_delay, MENU_ENUM_SUBLABEL_MENU_RGUI_THUMBNAIL_DELAY) default_sublabel_macro(action_bind_sublabel_content_runtime_log, MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG) default_sublabel_macro(action_bind_sublabel_content_runtime_log_aggregate, MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG_AGGREGATE) default_sublabel_macro(action_bind_sublabel_playlist_sublabel_runtime_type, MENU_ENUM_SUBLABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE) @@ -2438,6 +2439,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_rgui_thumbnail_downscaler); break; + case MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_rgui_thumbnail_delay); + break; case MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_runtime_log); break; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 23ac36b82b..03e9a6f334 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -58,6 +58,7 @@ #include #include "../../tasks/tasks_internal.h" #include +#include #if defined(GEKKO) #define RGUI_TERM_START_X(fb_width) (fb_width / 21) @@ -494,6 +495,8 @@ typedef struct menu_thumbnail_path_data_t *thumbnail_path_data; uint32_t thumbnail_queue_size; uint32_t left_thumbnail_queue_size; + bool thumbnail_load_pending; + retro_time_t thumbnail_load_trigger_time; bool show_wallpaper; char theme_preset_path[PATH_MAX_LENGTH]; /* Must be a fixed length array... */ char menu_title[255]; /* Must be a fixed length array... */ @@ -2727,6 +2730,8 @@ static void *rgui_init(void **userdata, bool video_is_threaded) rgui->thumbnail_queue_size = 0; rgui->left_thumbnail_queue_size = 0; + rgui->thumbnail_load_pending = false; + rgui->thumbnail_load_trigger_time = 0; /* Ensure that we start with fullscreen thumbnails disabled */ rgui->show_fs_thumbnail = false; @@ -2766,89 +2771,6 @@ static void rgui_free(void *data) } } -static void rgui_frame(void *data, video_frame_info_t *video_info) -{ - rgui_t *rgui = (rgui_t*)data; - settings_t *settings = config_get_ptr(); - - if (settings->bools.menu_rgui_background_filler_thickness_enable != rgui->bg_thickness) - { - rgui->bg_thickness = settings->bools.menu_rgui_background_filler_thickness_enable; - rgui->bg_modified = true; - rgui->force_redraw = true; - } - - if (settings->bools.menu_rgui_border_filler_thickness_enable != rgui->border_thickness) - { - rgui->border_thickness = settings->bools.menu_rgui_border_filler_thickness_enable; - rgui->bg_modified = true; - rgui->force_redraw = true; - } - - if (settings->bools.menu_rgui_border_filler_enable != rgui->border_enable) - { - rgui->border_enable = settings->bools.menu_rgui_border_filler_enable; - rgui->bg_modified = true; - rgui->force_redraw = true; - } - - if (settings->bools.menu_rgui_shadows != rgui->shadow_enable) - { - rgui_set_blit_line_function( - settings->bools.menu_rgui_shadows, settings->bools.menu_rgui_extended_ascii); - - rgui->shadow_enable = settings->bools.menu_rgui_shadows; - rgui->bg_modified = true; - rgui->force_redraw = true; - } - - if (settings->bools.menu_rgui_extended_ascii != rgui->extended_ascii_enable) - { - rgui_set_blit_line_function( - settings->bools.menu_rgui_shadows, settings->bools.menu_rgui_extended_ascii); - - rgui->extended_ascii_enable = settings->bools.menu_rgui_extended_ascii; - rgui->force_redraw = true; - } - - if (settings->uints.menu_rgui_color_theme != rgui->color_theme) - { - prepare_rgui_colors(rgui, settings); - } - else if (settings->uints.menu_rgui_color_theme == RGUI_THEME_CUSTOM) - { - if (string_is_not_equal_fast(settings->paths.path_rgui_theme_preset, rgui->theme_preset_path, sizeof(rgui->theme_preset_path))) - { - prepare_rgui_colors(rgui, settings); - } - } - - /* Note: both rgui_set_aspect_ratio() and rgui_set_video_config() - * normally call command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL) - * ## THIS CANNOT BE DONE INSIDE rgui_frame() IF THREADED VIDEO IS ENABLED ## - * Attempting to do so creates a deadlock, and causes RetroArch to hang. - * We therefore have to set the 'delay_update' argument, which causes - * command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL) to be called at - * the next instance of rgui_render() */ - if (settings->uints.menu_rgui_aspect_ratio != rgui->menu_aspect_ratio) - rgui_set_aspect_ratio(rgui, true); - - if (settings->uints.menu_rgui_aspect_ratio_lock != rgui->menu_aspect_ratio_lock) - { - rgui->menu_aspect_ratio_lock = settings->uints.menu_rgui_aspect_ratio_lock; - - if (settings->uints.menu_rgui_aspect_ratio_lock == RGUI_ASPECT_RATIO_LOCK_NONE) - { - rgui_set_video_config(rgui, &rgui->content_video_settings, true); - } - else - { - rgui_update_menu_viewport(rgui); - rgui_set_video_config(rgui, &rgui->menu_video_settings, true); - } - } -} - static void rgui_set_texture(void) { size_t fb_pitch; @@ -2969,54 +2891,79 @@ static void rgui_set_thumbnail_system(void *userdata, char *s, size_t len) menu_thumbnail_set_system(rgui->thumbnail_path_data, s); } -static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui) +static void rgui_load_current_thumbnails(rgui_t *rgui) { + const char *thumbnail_path = NULL; + const char *left_thumbnail_path = NULL; + + /* Right (or fullscreen) thumbnail */ + if (menu_thumbnail_get_path(rgui->thumbnail_path_data, + MENU_THUMBNAIL_RIGHT, &thumbnail_path)) + { + rgui->entry_has_thumbnail = request_thumbnail( + rgui->show_fs_thumbnail ? &fs_thumbnail : &mini_thumbnail, + MENU_THUMBNAIL_RIGHT, &rgui->thumbnail_queue_size, thumbnail_path); + } + + /* Left thumbnail + * (Note: there is no need to load this when viewing + * fullscreen thumbnails) */ + if (!rgui->show_fs_thumbnail) + { + if (menu_thumbnail_get_path(rgui->thumbnail_path_data, + MENU_THUMBNAIL_LEFT, &left_thumbnail_path)) + { + rgui->entry_has_left_thumbnail = request_thumbnail( + &mini_left_thumbnail, MENU_THUMBNAIL_LEFT, &rgui->left_thumbnail_queue_size, left_thumbnail_path); + } + } + + /* Reset 'load pending' state */ + rgui->thumbnail_load_pending = false; + + /* Force a redraw (so 'entry_has_thumbnail' values are + * applied immediately) */ + rgui->force_redraw = true; +} + +static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load) +{ + bool has_thumbnail = false; settings_t *settings = config_get_ptr(); if (!settings) return; - rgui->entry_has_thumbnail = false; + rgui->entry_has_thumbnail = false; rgui->entry_has_left_thumbnail = false; + rgui->thumbnail_load_pending = false; + /* Update thumbnail content/path */ if ((rgui->show_fs_thumbnail || settings->bools.menu_rgui_inline_thumbnails) && rgui->is_playlist) { if (menu_thumbnail_set_content_playlist(rgui->thumbnail_path_data, playlist_get_cached(), menu_navigation_get_selection())) { if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT)) - { - if (menu_thumbnail_update_path(rgui->thumbnail_path_data, MENU_THUMBNAIL_RIGHT)) - { - const char *thumbnail_path = NULL; - - if (menu_thumbnail_get_path(rgui->thumbnail_path_data, - MENU_THUMBNAIL_RIGHT, &thumbnail_path)) - { - if (rgui->show_fs_thumbnail) - rgui->entry_has_thumbnail = request_thumbnail( - &fs_thumbnail, MENU_THUMBNAIL_RIGHT, &rgui->thumbnail_queue_size, thumbnail_path); - else - rgui->entry_has_thumbnail = request_thumbnail( - &mini_thumbnail, MENU_THUMBNAIL_RIGHT, &rgui->thumbnail_queue_size, thumbnail_path); - } - } - } + has_thumbnail = menu_thumbnail_update_path(rgui->thumbnail_path_data, MENU_THUMBNAIL_RIGHT); if (settings->bools.menu_rgui_inline_thumbnails && menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT)) - { - if (menu_thumbnail_update_path(rgui->thumbnail_path_data, MENU_THUMBNAIL_LEFT)) - { - const char *left_thumbnail_path = NULL; - - if (menu_thumbnail_get_path(rgui->thumbnail_path_data, - MENU_THUMBNAIL_LEFT, &left_thumbnail_path)) - { - rgui->entry_has_left_thumbnail = request_thumbnail( - &mini_left_thumbnail, MENU_THUMBNAIL_LEFT, &rgui->left_thumbnail_queue_size, left_thumbnail_path); - } - } - } + has_thumbnail = menu_thumbnail_update_path(rgui->thumbnail_path_data, MENU_THUMBNAIL_LEFT) || + has_thumbnail; + } + } + + /* Check whether thumbnails should be loaded */ + if (has_thumbnail) + { + /* Check whether thumbnails should be loaded immediately */ + if ((settings->uints.menu_rgui_thumbnail_delay == 0) || force_load) + rgui_load_current_thumbnails(rgui); + else + { + /* Schedule a delayed load */ + rgui->thumbnail_load_pending = true; + rgui->thumbnail_load_trigger_time = cpu_features_get_time_usec(); } } } @@ -3055,7 +3002,11 @@ static void rgui_update_thumbnail_image(void *userdata) } } - rgui_scan_selected_entry_thumbnail(rgui); + /* Note that we always load thumbnails immediately + * when toggling via the 'scan' button (scheduling a + * delayed load here would make for a poor user + * experience...) */ + rgui_scan_selected_entry_thumbnail(rgui, true); } static void rgui_update_menu_sublabel(rgui_t *rgui) @@ -3116,7 +3067,7 @@ static void rgui_navigation_set(void *data, bool scroll) if (!rgui) return; - rgui_scan_selected_entry_thumbnail(rgui); + rgui_scan_selected_entry_thumbnail(rgui, false); rgui_update_menu_sublabel(rgui); if (!scroll) @@ -3179,6 +3130,9 @@ static void rgui_populate_entries(void *data, /* Set menu title */ menu_entries_get_title(rgui->menu_title, sizeof(rgui->menu_title)); + /* Cancel any pending thumbnail load operations */ + rgui->thumbnail_load_pending = false; + rgui_navigation_set(data, true); /* If aspect ratio lock is enabled, must restore @@ -3251,6 +3205,101 @@ static int rgui_pointer_tap(void *data, return 0; } +static void rgui_frame(void *data, video_frame_info_t *video_info) +{ + rgui_t *rgui = (rgui_t*)data; + settings_t *settings = config_get_ptr(); + + if (settings->bools.menu_rgui_background_filler_thickness_enable != rgui->bg_thickness) + { + rgui->bg_thickness = settings->bools.menu_rgui_background_filler_thickness_enable; + rgui->bg_modified = true; + rgui->force_redraw = true; + } + + if (settings->bools.menu_rgui_border_filler_thickness_enable != rgui->border_thickness) + { + rgui->border_thickness = settings->bools.menu_rgui_border_filler_thickness_enable; + rgui->bg_modified = true; + rgui->force_redraw = true; + } + + if (settings->bools.menu_rgui_border_filler_enable != rgui->border_enable) + { + rgui->border_enable = settings->bools.menu_rgui_border_filler_enable; + rgui->bg_modified = true; + rgui->force_redraw = true; + } + + if (settings->bools.menu_rgui_shadows != rgui->shadow_enable) + { + rgui_set_blit_line_function( + settings->bools.menu_rgui_shadows, settings->bools.menu_rgui_extended_ascii); + + rgui->shadow_enable = settings->bools.menu_rgui_shadows; + rgui->bg_modified = true; + rgui->force_redraw = true; + } + + if (settings->bools.menu_rgui_extended_ascii != rgui->extended_ascii_enable) + { + rgui_set_blit_line_function( + settings->bools.menu_rgui_shadows, settings->bools.menu_rgui_extended_ascii); + + rgui->extended_ascii_enable = settings->bools.menu_rgui_extended_ascii; + rgui->force_redraw = true; + } + + if (settings->uints.menu_rgui_color_theme != rgui->color_theme) + { + prepare_rgui_colors(rgui, settings); + } + else if (settings->uints.menu_rgui_color_theme == RGUI_THEME_CUSTOM) + { + if (string_is_not_equal_fast(settings->paths.path_rgui_theme_preset, rgui->theme_preset_path, sizeof(rgui->theme_preset_path))) + { + prepare_rgui_colors(rgui, settings); + } + } + + /* Note: both rgui_set_aspect_ratio() and rgui_set_video_config() + * normally call command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL) + * ## THIS CANNOT BE DONE INSIDE rgui_frame() IF THREADED VIDEO IS ENABLED ## + * Attempting to do so creates a deadlock, and causes RetroArch to hang. + * We therefore have to set the 'delay_update' argument, which causes + * command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL) to be called at + * the next instance of rgui_render() */ + if (settings->uints.menu_rgui_aspect_ratio != rgui->menu_aspect_ratio) + rgui_set_aspect_ratio(rgui, true); + + if (settings->uints.menu_rgui_aspect_ratio_lock != rgui->menu_aspect_ratio_lock) + { + rgui->menu_aspect_ratio_lock = settings->uints.menu_rgui_aspect_ratio_lock; + + if (settings->uints.menu_rgui_aspect_ratio_lock == RGUI_ASPECT_RATIO_LOCK_NONE) + { + rgui_set_video_config(rgui, &rgui->content_video_settings, true); + } + else + { + rgui_update_menu_viewport(rgui); + rgui_set_video_config(rgui, &rgui->menu_video_settings, true); + } + } + + /* Handle pending thumbnail load operations */ + if (rgui->thumbnail_load_pending) + { + /* Check whether current 'load delay' duration has elapsed + * Note: Delay is increased when viewing fullscreen thumbnails, + * since the flicker when switching between playlist view and + * fullscreen thumbnail view is incredibly jarring...) */ + if ((cpu_features_get_time_usec() - rgui->thumbnail_load_trigger_time) >= + (settings->uints.menu_rgui_thumbnail_delay * 1000 * (rgui->show_fs_thumbnail ? 1.5f : 1.0f))) + rgui_load_current_thumbnails(rgui); + } +} + static void rgui_toggle(void *userdata, bool menu_on) { rgui_t *rgui = (rgui_t*)userdata; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index be5ca2b0dd..b621326a67 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -6238,6 +6238,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, PARSE_ONLY_UINT, false) == 0) count++; + if (menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY, + PARSE_ONLY_UINT, false) == 0) + count++; if (menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_TICKER_TYPE, PARSE_ONLY_UINT, false) == 0) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 4971b40221..f4c1fc7c8b 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -9497,6 +9497,19 @@ static bool setting_append_list( (*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); + + CONFIG_UINT( + list, list_info, + &settings->uints.menu_rgui_thumbnail_delay, + MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY, + MENU_ENUM_LABEL_VALUE_MENU_RGUI_THUMBNAIL_DELAY, + rgui_thumbnail_delay, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_range(list, list_info, 0.0f, 1024.0f, 64.0f, true, true); } CONFIG_BOOL( diff --git a/msg_hash.h b/msg_hash.h index 55b0d68a1b..2b54064111 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -912,6 +912,7 @@ enum msg_hash_enums MENU_LABEL(MENU_RGUI_INLINE_THUMBNAILS), MENU_LABEL(MENU_RGUI_SWAP_THUMBNAILS), MENU_LABEL(MENU_RGUI_THUMBNAIL_DOWNSCALER), + MENU_LABEL(MENU_RGUI_THUMBNAIL_DELAY), MENU_LABEL(TIMEDATE_ENABLE), MENU_LABEL(TIMEDATE_STYLE), MENU_LABEL(BATTERY_LEVEL_ENABLE),