mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
Pressing OK on an image in the file browser read and decoded the file a second time even though its thumbnail was already on screen. menu_media_open_selected_file only reuses a thumbnail when gfx_thumbnail_has_file says it holds the file, and that answered yes only for a live animation session. Every still (PNG, JPEG, BMP, TGA, single-frame GIF/WEBP) has no session, and neither does an animation the preview budget refuses - large ones land as a still - nor one that finished its last loop. All of those were reset and loaded again. Each thumbnail now records a 64-bit hash of the path it was requested from (no per-thumbnail path buffer), cleared on reset. gfx_thumbnail_has_file matches it while the still is shown, or while its load is in flight and not superseded; a failed or cancelled load still gets requested again. samples/gfx/gfx_thumbnail_anim lane 16 drives the real gfx_thumbnail.c: a still is recognised in flight and once shown, and not for another path, after a reset, when superseded or when the load failed. It fails on the old code.
663 lines
26 KiB
C++
663 lines
26 KiB
C++
/* Copyright (C) 2010-2019 The RetroArch team
|
|
*
|
|
* ---------------------------------------------------------------------------------------
|
|
* The following license statement only applies to this file (gfx_thumbnail.h).
|
|
* ---------------------------------------------------------------------------------------
|
|
*
|
|
* Permission is hereby granted, free of charge,
|
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef __GFX_THUMBNAIL_H
|
|
#define __GFX_THUMBNAIL_H
|
|
|
|
#include <retro_common_api.h>
|
|
#include <libretro.h>
|
|
|
|
#include <boolean.h>
|
|
#include <retro_miscellaneous.h>
|
|
#include <retro_atomic.h>
|
|
|
|
#include "gfx_animation.h"
|
|
#include "gfx_media_state.h"
|
|
|
|
#include "../playlist.h"
|
|
|
|
struct data_transfer;
|
|
|
|
RETRO_BEGIN_DECLS
|
|
|
|
/* Note: This implementation reflects the current
|
|
* setup of:
|
|
* - gfx_thumbnail_set_system()
|
|
* - menu_driver_set_thumbnail_content()
|
|
* - menu_driver_update_thumbnail_path()
|
|
* This is absolutely not the best way to handle things,
|
|
* but I have no interest in rewriting the existing
|
|
* menu code... */
|
|
|
|
enum gfx_thumbnail_id
|
|
{
|
|
GFX_THUMBNAIL_RIGHT = 0,
|
|
GFX_THUMBNAIL_LEFT,
|
|
GFX_THUMBNAIL_ICON
|
|
};
|
|
|
|
/* Prevent direct access to gfx_thumbnail_path_data_t members */
|
|
typedef struct gfx_thumbnail_path_data gfx_thumbnail_path_data_t;
|
|
|
|
/* Used fixed size char arrays here, just to avoid
|
|
* the inconvenience of having to calloc()/free()
|
|
* each individual entry by hand... */
|
|
struct gfx_thumbnail_path_data
|
|
{
|
|
enum playlist_thumbnail_mode playlist_right_mode;
|
|
enum playlist_thumbnail_mode playlist_left_mode;
|
|
enum playlist_thumbnail_mode playlist_icon_mode;
|
|
size_t playlist_index;
|
|
size_t system_len;
|
|
char content_label[NAME_MAX_LENGTH];
|
|
char content_core_name[NAME_MAX_LENGTH];
|
|
char system[NAME_MAX_LENGTH];
|
|
char content_db_name[NAME_MAX_LENGTH];
|
|
char content_path[PATH_MAX_LENGTH];
|
|
char content_img[PATH_MAX_LENGTH];
|
|
char content_img_short[PATH_MAX_LENGTH];
|
|
char content_img_full[PATH_MAX_LENGTH];
|
|
char right_path[PATH_MAX_LENGTH];
|
|
char left_path[PATH_MAX_LENGTH];
|
|
char icon_path[PATH_MAX_LENGTH];
|
|
};
|
|
|
|
/* Initialisation */
|
|
|
|
/* Creates new thumbnail path data container.
|
|
* Returns handle to new gfx_thumbnail_path_data_t object.
|
|
* on success, otherwise NULL.
|
|
* Note: Returned object must be free()d */
|
|
gfx_thumbnail_path_data_t *gfx_thumbnail_path_init(void);
|
|
|
|
/* Resets thumbnail path data
|
|
* (blanks all internal string containers) */
|
|
void gfx_thumbnail_path_reset(gfx_thumbnail_path_data_t *path_data);
|
|
|
|
/* Utility Functions */
|
|
|
|
/* Returns true if specified thumbnail is enabled
|
|
* (i.e. if 'type' is not equal to MENU_ENUM_LABEL_VALUE_OFF) */
|
|
bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id);
|
|
|
|
/* Setters */
|
|
|
|
/* Fills content_img field of path_data using existing
|
|
* content_label field (for internal use only) */
|
|
void gfx_thumbnail_fill_content_img(char *s, size_t len, const char *src, bool shorten);
|
|
|
|
/* Sets current 'system' (default database name).
|
|
* Returns true if 'system' is valid.
|
|
* If playlist is provided, extracts system-specific
|
|
* thumbnail assignment metadata (required for accurate
|
|
* usage of gfx_thumbnail_is_enabled())
|
|
* > Used as a fallback when individual content lacks an
|
|
* associated database name */
|
|
bool gfx_thumbnail_set_system(gfx_thumbnail_path_data_t *path_data, const char *system, playlist_t *playlist);
|
|
|
|
/* Sets current thumbnail content according to the specified label.
|
|
* Returns true if content is valid */
|
|
bool gfx_thumbnail_set_content(gfx_thumbnail_path_data_t *path_data, const char *label);
|
|
|
|
/* Sets current thumbnail content to the specified image.
|
|
* Returns true if content is valid */
|
|
bool gfx_thumbnail_set_content_image(gfx_thumbnail_path_data_t *path_data, const char *img_dir, const char *img_name);
|
|
|
|
/* Sets current thumbnail content to the specified playlist entry.
|
|
* Returns true if content is valid.
|
|
* > Note: It is always best to use playlists when setting
|
|
* thumbnail content, since there is no guarantee that the
|
|
* corresponding menu entry label will contain a useful
|
|
* identifier (it may be 'tainted', e.g. with the current
|
|
* core name). 'Real' labels should be extracted from source */
|
|
bool gfx_thumbnail_set_content_playlist(gfx_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx);
|
|
|
|
/* Updaters */
|
|
|
|
/* Updates path for specified thumbnail identifier (right, left).
|
|
* Must be called after:
|
|
* - gfx_thumbnail_set_system()
|
|
* - gfx_thumbnail_set_content*()
|
|
* ...and before:
|
|
* - gfx_thumbnail_get_path()
|
|
* Returns true if generated path is valid */
|
|
bool gfx_thumbnail_update_path(gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id);
|
|
|
|
/* The settings gfx_thumbnail_update_path() consults, as a value: a
|
|
* worker captures these on the main thread when its task is pushed
|
|
* and calls the _cfg variant, which reads no live settings at all.
|
|
* Main-thread callers keep the plain variant, which reads live. */
|
|
typedef struct gfx_thumbnail_dir_config
|
|
{
|
|
char dir_thumbnails[DIR_MAX_LENGTH];
|
|
bool playlist_allow_non_png;
|
|
unsigned gfx_thumbnails;
|
|
unsigned menu_left_thumbnails;
|
|
unsigned menu_icon_thumbnails;
|
|
} gfx_thumbnail_dir_config_t;
|
|
|
|
void gfx_thumbnail_dir_config_capture(gfx_thumbnail_dir_config_t *cfg);
|
|
bool gfx_thumbnail_update_path_cfg(gfx_thumbnail_path_data_t *path_data,
|
|
enum gfx_thumbnail_id thumbnail_id,
|
|
const gfx_thumbnail_dir_config_t *cfg);
|
|
|
|
/* Getters */
|
|
|
|
/* Fetches current content directory.
|
|
* Returns true if content directory is valid. */
|
|
size_t gfx_thumbnail_get_content_dir(gfx_thumbnail_path_data_t *path_data, char *s, size_t len);
|
|
|
|
/* Gets the common savestate thumbnail path. */
|
|
void gfx_savestate_thumbnail_get_path(char *s, size_t len, const char *state_name, int state_slot);
|
|
|
|
/* Defines the current status of an entry
|
|
* thumbnail texture */
|
|
enum gfx_thumbnail_status
|
|
{
|
|
GFX_THUMBNAIL_STATUS_UNKNOWN = 0,
|
|
GFX_THUMBNAIL_STATUS_PENDING,
|
|
GFX_THUMBNAIL_STATUS_AVAILABLE,
|
|
GFX_THUMBNAIL_STATUS_MISSING
|
|
};
|
|
|
|
/* Defines thumbnail alignment within
|
|
* gfx_thumbnail_draw() bounding box */
|
|
enum gfx_thumbnail_alignment
|
|
{
|
|
GFX_THUMBNAIL_ALIGN_CENTRE = 0,
|
|
GFX_THUMBNAIL_ALIGN_TOP,
|
|
GFX_THUMBNAIL_ALIGN_BOTTOM,
|
|
GFX_THUMBNAIL_ALIGN_LEFT,
|
|
GFX_THUMBNAIL_ALIGN_RIGHT
|
|
};
|
|
|
|
/* Defines all possible thumbnail shadow
|
|
* effect types */
|
|
enum gfx_thumbnail_shadow_type
|
|
{
|
|
GFX_THUMBNAIL_SHADOW_NONE = 0,
|
|
GFX_THUMBNAIL_SHADOW_DROP,
|
|
GFX_THUMBNAIL_SHADOW_OUTLINE
|
|
};
|
|
|
|
enum gfx_thumbnail_flags
|
|
{
|
|
GFX_THUMB_FLAG_FADE_ACTIVE = (1 << 0),
|
|
GFX_THUMB_FLAG_CORE_ASPECT = (1 << 1),
|
|
GFX_THUMB_FLAG_BG_ONLY = (1 << 2),
|
|
GFX_THUMB_FLAG_ANIM_ACTIVE = (1 << 3),
|
|
GFX_THUMB_FLAG_MEDIA_COMPLETED = (1 << 4),
|
|
GFX_THUMB_FLAG_MEDIA_ENDED = (1 << 5)
|
|
};
|
|
|
|
/* Holds all runtime parameters associated with
|
|
* an entry thumbnail.
|
|
*
|
|
* @c status is read by the video thread (via
|
|
* gfx_thumbnail_draw) and written by both the upload-callback
|
|
* thread (release-store after publishing texture/width/height)
|
|
* and the main thread (a number of plain transitions during menu
|
|
* processing). retro_atomic_int_t backs the field with an
|
|
* atomic-typed integer that is safe to read/write through the
|
|
* retro_atomic_*_int API on every supported backend.
|
|
*
|
|
* Same size and alignment as plain int on every backend; struct
|
|
* layout is unchanged. The cost of the acquire/release barriers
|
|
* on weak-memory ARM/PowerPC is negligible at this field's
|
|
* access rates (menu and frame draw, never per-sample). */
|
|
/* LIFECYCLE CONTRACT: every instance must be zeroed before any
|
|
* other thumbnail API call - including gfx_thumbnail_reset(),
|
|
* which frees the animation pointers below and therefore treats
|
|
* nonzero garbage as live allocations. calloc'd and static
|
|
* instances are inherently safe; anything malloc'd or
|
|
* stack-allocated must go through gfx_thumbnail_init_blank(),
|
|
* which also stores the atomically-typed status correctly and
|
|
* stays complete as fields are added. Manual field-by-field
|
|
* initialization is how the materialui Android startup abort
|
|
* happened; do not reintroduce it. */
|
|
typedef struct
|
|
{
|
|
/* The animation surface's, which owns and unloads it */
|
|
uintptr_t texture;
|
|
/* Animated thumbnail state (all main-thread only). 'anim' is a
|
|
* streaming image_transfer handle which BORROWS 'anim_buf'; both
|
|
* are owned by the thumbnail and released in gfx_thumbnail_reset
|
|
* (or when the animation finishes its final loop). 'anim_buf'
|
|
* is either a malloc'd file read (anim_dt NULL, freed with
|
|
* free()) or borrowed from an adopted nbio handle (released via
|
|
* data_transfer_free(anim_dt); anim_buf itself must not be
|
|
* freed). */
|
|
void *anim;
|
|
/* Shared preview session (gfx_anim_preview_t*) over anim / anim_dt:
|
|
* the window feeder and the preview audio. Non-owning. */
|
|
void *anim_sess;
|
|
void *anim_buf;
|
|
struct data_transfer *anim_dt; /* transfer owning anim_buf (and the
|
|
adopted nbio handle beneath it) */
|
|
/* The playback (gfx_surface_player_t*): its clock and loops, and
|
|
* the decode, a frame ahead on a worker where there is one. */
|
|
void *anim_player;
|
|
void *anim_lifetime;
|
|
/* The GPU surface (gfx_surface_t*) the still goes to, and the
|
|
* animation's frames are decoded into and shown from: one
|
|
* persistent texture updated per frame, kept after the animation
|
|
* ends so its last frame stays as the still. Freed by
|
|
* gfx_thumbnail_reset. */
|
|
void *anim_surface;
|
|
size_t anim_buf_len; /* size of anim_buf */
|
|
/* Generation the in-flight request was issued under. Only
|
|
* meaningful while status is PENDING: if it no longer matches the
|
|
* current generation, that request was superseded and nothing will
|
|
* ever deliver it, so the slot must be re-requested rather than
|
|
* waited on. */
|
|
uint64_t list_id;
|
|
/* 64-bit FNV-1a of the file this thumbnail was last requested
|
|
* from, 0 when none; cleared by gfx_thumbnail_reset. Lets
|
|
* gfx_thumbnail_has_file recognise a still (or an animation that
|
|
* fell back to one) without keeping a path buffer per thumbnail,
|
|
* so the viewer takes what the browser already decoded. */
|
|
uint64_t file_hash;
|
|
/* Both axes in one word, VIDEO_SCALE_PACK's layout. */
|
|
unsigned dims;
|
|
float alpha;
|
|
float delay_timer;
|
|
retro_atomic_int_t status;
|
|
uint8_t flags;
|
|
uint8_t anim_type; /* enum image_type_enum of 'anim' */
|
|
uint8_t anim_read_pending; /* adopted nbio read still in flight;
|
|
animation/audio held at the static
|
|
frame until it completes */
|
|
|
|
uint8_t anim_windowed; /* anim_dt is a sliding window fed from the
|
|
decoder frontier during playback, not a
|
|
buffer pumped to completion: residency is
|
|
the window, not the whole file (large
|
|
video previews). 0 = classic whole-file
|
|
buffer (audio preview, non-reserve
|
|
platforms, adopted stills). */
|
|
} gfx_thumbnail_t;
|
|
|
|
/* Field-by-field initializer for non-trivial gfx_thumbnail_t.
|
|
*
|
|
* Now that .status is atomically-typed, a wholesale
|
|
* memset(t, 0, sizeof(*t)) of a struct containing this type
|
|
* warns under CXX_BUILD's C++ compile (the struct is no longer
|
|
* trivially-copyable per C++11), even though the resulting
|
|
* bytes are identical. RetroArch's CXX_BUILD mode
|
|
* compiles every .c file as C++, so this helper is required
|
|
* for clean builds, not just style.
|
|
*
|
|
* gfx_thumbnail_init_blank zero-inits the small struct field
|
|
* by field, using retro_atomic_int_init() for the atomic field
|
|
* so the first write is well-defined under C11 stdatomic and
|
|
* C++11 std::atomic. Equivalent in effect to the pre-port
|
|
* memset on every real backend (status field is also zero ->
|
|
* UNKNOWN). */
|
|
static INLINE void gfx_thumbnail_init_blank(gfx_thumbnail_t *t)
|
|
{
|
|
t->texture = 0;
|
|
t->anim = NULL;
|
|
t->anim_buf = NULL;
|
|
t->anim_dt = NULL;
|
|
t->anim_sess = NULL;
|
|
t->anim_player = NULL;
|
|
t->anim_lifetime = NULL;
|
|
t->anim_surface = NULL;
|
|
t->anim_buf_len = 0;
|
|
t->list_id = 0;
|
|
t->dims = 0;
|
|
t->alpha = 0.0f;
|
|
t->delay_timer = 0.0f;
|
|
retro_atomic_int_init(&t->status, 0 /* GFX_THUMBNAIL_STATUS_UNKNOWN */);
|
|
t->flags = 0;
|
|
t->anim_type = 0;
|
|
t->anim_read_pending = 0;
|
|
t->anim_windowed = 0;
|
|
}
|
|
|
|
/* Holds all configuration parameters associated
|
|
* with a thumbnail shadow effect */
|
|
typedef struct
|
|
{
|
|
struct
|
|
{
|
|
unsigned width;
|
|
} outline;
|
|
float alpha;
|
|
struct
|
|
{
|
|
float x_offset;
|
|
float y_offset;
|
|
} drop;
|
|
enum gfx_thumbnail_shadow_type type;
|
|
} gfx_thumbnail_shadow_t;
|
|
|
|
/* Structure containing all gfx_thumbnail
|
|
* variables */
|
|
struct gfx_thumbnail_state
|
|
{
|
|
/* Due to the asynchronous nature of thumbnail
|
|
* loading, it is quite possible to trigger a load
|
|
* then navigate to a different menu list before
|
|
* the load is complete/handled. As an additional
|
|
* safety check, we therefore tag the current menu
|
|
* list with counter value that is incremented whenever
|
|
* a list is cleared/set. This is sent as userdata when
|
|
* requesting a thumbnail, and the upload is only
|
|
* handled if the tag matches the most recent value
|
|
* at the time when the load completes */
|
|
uint64_t list_id;
|
|
|
|
/* When streaming thumbnails, to minimise the processing
|
|
* of unnecessary images (i.e. when scrolling rapidly through
|
|
* playlists), we delay loading until an entry has been on screen
|
|
* for at least gfx_thumbnail_delay ms */
|
|
float stream_delay;
|
|
|
|
/* Duration in ms of the thumbnail 'fade in' animation */
|
|
float fade_duration;
|
|
|
|
/* When true, 'fade in' animation will also be
|
|
* triggered for missing thumbnails */
|
|
bool fade_missing;
|
|
};
|
|
|
|
typedef struct gfx_thumbnail_state gfx_thumbnail_state_t;
|
|
|
|
|
|
/* Setters */
|
|
|
|
/* When streaming thumbnails, sets time in ms that an
|
|
* entry must be on screen before an image load is
|
|
* requested
|
|
* > if 'delay' is negative, default value is set */
|
|
void gfx_thumbnail_set_stream_delay(float delay);
|
|
|
|
/* Sets duration in ms of the thumbnail 'fade in'
|
|
* animation
|
|
* > If 'duration' is negative, default value is set */
|
|
void gfx_thumbnail_set_fade_duration(float duration);
|
|
|
|
/* Specifies whether 'fade in' animation should be
|
|
* triggered for missing thumbnails
|
|
* > When 'true', allows menu driver to animate
|
|
* any 'thumbnail unavailable' notifications */
|
|
void gfx_thumbnail_set_fade_missing(bool fade_missing);
|
|
|
|
/* Core interface */
|
|
|
|
/* Tears down the shared animated-thumbnail decode worker (a no-op in
|
|
* builds without HAVE_THREADS, and when the worker was never started).
|
|
* Must be called after every gfx_thumbnail_t has been reset. The worker
|
|
* is recreated lazily by the next animated thumbnail. */
|
|
void gfx_thumbnail_anim_worker_deinit(void);
|
|
|
|
/* When called, prevents the handling of any pending
|
|
* thumbnail load requests
|
|
* >> **MUST** be called before deleting any gfx_thumbnail_t
|
|
* objects passed to gfx_thumbnail_request() or
|
|
* gfx_thumbnail_process_stream(), otherwise
|
|
* heap-use-after-free errors *will* occur */
|
|
void gfx_thumbnail_cancel_pending_requests(void);
|
|
|
|
/* While on, still requests land decoded and are held instead of
|
|
* uploaded (at most four, by path); the next request for the same
|
|
* path uploads the held image without reading or decoding the file.
|
|
* For a menu whose thumbnails are not shown while content runs:
|
|
* requested as content starts, they upload when shown or on close. */
|
|
void gfx_thumbnail_park_requests(bool park);
|
|
|
|
/* Frees the held images */
|
|
void gfx_thumbnail_parked_free(void);
|
|
|
|
/* True if 'thumbnail' is waiting on a request that has since been
|
|
* superseded, i.e. it is PENDING with nothing behind it. Resets the
|
|
* thumbnail (returning it to UNKNOWN) and returns true in that case, so
|
|
* the caller's normal "request if UNKNOWN" path picks it up again.
|
|
* gfx_thumbnail_process_stream()/_streams() call this themselves; menu
|
|
* drivers that call gfx_thumbnail_request() directly should call it
|
|
* before testing the status. */
|
|
bool gfx_thumbnail_reset_if_orphaned(gfx_thumbnail_t *thumbnail);
|
|
|
|
/* Requests loading of the specified thumbnail
|
|
* - If operation fails, 'thumbnail->status' will be set to
|
|
* MUI_THUMBNAIL_STATUS_MISSING
|
|
* - If operation is successful, 'thumbnail->status' will be
|
|
* set to MUI_THUMBNAIL_STATUS_PENDING
|
|
* 'thumbnail' will be populated with texture info/metadata
|
|
* once the image load is complete
|
|
* 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...) */
|
|
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);
|
|
|
|
/* Requests loading of a specific thumbnail image file
|
|
* (may be used, for example, to load savestate images)
|
|
* - If operation fails, 'thumbnail->status' will be set to
|
|
* MUI_THUMBNAIL_STATUS_MISSING
|
|
* - If operation is successful, 'thumbnail->status' will be
|
|
* set to MUI_THUMBNAIL_STATUS_PENDING
|
|
* 'thumbnail' will be populated with texture info/metadata
|
|
* once the image load is complete */
|
|
void gfx_thumbnail_request_file(
|
|
const char *file_path, gfx_thumbnail_t *thumbnail,
|
|
unsigned gfx_thumbnail_upscale_threshold);
|
|
|
|
/* Sends the stills asked for since the last call to the task queue,
|
|
* in sets decoded across the cores at once. Called by a menu driver
|
|
* at the end of a frame that may have asked for thumbnails; nothing
|
|
* to send is a no-op. */
|
|
void gfx_thumbnail_flush_requests(void);
|
|
|
|
/* Resets (and free()s the current texture of) the
|
|
* specified thumbnail */
|
|
void gfx_thumbnail_reset(gfx_thumbnail_t *thumbnail);
|
|
|
|
/* Advances an animated thumbnail (animated WebP / WebM) by at most one frame,
|
|
* if its frame duration has elapsed. Call once per frame, on the main
|
|
* thread, for every on-screen thumbnail. Non-animated thumbnails and
|
|
* non-WebP image types return immediately (single flag test), so this
|
|
* is safe and near-free to call for every thumbnail unconditionally. */
|
|
/* @current_time is the frame's monotonic timestamp, as sampled once
|
|
* per iteration by the runloop and handed to gfx_animation_update():
|
|
* this function reads no clock of its own, so every thumbnail
|
|
* advanced in a frame paces off one coherent 'now', and a harness can
|
|
* drive it with synthetic time. */
|
|
unsigned gfx_thumbnail_anim_threads_wanted(void);
|
|
|
|
/* Main-thread identity check for an installed preview session. */
|
|
bool gfx_thumbnail_has_file(const gfx_thumbnail_t *thumbnail, const char *path);
|
|
|
|
void gfx_thumbnail_animate(gfx_thumbnail_t *thumbnail,
|
|
retro_time_t current_time);
|
|
|
|
/* Main-thread media command: retain the current picture and preview PCM.
|
|
* Uses the same monotonic clock as animate. False for a still or a
|
|
* thumbnail whose animation session has not been installed yet. */
|
|
bool gfx_thumbnail_set_repeat(gfx_thumbnail_t *thumbnail, bool repeat);
|
|
bool gfx_thumbnail_take_completed(gfx_thumbnail_t *thumbnail);
|
|
bool gfx_thumbnail_set_paused(gfx_thumbnail_t *thumbnail, bool paused,
|
|
retro_time_t current_time);
|
|
|
|
typedef gfx_media_playback_state_t gfx_thumbnail_playback_state_t;
|
|
|
|
/* Main-thread UI snapshot using the same monotonic time as animate.
|
|
* Position follows mixed PCM when available. While seeking it shows
|
|
* the latest requested target. False for a still/non-media thumbnail. */
|
|
bool gfx_thumbnail_get_playback_state(gfx_thumbnail_t *thumbnail,
|
|
retro_time_t current_time, gfx_thumbnail_playback_state_t *state);
|
|
|
|
/* Main-thread absolute media seek, currently MP4. Latest request wins;
|
|
* decoding and audio preparation use the existing player worker.
|
|
* Keeps the last texture visible and preserves the user's pause state. */
|
|
bool gfx_thumbnail_seek(gfx_thumbnail_t *thumbnail, int64_t target_us,
|
|
retro_time_t current_time);
|
|
|
|
/* 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
|
|
* - Must be called once for each entry as it moves off-screen
|
|
* (or can be called each frame - overheads are small)
|
|
* NOTE 1: Must be called *after* gfx_thumbnail_set_system()
|
|
* NOTE 2: This function calls gfx_thumbnail_set_content*()
|
|
* 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_process_streams() for improved
|
|
* performance */
|
|
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,
|
|
gfx_thumbnail_t *thumbnail,
|
|
bool on_screen,
|
|
unsigned gfx_thumbnail_upscale_threshold,
|
|
bool network_on_demand_thumbnails);
|
|
|
|
/* Handles streaming of the specified thumbnails as they move
|
|
* on/off screen
|
|
* - Must be called each frame for every on-screen entry
|
|
* - Must be called once for each entry as it moves off-screen
|
|
* (or can be called each frame - overheads are small)
|
|
* NOTE 1: Must be called *after* gfx_thumbnail_set_system()
|
|
* NOTE 2: This function calls gfx_thumbnail_set_content*()
|
|
* 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_process_stream() for improved
|
|
* performance */
|
|
void gfx_thumbnail_process_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,
|
|
bool on_screen,
|
|
unsigned gfx_thumbnail_upscale_threshold,
|
|
bool network_on_demand_thumbnails);
|
|
|
|
/* Thumbnail rendering */
|
|
|
|
/* Determines the actual screen dimensions of a
|
|
* thumbnail when centred with aspect correct
|
|
* scaling within a rectangle of (width x height) */
|
|
void gfx_thumbnail_get_draw_dimensions(
|
|
gfx_thumbnail_t *thumbnail,
|
|
unsigned dims, float scale_factor,
|
|
float *draw_width, float *draw_height);
|
|
|
|
/* Draws specified thumbnail with specified alignment
|
|
* (and aspect correct scaling) within a rectangle of
|
|
* (width x height).
|
|
* 'shadow' defines an optional shadow effect (may be
|
|
* set to NULL if a shadow effect is not required).
|
|
* NOTE: Setting scale_factor > 1.0f will increase the
|
|
* size of the thumbnail beyond the limits of the
|
|
* (width x height) rectangle (alignment + aspect
|
|
* correct scaling is preserved). Use with caution */
|
|
/* @video_dims and @dims: the output size and the rectangle the
|
|
* thumbnail is fitted into, each with both axes in one word,
|
|
* VIDEO_SCALE_PACK's layout. */
|
|
void gfx_thumbnail_draw(
|
|
void *userdata,
|
|
unsigned video_dims,
|
|
gfx_thumbnail_t *thumbnail,
|
|
float x, float y, unsigned dims,
|
|
enum gfx_thumbnail_alignment alignment,
|
|
float alpha, float scale_factor,
|
|
gfx_thumbnail_shadow_t *shadow);
|
|
|
|
gfx_thumbnail_state_t *gfx_thumb_get_ptr(void);
|
|
|
|
RETRO_END_DECLS
|
|
|
|
#endif
|