From f2dca12a22295978e9ba5a86521e9b7c2efe738d Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Thu, 19 May 2022 16:40:21 +0100 Subject: [PATCH] (Ozone/XMB) Prevent unnecessary thumbnail requests when scrolling through playlists --- gfx/gfx_thumbnail.c | 197 ++++++++++++++++++++++++++++++++++++++----- gfx/gfx_thumbnail.h | 72 ++++++++++++++-- menu/drivers/ozone.c | 141 +++++++++++++++++++++++-------- menu/drivers/xmb.c | 129 ++++++++++++++++++---------- 4 files changed, 433 insertions(+), 106 deletions(-) diff --git a/gfx/gfx_thumbnail.c b/gfx/gfx_thumbnail.c index a09ebe61fd..986fedb193 100644 --- a/gfx/gfx_thumbnail.c +++ b/gfx/gfx_thumbnail.c @@ -247,19 +247,15 @@ void gfx_thumbnail_request( gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id, playlist_t *playlist, size_t idx, gfx_thumbnail_t *thumbnail, unsigned gfx_thumbnail_upscale_threshold, - bool network_on_demand_thumbnails - ) + bool network_on_demand_thumbnails) { const char *thumbnail_path = NULL; bool has_thumbnail = false; - gfx_thumbnail_state_t *p_gfx_thumb = NULL; - p_gfx_thumb = NULL; + gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; if (!path_data || !thumbnail) return; - p_gfx_thumb = &gfx_thumb_st; - /* Reset thumbnail, then set 'missing' status by default * (saves a number of checks later) */ gfx_thumbnail_reset(thumbnail); @@ -354,8 +350,7 @@ end: * once the image load is complete */ void gfx_thumbnail_request_file( const char *file_path, gfx_thumbnail_t *thumbnail, - unsigned gfx_thumbnail_upscale_threshold - ) + unsigned gfx_thumbnail_upscale_threshold) { gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; gfx_thumbnail_tag_t *thumbnail_tag = NULL; @@ -424,6 +419,174 @@ void gfx_thumbnail_reset(gfx_thumbnail_t *thumbnail) /* Stream processing */ +/* Requests loading of the specified thumbnail via + * the stream interface + * - Must be called on each frame for the duration + * that specified thumbnail is on-screen + * - Actual load request is deferred by currently + * set stream delay + * - Function becomes a no-op once load request is + * made + * - Thumbnails loaded via this function must be + * deleted manually via gfx_thumbnail_reset() + * when they move off-screen + * NOTE 1: Must be called *after* gfx_thumbnail_set_system() + * and gfx_thumbnail_set_content*() + * NOTE 2: 'playlist' and 'idx' are only required here for + * on-demand thumbnail download support + * (an annoyance...) + * NOTE 3: This function is intended for use in situations + * where each menu entry has a *single* thumbnail. + * If each entry has two thumbnails, use + * gfx_thumbnail_request_streams() for improved + * performance */ +void gfx_thumbnail_request_stream( + gfx_thumbnail_path_data_t *path_data, + gfx_animation_t *p_anim, + enum gfx_thumbnail_id thumbnail_id, + playlist_t *playlist, size_t idx, + gfx_thumbnail_t *thumbnail, + unsigned gfx_thumbnail_upscale_threshold, + bool network_on_demand_thumbnails) +{ + gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; + + /* Only process request if current status + * is GFX_THUMBNAIL_STATUS_UNKNOWN */ + if (!thumbnail || + (thumbnail->status != GFX_THUMBNAIL_STATUS_UNKNOWN)) + return; + + /* Check if stream delay timer has elapsed */ + thumbnail->delay_timer += p_anim->delta_time; + + if (thumbnail->delay_timer > p_gfx_thumb->stream_delay) + { + /* Sanity check */ + if (!path_data) + { + /* No path information + * > Reset thumbnail and set missing status + * to prevent repeated load attempts */ + gfx_thumbnail_reset(thumbnail); + thumbnail->status = GFX_THUMBNAIL_STATUS_MISSING; + thumbnail->alpha = 1.0f; + return; + } + + /* Request image load */ + gfx_thumbnail_request( + path_data, thumbnail_id, playlist, idx, thumbnail, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + } +} + +/* Requests loading of the specified thumbnails via + * the stream interface + * - Must be called on each frame for the duration + * that specified thumbnails are on-screen + * - Actual load request is deferred by currently + * set stream delay + * - Function becomes a no-op once load request is + * made + * - Thumbnails loaded via this function must be + * deleted manually via gfx_thumbnail_reset() + * when they move off-screen + * NOTE 1: Must be called *after* gfx_thumbnail_set_system() + * and gfx_thumbnail_set_content*() + * NOTE 2: 'playlist' and 'idx' are only required here for + * on-demand thumbnail download support + * (an annoyance...) + * NOTE 3: This function is intended for use in situations + * where each menu entry has *two* thumbnails. + * If each entry only has a single thumbnail, use + * gfx_thumbnail_request_stream() for improved + * performance */ +void gfx_thumbnail_request_streams( + gfx_thumbnail_path_data_t *path_data, + gfx_animation_t *p_anim, + playlist_t *playlist, size_t idx, + gfx_thumbnail_t *right_thumbnail, + gfx_thumbnail_t *left_thumbnail, + unsigned gfx_thumbnail_upscale_threshold, + bool network_on_demand_thumbnails) +{ + bool process_right = false; + bool process_left = false; + + if (!right_thumbnail || !left_thumbnail) + return; + + /* Only process request if current status + * is GFX_THUMBNAIL_STATUS_UNKNOWN */ + process_right = (right_thumbnail->status == GFX_THUMBNAIL_STATUS_UNKNOWN); + process_left = (left_thumbnail->status == GFX_THUMBNAIL_STATUS_UNKNOWN); + + if (process_right || process_left) + { + /* Check if stream delay timer has elapsed */ + gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; + float delta_time = p_anim->delta_time; + bool request_right = false; + bool request_left = false; + + if (process_right) + { + right_thumbnail->delay_timer += delta_time; + request_right = + (right_thumbnail->delay_timer > p_gfx_thumb->stream_delay); + } + + if (process_left) + { + left_thumbnail->delay_timer += delta_time; + request_left = + (left_thumbnail->delay_timer > p_gfx_thumb->stream_delay); + } + + /* Check if one or more thumbnails should be requested */ + if (request_right || request_left) + { + /* Sanity check */ + if (!path_data) + { + /* No path information + * > Reset thumbnail and set missing status + * to prevent repeated load attempts */ + if (request_right) + { + gfx_thumbnail_reset(right_thumbnail); + right_thumbnail->status = GFX_THUMBNAIL_STATUS_MISSING; + right_thumbnail->alpha = 1.0f; + } + + if (request_left) + { + gfx_thumbnail_reset(left_thumbnail); + left_thumbnail->status = GFX_THUMBNAIL_STATUS_MISSING; + left_thumbnail->alpha = 1.0f; + } + + return; + } + + /* Request image load */ + if (request_right) + gfx_thumbnail_request( + path_data, GFX_THUMBNAIL_RIGHT, playlist, idx, right_thumbnail, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + + if (request_left) + gfx_thumbnail_request( + path_data, GFX_THUMBNAIL_LEFT, playlist, idx, left_thumbnail, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + } + } +} + /* Handles streaming of the specified thumbnail as it moves * on/off screen * - Must be called each frame for every on-screen entry @@ -440,13 +603,11 @@ void gfx_thumbnail_process_stream( gfx_thumbnail_path_data_t *path_data, gfx_animation_t *p_anim, enum gfx_thumbnail_id thumbnail_id, - playlist_t *playlist, - size_t idx, + playlist_t *playlist, size_t idx, gfx_thumbnail_t *thumbnail, bool on_screen, unsigned gfx_thumbnail_upscale_threshold, - bool network_on_demand_thumbnails - ) + bool network_on_demand_thumbnails) { if (!thumbnail) return; @@ -458,10 +619,10 @@ void gfx_thumbnail_process_stream( * GFX_THUMBNAIL_STATUS_UNKNOWN */ if (thumbnail->status == GFX_THUMBNAIL_STATUS_UNKNOWN) { - gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; + gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; /* Check if stream delay timer has elapsed */ - thumbnail->delay_timer += p_anim->delta_time; + thumbnail->delay_timer += p_anim->delta_time; if (thumbnail->delay_timer > p_gfx_thumb->stream_delay) { @@ -482,8 +643,7 @@ void gfx_thumbnail_process_stream( gfx_thumbnail_request( path_data, thumbnail_id, playlist, idx, thumbnail, gfx_thumbnail_upscale_threshold, - network_on_demand_thumbnails - ); + network_on_demand_thumbnails); } } } @@ -521,8 +681,7 @@ void gfx_thumbnail_process_streams( gfx_thumbnail_t *left_thumbnail, bool on_screen, unsigned gfx_thumbnail_upscale_threshold, - bool network_on_demand_thumbnails - ) + bool network_on_demand_thumbnails) { if (!right_thumbnail || !left_thumbnail) return; @@ -538,7 +697,7 @@ void gfx_thumbnail_process_streams( if (process_right || process_left) { /* Check if stream delay timer has elapsed */ - gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; + gfx_thumbnail_state_t *p_gfx_thumb = &gfx_thumb_st; float delta_time = p_anim->delta_time; bool request_right = false; bool request_left = false; diff --git a/gfx/gfx_thumbnail.h b/gfx/gfx_thumbnail.h index 66773997eb..158eacd188 100644 --- a/gfx/gfx_thumbnail.h +++ b/gfx/gfx_thumbnail.h @@ -171,8 +171,7 @@ void gfx_thumbnail_request( gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id, playlist_t *playlist, size_t idx, gfx_thumbnail_t *thumbnail, unsigned gfx_thumbnail_upscale_threshold, - bool network_on_demand_thumbnails - ); + bool network_on_demand_thumbnails); /* Requests loading of a specific thumbnail image file * (may be used, for example, to load savestate images) @@ -192,6 +191,66 @@ void gfx_thumbnail_reset(gfx_thumbnail_t *thumbnail); /* Stream processing */ +/* Requests loading of the specified thumbnail via + * the stream interface + * - Must be called on each frame for the duration + * that specified thumbnail is on-screen + * - Actual load request is deferred by currently + * set stream delay + * - Function becomes a no-op once load request is + * made + * - Thumbnails loaded via this function must be + * deleted manually via gfx_thumbnail_reset() + * when they move off-screen + * NOTE 1: Must be called *after* gfx_thumbnail_set_system() + * and gfx_thumbnail_set_content*() + * NOTE 2: 'playlist' and 'idx' are only required here for + * on-demand thumbnail download support + * (an annoyance...) + * NOTE 3: This function is intended for use in situations + * where each menu entry has a *single* thumbnail. + * If each entry has two thumbnails, use + * gfx_thumbnail_request_streams() for improved + * performance */ +void gfx_thumbnail_request_stream( + gfx_thumbnail_path_data_t *path_data, + gfx_animation_t *p_anim, + enum gfx_thumbnail_id thumbnail_id, + playlist_t *playlist, size_t idx, + gfx_thumbnail_t *thumbnail, + unsigned gfx_thumbnail_upscale_threshold, + bool network_on_demand_thumbnails); + +/* Requests loading of the specified thumbnails via + * the stream interface + * - Must be called on each frame for the duration + * that specified thumbnails are on-screen + * - Actual load request is deferred by currently + * set stream delay + * - Function becomes a no-op once load request is + * made + * - Thumbnails loaded via this function must be + * deleted manually via gfx_thumbnail_reset() + * when they move off-screen + * NOTE 1: Must be called *after* gfx_thumbnail_set_system() + * and gfx_thumbnail_set_content*() + * NOTE 2: 'playlist' and 'idx' are only required here for + * on-demand thumbnail download support + * (an annoyance...) + * NOTE 3: This function is intended for use in situations + * where each menu entry has *two* thumbnails. + * If each entry only has a single thumbnail, use + * gfx_thumbnail_request_stream() for improved + * performance */ +void gfx_thumbnail_request_streams( + gfx_thumbnail_path_data_t *path_data, + gfx_animation_t *p_anim, + playlist_t *playlist, size_t idx, + gfx_thumbnail_t *right_thumbnail, + gfx_thumbnail_t *left_thumbnail, + unsigned gfx_thumbnail_upscale_threshold, + bool network_on_demand_thumbnails); + /* Handles streaming of the specified thumbnail as it moves * on/off screen * - Must be called each frame for every on-screen entry @@ -208,13 +267,11 @@ void gfx_thumbnail_process_stream( gfx_thumbnail_path_data_t *path_data, gfx_animation_t *p_anim, enum gfx_thumbnail_id thumbnail_id, - playlist_t *playlist, - size_t idx, + playlist_t *playlist, size_t idx, gfx_thumbnail_t *thumbnail, bool on_screen, unsigned gfx_thumbnail_upscale_threshold, - bool network_on_demand_thumbnails - ); + bool network_on_demand_thumbnails); /* Handles streaming of the specified thumbnails as they move * on/off screen @@ -236,8 +293,7 @@ void gfx_thumbnail_process_streams( gfx_thumbnail_t *left_thumbnail, bool on_screen, unsigned gfx_thumbnail_upscale_threshold, - bool network_on_demand_thumbnails - ); + bool network_on_demand_thumbnails); /* Thumbnail rendering */ diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index eafc4a13ab..93133d79d5 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -63,6 +63,8 @@ #define ANIMATION_CURSOR_DURATION 133 #define ANIMATION_CURSOR_PULSE 500 +#define OZONE_THUMBNAIL_STREAM_DELAY 166.66667f + #define FONT_SIZE_FOOTER 18 #define FONT_SIZE_TITLE 36 #define FONT_SIZE_TIME 22 @@ -317,6 +319,14 @@ enum OZONE_ENTRIES_ICONS_TEXTURE_LAST }; +enum ozone_pending_thumbnail_type +{ + OZONE_PENDING_THUMBNAIL_NONE = 0, + OZONE_PENDING_THUMBNAIL_RIGHT, + OZONE_PENDING_THUMBNAIL_LEFT, + OZONE_PENDING_THUMBNAIL_BOTH +}; + /* This structure holds all objects + metadata * corresponding to a particular font */ typedef struct @@ -432,6 +442,8 @@ struct ozone_handle { gfx_thumbnail_t right; /* uintptr_t alignment */ gfx_thumbnail_t left; /* uintptr_t alignment */ + float stream_delay; + enum ozone_pending_thumbnail_type pending; } thumbnails; uintptr_t textures[OZONE_THEME_TEXTURE_LAST]; uintptr_t icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LAST]; @@ -3378,6 +3390,11 @@ static void ozone_entries_update_thumbnail_bar( } ozone->pending_hide_thumbnail_bar = false; + + /* Want thumbnails to load instantly when thumbnail + * sidebar first opens */ + ozone->thumbnails.stream_delay = 0.0f; + gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); } /* Hide it */ else @@ -3989,6 +4006,11 @@ static void ozone_refresh_sidebars( { ozone->animations.thumbnail_bar_position = ozone->dimensions.thumbnail_bar_width; ozone->show_thumbnail_bar = true; + + /* Want thumbnails to load instantly when thumbnail + * sidebar first opens */ + ozone->thumbnails.stream_delay = 0.0f; + gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); } else { @@ -6818,6 +6840,17 @@ static enum menu_action ozone_parse_menu_entry_action( size_t selection; size_t selection_total; + /* We have to override the thumbnail stream + * delay when opening the thumbnail sidebar; + * ensure that the proper value is restored + * whenever the user performs regular navigation */ + if ((action != MENU_ACTION_NOOP) && + (ozone->thumbnails.stream_delay != OZONE_THUMBNAIL_STREAM_DELAY)) + { + ozone->thumbnails.stream_delay = OZONE_THUMBNAIL_STREAM_DELAY; + gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); + } + /* If fullscreen thumbnail view is active, any * valid menu action will disable it... */ if (ozone->show_fullscreen_thumbnails) @@ -7225,7 +7258,9 @@ static void *ozone_init(void **userdata, bool video_is_threaded) ozone->animations.left_thumbnail_alpha = 1.0f; ozone->force_metadata_display = false; - gfx_thumbnail_set_stream_delay(-1.0f); + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; + ozone->thumbnails.stream_delay = OZONE_THUMBNAIL_STREAM_DELAY; + gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); gfx_thumbnail_set_fade_duration(-1.0f); gfx_thumbnail_set_fade_missing(false); @@ -7407,47 +7442,29 @@ static void ozone_free(void *data) static void ozone_update_thumbnail_image(void *data) { - ozone_handle_t *ozone = (ozone_handle_t*)data; - size_t selection = menu_navigation_get_selection(); - settings_t *settings = config_get_ptr(); - playlist_t *playlist = playlist_get_cached(); - unsigned gfx_thumbnail_upscale_threshold = settings->uints.gfx_thumbnail_upscale_threshold; - bool network_on_demand_thumbnails = settings->bools.network_on_demand_thumbnails; + ozone_handle_t *ozone = (ozone_handle_t*)data; if (!ozone) return; + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; gfx_thumbnail_cancel_pending_requests(); + gfx_thumbnail_reset(&ozone->thumbnails.right); + gfx_thumbnail_reset(&ozone->thumbnails.left); - gfx_thumbnail_request( - ozone->thumbnail_path_data, - GFX_THUMBNAIL_RIGHT, - playlist, - selection, - &ozone->thumbnails.right, - gfx_thumbnail_upscale_threshold, - network_on_demand_thumbnails - ); + /* Right thumbnail */ + if (gfx_thumbnail_is_enabled(ozone->thumbnail_path_data, + GFX_THUMBNAIL_RIGHT)) + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_RIGHT; - /* Image (and video/music) content requires special - * treatment... */ - if (ozone->selection_core_is_viewer) - { - /* Left thumbnail is simply reset */ - gfx_thumbnail_reset(&ozone->thumbnails.left); - } - else - { - /* Left thumbnail */ - gfx_thumbnail_request( - ozone->thumbnail_path_data, - GFX_THUMBNAIL_LEFT, - playlist, - selection, - &ozone->thumbnails.left, - gfx_thumbnail_upscale_threshold, - network_on_demand_thumbnails); - } + /* Left thumbnail + * > Disabled for image (and video/music) content */ + if (!ozone->selection_core_is_viewer && + gfx_thumbnail_is_enabled(ozone->thumbnail_path_data, + GFX_THUMBNAIL_LEFT)) + ozone->thumbnails.pending = + (ozone->thumbnails.pending == OZONE_PENDING_THUMBNAIL_RIGHT) ? + OZONE_PENDING_THUMBNAIL_BOTH : OZONE_PENDING_THUMBNAIL_LEFT; } static void ozone_refresh_thumbnail_image(void *data, unsigned i) @@ -7847,6 +7864,7 @@ static void ozone_unload_thumbnail_textures(void *data) if (!ozone) return; + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; gfx_thumbnail_cancel_pending_requests(); gfx_thumbnail_reset(&ozone->thumbnails.right); gfx_thumbnail_reset(&ozone->thumbnails.left); @@ -8646,6 +8664,59 @@ static void ozone_render(void *data, } } + /* Handle any pending thumbnail load requests */ + if (ozone->show_thumbnail_bar && + (ozone->thumbnails.pending != OZONE_PENDING_THUMBNAIL_NONE)) + { + size_t selection = menu_navigation_get_selection(); + playlist_t *playlist = playlist_get_cached(); + unsigned gfx_thumbnail_upscale_threshold = settings->uints.gfx_thumbnail_upscale_threshold; + bool network_on_demand_thumbnails = settings->bools.network_on_demand_thumbnails; + + switch (ozone->thumbnails.pending) + { + case OZONE_PENDING_THUMBNAIL_BOTH: + gfx_thumbnail_request_streams( + ozone->thumbnail_path_data, + p_anim, + playlist, selection, + &ozone->thumbnails.right, + &ozone->thumbnails.left, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + if ((ozone->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) && + (ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN)) + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; + break; + case OZONE_PENDING_THUMBNAIL_RIGHT: + gfx_thumbnail_request_stream( + ozone->thumbnail_path_data, + p_anim, + GFX_THUMBNAIL_RIGHT, + playlist, selection, + &ozone->thumbnails.right, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + if (ozone->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; + break; + case OZONE_PENDING_THUMBNAIL_LEFT: + gfx_thumbnail_request_stream( + ozone->thumbnail_path_data, + p_anim, + GFX_THUMBNAIL_LEFT, + playlist, selection, + &ozone->thumbnails.left, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + if (ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN) + ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; + break; + default: + break; + } + } + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); if (i >= entries_end) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 59d2c9a0f4..a19b8749bc 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -72,6 +72,8 @@ #define XMB_DELAY 166.66667f #endif +#define XMB_THUMBNAIL_STREAM_DELAY 166.66667f + /* Specifies minimum period (in usec) between * tab switch events when input repeat is * active (i.e. when navigating between top level @@ -255,6 +257,14 @@ enum XMB_SYSTEM_TAB_MAX_LENGTH }; +enum xmb_pending_thumbnail_type +{ + XMB_PENDING_THUMBNAIL_NONE = 0, + XMB_PENDING_THUMBNAIL_RIGHT, + XMB_PENDING_THUMBNAIL_LEFT, + XMB_PENDING_THUMBNAIL_BOTH +}; + /* NOTE: If you change this you HAVE to update * xmb_alloc_node() and xmb_copy_node() */ typedef struct @@ -317,6 +327,7 @@ typedef struct xmb_handle gfx_thumbnail_t right; gfx_thumbnail_t left; gfx_thumbnail_t savestate; + enum xmb_pending_thumbnail_type pending; } thumbnails; struct @@ -1213,70 +1224,44 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) static void xmb_update_thumbnail_image(void *data) { + xmb_handle_t *xmb = (xmb_handle_t*)data; const char *core_name = NULL; - xmb_handle_t *xmb = (xmb_handle_t*)data; - size_t selection = menu_navigation_get_selection(); - playlist_t *playlist = playlist_get_cached(); - settings_t *settings = config_get_ptr(); - unsigned thumbnail_upscale_threshold = settings->uints.gfx_thumbnail_upscale_threshold; - bool network_on_demand_thumbnails = settings->bools.network_on_demand_thumbnails; if (!xmb) return; + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; gfx_thumbnail_cancel_pending_requests(); + gfx_thumbnail_reset(&xmb->thumbnails.right); + gfx_thumbnail_reset(&xmb->thumbnails.left); /* imageviewer content requires special treatment... */ gfx_thumbnail_get_core_name(xmb->thumbnail_path_data, &core_name); + if (string_is_equal(core_name, "imageviewer")) { - gfx_thumbnail_reset(&xmb->thumbnails.right); - gfx_thumbnail_reset(&xmb->thumbnails.left); - /* Right thumbnail */ if (gfx_thumbnail_is_enabled(xmb->thumbnail_path_data, - GFX_THUMBNAIL_RIGHT)) - gfx_thumbnail_request( - xmb->thumbnail_path_data, - GFX_THUMBNAIL_RIGHT, - playlist, - selection, - &xmb->thumbnails.right, - thumbnail_upscale_threshold, - network_on_demand_thumbnails); + GFX_THUMBNAIL_RIGHT)) + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_RIGHT; /* Left thumbnail */ else if (gfx_thumbnail_is_enabled(xmb->thumbnail_path_data, - GFX_THUMBNAIL_LEFT)) - gfx_thumbnail_request( - xmb->thumbnail_path_data, - GFX_THUMBNAIL_LEFT, - playlist, - selection, - &xmb->thumbnails.left, - thumbnail_upscale_threshold, - network_on_demand_thumbnails); + GFX_THUMBNAIL_LEFT)) + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_LEFT; } else { /* Right thumbnail */ - gfx_thumbnail_request( - xmb->thumbnail_path_data, - GFX_THUMBNAIL_RIGHT, - playlist, - selection, - &xmb->thumbnails.right, - thumbnail_upscale_threshold, - network_on_demand_thumbnails); + if (gfx_thumbnail_is_enabled(xmb->thumbnail_path_data, + GFX_THUMBNAIL_RIGHT)) + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_RIGHT; /* Left thumbnail */ - gfx_thumbnail_request( - xmb->thumbnail_path_data, - GFX_THUMBNAIL_LEFT, - playlist, - selection, - &xmb->thumbnails.left, - thumbnail_upscale_threshold, - network_on_demand_thumbnails); + if (gfx_thumbnail_is_enabled(xmb->thumbnail_path_data, + GFX_THUMBNAIL_LEFT)) + xmb->thumbnails.pending = + (xmb->thumbnails.pending == XMB_PENDING_THUMBNAIL_RIGHT) ? + XMB_PENDING_THUMBNAIL_BOTH : XMB_PENDING_THUMBNAIL_LEFT; } } @@ -1338,6 +1323,7 @@ static void xmb_unload_thumbnail_textures(void *data) if (!xmb) return; + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; gfx_thumbnail_cancel_pending_requests(); gfx_thumbnail_reset(&xmb->thumbnails.right); gfx_thumbnail_reset(&xmb->thumbnails.left); @@ -1577,6 +1563,7 @@ static void xmb_selection_pointer_changed( * content + right/left thumbnails * (otherwise last loaded thumbnail will * persist, and be shown on the wrong entry) */ + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; gfx_thumbnail_set_content(xmb->thumbnail_path_data, NULL); gfx_thumbnail_cancel_pending_requests(); gfx_thumbnail_reset(&xmb->thumbnails.right); @@ -2563,6 +2550,7 @@ static void xmb_populate_entries(void *data, * file list is populated... */ if (xmb->is_file_list) { + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; gfx_thumbnail_set_content(xmb->thumbnail_path_data, NULL); gfx_thumbnail_cancel_pending_requests(); gfx_thumbnail_reset(&xmb->thumbnails.right); @@ -4286,6 +4274,58 @@ static void xmb_render(void *data, } } + /* Handle any pending thumbnail load requests */ + if (xmb->thumbnails.pending != XMB_PENDING_THUMBNAIL_NONE) + { + size_t selection = menu_navigation_get_selection(); + playlist_t *playlist = playlist_get_cached(); + unsigned gfx_thumbnail_upscale_threshold = settings->uints.gfx_thumbnail_upscale_threshold; + bool network_on_demand_thumbnails = settings->bools.network_on_demand_thumbnails; + + switch (xmb->thumbnails.pending) + { + case XMB_PENDING_THUMBNAIL_BOTH: + gfx_thumbnail_request_streams( + xmb->thumbnail_path_data, + p_anim, + playlist, selection, + &xmb->thumbnails.right, + &xmb->thumbnails.left, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + if ((xmb->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) && + (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN)) + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; + break; + case XMB_PENDING_THUMBNAIL_RIGHT: + gfx_thumbnail_request_stream( + xmb->thumbnail_path_data, + p_anim, + GFX_THUMBNAIL_RIGHT, + playlist, selection, + &xmb->thumbnails.right, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + if (xmb->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; + break; + case XMB_PENDING_THUMBNAIL_LEFT: + gfx_thumbnail_request_stream( + xmb->thumbnail_path_data, + p_anim, + GFX_THUMBNAIL_LEFT, + playlist, selection, + &xmb->thumbnails.left, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + if (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN) + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; + break; + default: + break; + } + } + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); if (i >= end) @@ -6008,7 +6048,8 @@ static void *xmb_init(void **userdata, bool video_is_threaded) xmb->fullscreen_thumbnail_selection = 0; xmb->fullscreen_thumbnail_label[0] = '\0'; - gfx_thumbnail_set_stream_delay(-1.0f); + xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; + gfx_thumbnail_set_stream_delay(XMB_THUMBNAIL_STREAM_DELAY); gfx_thumbnail_set_fade_duration(-1.0f); gfx_thumbnail_set_fade_missing(false);