mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
* file_path: stop at the end of the path after '~'
fill_pathname_expand_special() skipped two characters after a leading
'~' or ':', so a bare "~" read past its NUL and "~x" lost the x. It
now skips the prefix and a slash after it, if there is one.
* scan: hand the callback user data and what the scan did
task_push_dbscan() and task_push_manual_content_scan() take user data
for their callback, and the callback's task_data is now a
task_dbscan_result_t: how many entries the scan added, how many its
playlists already held, and how many files matched nothing. A file is
counted by what became of it, so an archive that is expanded is not
counted as unmatched, and a loose scan's unmatched files count as
added. Callers pass NULL for now.
* scan: say in the result when a scan failed
A scan that ends before it runs (bad setup, no valid content, a DAT
that will not load) or ends with a task error now sets the result's
failed flag. A database folder that is missing or unset is treated as
an empty one, so it reports the same "no database" error instead of
finishing as if it had scanned.
* scan: count the files a scan could not read
A file whose scan fails (an unreadable file, a failed lookup) was in
no count. The result now carries an errors count for them. They do
not fail the scan.
* scan: print --scan errors on stderr and totals on stdout
A command-line scan now ends with a totals line on stdout, or with the
reason it failed on stderr. A file it could not read is listed on
stderr. The ++/==/?? marks are coloured only when their stream is a
terminal, so pipes and redirected output get plain text; on Windows
redirected output keeps its marks instead of losing them to
WriteConsole.
* scan: the manual scan finder skips a finished task
A finished scan stays in the task queue while its callback runs, and
the finder that refuses a second scan for the same playlist still
matched it, so a scan pushed from that callback was refused.
* retroarch: run every --scan, then exit with what the scans did
Each --scan is collected while the command line is parsed and run in
turn once it is done, so later options and further --scan flags are
no longer dropped. A path is expanded and made absolute first; one
that does not exist, or a scan that cannot start, is reported on
stderr and the next path still runs. --scan with --cloudsync or
--command is refused.
Without --menu the exit status is 1 if any scan failed, else 0 if any
added an entry, else 2, and a content path given with the scans is
ignored, with a line on stderr. With --menu each finished scan starts
the next, as a second scan is refused while one runs.
* manual_content_scan: clear the database name a refresh did not save
A playlist with no saved database name left the name buffer
uninitialised, and the refresh compared it against every installed
database, so whatever was on the stack could pick a database the
playlist never named.
* scan: Skip Database References names the scan's one playlist
The option was meant to put the playlist's name in each entry's
db_name, even for a database match (#18641), for users who build
their own thumbnail sets. When the scan picks the playlists, db_name
also picks the playlist an entry goes to, so with the option on every
match went to one playlist named after the content folder.
It now applies only when the scan writes one playlist, and gives
that playlist's name, a loose scan's unmatched entries included. With
the target on <Automatic>, or Fully Automatic with the option left on
from a Custom scan, matches go to their databases' playlists as with
it off; the entries of a custom playlist look their thumbnails up
under its name, not the folder's.
* scan: name the scanned folder in the start line
The "Scanning content" line, in the log and in --scan's output, has
named the database folder since the manual scan and the database scan
were merged (2fdf736d51); before, it named the path being scanned. It
names the content folder again.
* manual_content_scan: reset, scan overrides and their apply
The command line's scan options need each scan to start from the
defaults and to lay their values over them, or over a playlist's saved
settings. Add a reset, a record of those options and a function that
applies it through the existing setters: a core named by path, file
name or display name, a database, a playlist, the database check or a
DAT, extensions and the switches, stopping with a reason at the first
that does not resolve.
A core path is normalised before it is compared. A core's file name
matches in the case given first, then ignoring case, on every
platform; a display name matches exactly. Given another database, a
playlist named after its database keeps that name as a custom one, so
a refresh still writes the same playlist.
The core setter's copy step becomes its own function, so a core found
by path or file name can be set. Nothing calls the new functions yet.
* scan: run --scan items through one chain
The --scan paths ran through a loop in retroarch.c, and with --menu
through a second chain of their own. The scan options and playlist
refreshes to come need one runner for every item, from the command
line and from the menu.
task_push_dbscan_chain() runs a list of items one task at a time: a
prep task lists the databases, then each step is pushed from the last
task's callback on the main thread, so nothing waits and nothing
locks. An item that fails is reported and the run goes on; a
cancelled task ends it. retroarch.c builds the items in the first
argument pass and hands them to the chain; without --menu it waits
for the chain's end and exits as before.
Running out of memory prints "out of memory" on stderr: for an item's
path the item fails, and for the chain itself nothing runs, which
without --menu exits 1.
The chain also prints a scan's override errors, and the warnings for
an option that needs one playlist or does nothing for a single file,
which the scan options of the next commit can trigger.
* retroarch: Manual Scan options for --scan
--scan-playlist, --scan-database, --scan-match, --scan-dat, --scan-core,
--scan-exts and the five switches set the Manual Scan settings of the
--scan before them; a --scan without any stays Fully Automatic.
Values are checked in the first pass, so an option before any --scan,
an empty or bad value, or one too long for its setting ends the run
with its reason on stderr and status 1, before the config loads and
before anything is scanned. Cores, databases and DAT files are
resolved when their scan runs, and one that does not resolve fails
only that scan.
* scan: refresh playlists in the chain
A refresh item rescans one playlist with its saved scan settings, as
the menu's Refresh Playlist does, with the item's scan options laid
over them and written back by the scan. A refresh-all item does the
same for every playlist in the playlist folder that has saved
settings, in the order Manage Playlists lists them, histories and
favorites left out.
A refresh item names its playlist by name or by a path in the playlist
folder. A bare "name.lpl" is the playlist folder's file, and an
absolute path is normalised before it is checked against the folder.
The name is looked up in the folder's listing on every platform, the
exact name first, then ignoring case, since macOS and FAT/exFAT cards
ignore case; the refresh then takes the file's own name, so a
database's playlist stays one. Two or more playlists that match only
in other cases fail the item.
The playlist folder walk and each playlist load run in prep tasks: on
the worker with a threaded queue, under the shared I/O window without
one, each pushed from the previous step's callback. A playlist whose
saved content folder is gone is skipped rather than failed. A listing
that runs out of memory fails the refresh-all; a playlist folder that
is missing or cannot be read lists nothing, and the refresh-all ends
with "no playlists with saved scan settings". A refresh's start line
names its content folder; its totals and failure lines name the
playlist.
* retroarch: --scan-refresh and --scan-refresh-all
--scan-refresh=NAME|PATH rescans a playlist with its saved scan
settings, as the menu's Refresh Playlist does, and --scan-refresh-all
rescans every playlist that has them. Both are items of the same run
as --scan: the scan options after one are laid over the saved
settings and written back, and the exit status follows the same rule.
--scan-playlist after a refresh is refused, so a refresh always
updates its own playlist, and an empty --scan-refresh is refused as
the other empty values are. Like --scan, the refresh options cannot be
combined with --cloudsync or --command; the error names whichever of
the three comes first on the command line.
* menu: Refresh All Playlists
Manage Playlists gets Refresh All Playlists as its first entry when it
lists any playlist, so an empty list still says there are no entries.
It rescans every playlist that has saved scan settings, with those
settings, through the same chain as --scan-refresh-all, and ends with
one notification saying how many playlists were refreshed, skipped
(content folder gone) and failed.
While a content scan runs it is refused with a new message; a refused
scan had none. Other languages come through Crowdin.
While a scan chain runs (Refresh All, or a command-line scan with
--menu), Start Scan, a playlist's Refresh, Scan Directory and Scan
File are refused with the same message, as they would run with the
settings the chain last loaded. task_push_dbscan() returns false then
too, which covers the companion and the iOS caller.
* docs: --scan, refresh and the Manual Scan options in the man page
--help lists the options but not what a script needs: the order the
scans run in, the exit status and what the options set. The man page
now has them, next to --cloudsync, and CHANGES.md has the entry.
* scan chain: writes from workers reach the playlist cache by note
A playlist written by a task - the chain's prep parse, a scan, a
playlist-manager task, whatever thread it runs on - leaves a note on a
lock-free stack instead of reading the cached playlist; the main
thread applies the notes when it next decides whether the cache may
stand in, so no worker reads playlist_cached while the main thread
frees or installs it. Without threads or pointer atomics a write
applies at once.
The chain's prep tasks set their handlers by name, and
thread_read_audit.py fails on a handler set from a
retro_task_handler_t parameter, which would hide every handler passed
in. The chain puts the Manual Scan settings it found back when it
ends, and is no longer running when its done callback runs, so that
callback may start another. task_push_dbscan() says why it refuses,
so the menu and the companions show the same reason, and the
companions' status line takes it from companion_core. --scan and
--scan-refresh set the verbosity override, so a config with logging
off cannot detach the console the totals go to, and refuse a path too
long for the chain's buffers. The Refresh All notification passes the
length written, and fill_pathname_expand_special() stops at the end of
a buffer shorter than the home or application directory.
Lanes: playlist_parity_test writes the cached file from a worker,
once at the same size and then while the main thread reuses and frees
the cache; database_scan_test checks the refusal message, the restored
settings and a done callback that starts the next chain;
fill_pathname_test expands into a buffer shorter than the home
directory.
* playlist: header-only parse for the scan chain's prep
The prep task needs a playlist's saved scan settings and nothing else,
yet parsed every entry and, through autofix, could write the file back
from a worker. playlist_parse_begin_header() stops at "items", rebases
the scan record in memory when the base content directory moved, and
marks the playlist so playlist_write_file() refuses it.
Lane: playlist_parity_test header_only (entries skipped, scan dir
rebased, file bytes untouched, old format).
* scan chain: ask the file system nothing on the main thread
The chain's steps ran on the main thread between its tasks and stat'd
and realpath'd there: a --scan path's resolve and stat, a
--scan-refresh path's two realpaths, the content folder's stat, the
saved and override DATs' stat and size, an override core path's
realpath. On a network share each of those can stall a frame.
- manual_content_scan_fs_read() reads them on any thread, touching
nothing but its arguments; the _fs variants of the content-folder,
playlist and override setters take its answers instead of asking.
The plain setters pass NULL and behave as before, so the menu is
unchanged.
- A --scan path gets its own prep task (dbscan_path_handler); a
--scan-refresh resolves its path inside the load task, and the load
reads the folder, the saved DAT and the overrides' paths once the
header is parsed. The worker gets copies of the item's strings.
- The prep's state is freed in one place.
Lane: database_scan_test "fs off main": six items that each stop
before their scan, on a threaded queue, with path_stat, path_is_valid,
path_is_directory, path_get_size and path_resolve_realpath wrapped:
no call on the main thread.
Not moved: the scan task's own push still stats the content folder
and the DAT (manual_content_scan_get_task_config), shared with the
menu.
* samples: the scan chain's lanes hold on Windows and without realpath
From a native Windows run of both tests:
- database_scan_test "fs off main" refreshed f_gone.lpl through
"pl/../pl/", which only a realpath folds; the sample builds without
RARCH_INTERNAL, where path_resolve_realpath() folds nothing, so the
item was rightly not in the playlist folder. It names the playlist
by its plain path now, which the check still realpaths on the
worker.
- "another case, a database's playlist" read the system name type
after the chain ended, and the chain puts the Manual Scan settings
back then. The item callback records each scan's type instead.
- playlist_parity_test's header lane expected "/moved/snes"; autofix
converts the suffix to the local form, "/moved\snes" on Windows.
- The worker lane's stress read required a core name of every read.
Windows replaces the file with MoveFileExW, and an open that meets
the replace fails: that read is an empty playlist, which has none.
---------
Co-authored-by: LibretroAdmin <[email protected]>
613 lines
23 KiB
C
613 lines
23 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* Copyright (C) 2011-2017 - Higor Euripedes
|
|
* Copyright (C) 2011-2017 - Daniel De Matteis
|
|
*
|
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef TASKS_HANDLER_INTERNAL_H
|
|
#define TASKS_HANDLER_INTERNAL_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <boolean.h>
|
|
#include <retro_common_api.h>
|
|
#include <retro_miscellaneous.h>
|
|
#include <lists/string_list.h>
|
|
/* task_image_detach_video_stream takes enum image_type_enum: the enum
|
|
* must be a complete type here or a TU that includes this header first
|
|
* (griffin concatenates via runloop.h) declares it with prototype
|
|
* scope and the definition in task_image.c then conflicts. */
|
|
#include <formats/image.h>
|
|
|
|
#include <queues/task_queue.h>
|
|
#include <gfx/scaler/scaler.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "../config.h"
|
|
#endif
|
|
|
|
#if defined(HAVE_NETWORKING)
|
|
#include "../core_updater_list.h"
|
|
#endif
|
|
|
|
#include "../playlist.h"
|
|
|
|
/* Required for task_push_core_backup() */
|
|
#include "../core_backup.h"
|
|
|
|
#if defined(HAVE_OVERLAY)
|
|
#include "../input/input_overlay.h"
|
|
#endif
|
|
|
|
RETRO_BEGIN_DECLS
|
|
|
|
#ifdef HAVE_BLUETOOTH
|
|
bool task_push_bluetooth_scan(retro_task_callback_t cb);
|
|
#endif
|
|
|
|
|
|
typedef struct nbio_buf
|
|
{
|
|
void *buf;
|
|
char *path;
|
|
unsigned bufsize;
|
|
} nbio_buf_t;
|
|
|
|
/* Shared per-frame I/O window (implementation and rationale in
|
|
* task_file_transfer.c). A handler that performs bounded work per
|
|
* gather claims a share with task_nbio_slice_open(), consults
|
|
* task_nbio_slice_within_budget() between work items, and charges
|
|
* back what it actually spent with task_nbio_slice_close(). The
|
|
* window is shared by every participating task in a gather - file
|
|
* transfers, the content scanner - rather than handed to each one
|
|
* separately, because a per-task slice multiplies with the task
|
|
* count. Every open grants a floor of one work item so a queue
|
|
* whose window is already spent still makes progress. Under a
|
|
* threaded task queue each task simply gets a whole slice: there is
|
|
* no frame to protect there, and a shared static across threads
|
|
* would be a race for no benefit. */
|
|
typedef struct
|
|
{
|
|
retro_time_t start; /* when this task's work began */
|
|
retro_time_t allowance; /* usec this task may spend in it */
|
|
uint8_t floor; /* the guaranteed first work item */
|
|
} nbio_budget_t;
|
|
|
|
void task_nbio_slice_open(nbio_budget_t *b);
|
|
void task_nbio_slice_close(nbio_budget_t *b);
|
|
/* Signature matches data_transfer's within-budget callback; the
|
|
* @avail / @len arguments are unused. */
|
|
bool task_nbio_slice_within_budget(void *ud, size_t avail, size_t len);
|
|
|
|
/* Generic progress_cb that forwards a task's progress (0-100) to the
|
|
* platform's window/taskbar progress indicator (e.g. ITaskbarList3 on
|
|
* Win32). Set this on any task whose progress should be reflected on
|
|
* the taskbar -- aggregating tasks (e.g. the Core Updater's outer
|
|
* task) need to do this manually because their inner http transfers
|
|
* run muted and so their own progress callbacks never fire.
|
|
*
|
|
* Available regardless of HAVE_NETWORKING: implementation lives in
|
|
* task_file_transfer.c so non-network long-running tasks (manual
|
|
* content scan, core backup, ...) can use it too. */
|
|
void task_window_progress_cb(retro_task_t *task);
|
|
|
|
#ifdef HAVE_NETWORKING
|
|
#include <net/net_http.h>
|
|
typedef struct
|
|
{
|
|
char *data;
|
|
/* Response headers, one block of NUL-terminated "Name: value"
|
|
* lines ending in an empty line; walk with net_http_header_next().
|
|
* Owned here, freed with free(). */
|
|
char *headers;
|
|
size_t len;
|
|
int status;
|
|
} http_transfer_data_t;
|
|
|
|
void *task_push_http_transfer(const char *url, bool mute, const char *type,
|
|
retro_task_callback_t cb, void *userdata);
|
|
|
|
void *task_push_http_transfer_with_user_agent(const char *url, bool mute, const char *type,
|
|
const char *user_agent, retro_task_callback_t cb, void *userdata);
|
|
|
|
void *task_push_http_transfer_with_headers(const char *url, bool mute, const char *type,
|
|
const char *headers, retro_task_callback_t cb, void *user_data);
|
|
|
|
void *task_push_http_post_transfer(const char *url, const char *post_data, bool mute, const char *type,
|
|
retro_task_callback_t cb, void *userdata);
|
|
|
|
void *task_push_http_post_transfer_with_user_agent(const char *url, const char *post_data, bool mute,
|
|
const char *type, const char *user_agent, retro_task_callback_t cb, void *user_data);
|
|
|
|
void *task_push_http_post_transfer_with_headers(const char *url, const char *post_data, bool mute,
|
|
const char *type, const char *headers, retro_task_callback_t cb, void *user_data);
|
|
|
|
void *task_push_http_transfer_with_content(const char *url, const char *method,
|
|
const void *content, size_t content_len, const char *content_type, bool mute,
|
|
bool headers_accept_err, const char *headers,
|
|
retro_task_callback_t cb, void *user_data);
|
|
|
|
void *task_push_webdav_stat(const char *url, bool mute, const char *headers,
|
|
retro_task_callback_t cb, void *userdata);
|
|
void *task_push_webdav_mkdir(const char *url, bool mute, const char *headers,
|
|
retro_task_callback_t cb, void *userdata);
|
|
/* PUT a body of @len bytes pulled from @source as the socket takes
|
|
* them, holding one send buffer rather than the whole file. @rewind
|
|
* restarts the body for a replay on a fresh connection; NULL means the
|
|
* request is never replayed. */
|
|
void *task_push_webdav_put_stream(const char *url, net_http_source_t source,
|
|
net_http_source_rewind_t rewind, void *source_data, size_t len, bool mute,
|
|
const char *headers, retro_task_callback_t cb, void *user_data);
|
|
void *task_push_webdav_delete(const char *url, bool mute, const char *headers,
|
|
retro_task_callback_t cb, void *userdata);
|
|
void *task_push_webdav_move(const char *url, const char *dest, bool mute, const char *headers,
|
|
retro_task_callback_t cb, void *userdata);
|
|
void *task_push_webdav_copy(const char *url, const char *dest, bool mute, const char *headers,
|
|
retro_task_callback_t cb, void *userdata);
|
|
|
|
bool task_push_wifi_scan(retro_task_callback_t cb);
|
|
bool task_push_wifi_enable(retro_task_callback_t cb);
|
|
bool task_push_wifi_disable(retro_task_callback_t cb);
|
|
bool task_push_wifi_disconnect(retro_task_callback_t cb);
|
|
bool task_push_wifi_connect(retro_task_callback_t cb, void*);
|
|
|
|
bool task_push_netplay_lan_scan(void (*cb)(const void*), unsigned timeout);
|
|
|
|
bool task_push_netplay_crc_scan(uint32_t crc, const char *content,
|
|
const char *subsystem, const char *core, const char *hostname);
|
|
bool task_push_netplay_content_reload(const char *hostname);
|
|
|
|
bool task_push_netplay_nat_traversal(void *data, uint16_t port);
|
|
bool task_push_netplay_nat_close(void *data);
|
|
|
|
/* Core updater tasks */
|
|
|
|
void *task_push_get_core_updater_list(
|
|
core_updater_list_t* core_list, bool mute, bool refresh_menu);
|
|
|
|
/* NOTE: If CRC is set to 0, CRC of local core file
|
|
* will be calculated automatically */
|
|
void *task_push_core_updater_download(
|
|
core_updater_list_t* core_list,
|
|
const char *filename, uint32_t crc, bool mute,
|
|
bool auto_backup, size_t auto_backup_history_size,
|
|
const char *path_dir_libretro,
|
|
const char *path_dir_core_assets);
|
|
void task_push_update_installed_cores(
|
|
bool auto_backup, size_t auto_backup_history_size,
|
|
const char *path_dir_libretro,
|
|
const char *path_dir_core_assets);
|
|
#if defined(ANDROID)
|
|
void *task_push_play_feature_delivery_core_install(
|
|
core_updater_list_t* core_list,
|
|
const char *filename,
|
|
bool mute);
|
|
void task_push_play_feature_delivery_switch_installed_cores(
|
|
const char *path_dir_libretro,
|
|
const char *path_libretro_info);
|
|
#endif
|
|
|
|
bool task_push_pl_entry_thumbnail_download(
|
|
const char *system,
|
|
playlist_t *playlist,
|
|
unsigned idx,
|
|
bool overwrite,
|
|
bool mute);
|
|
|
|
#ifdef HAVE_MENU
|
|
bool task_push_pl_thumbnail_download(
|
|
const char *system,
|
|
const playlist_config_t *playlist_config,
|
|
const char *dir_thumbnails);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(HAVE_KEYCHAIN) && defined(HAVE_CRYPTO) && defined(HAVE_CONFIGFILE)
|
|
/* Unlocks a keychain moved from another machine with @passphrase, or
|
|
* sets it as the keychain's passphrase; empty removes the passphrase.
|
|
* The key derivation runs as a task, the result is a notification. */
|
|
bool task_push_keychain_passphrase(const char *passphrase);
|
|
#endif
|
|
|
|
/* Core backup/restore tasks */
|
|
|
|
/* NOTE 1: If CRC is set to 0, CRC of core_path file will
|
|
* be calculated automatically
|
|
* NOTE 2: If core_display_name is set to NULL, display
|
|
* name will be determined automatically
|
|
* > core_display_name *must* be set to a non-empty
|
|
* string if task_push_core_backup() is *not* called
|
|
* on the main thread
|
|
* NOTE 3: @cb, if set, is called with @user_data when the
|
|
* task retires, on the thread that retires the queue, once
|
|
* for every task this returns */
|
|
void *task_push_core_backup(
|
|
const char *core_path, const char *core_display_name,
|
|
uint32_t crc, enum core_backup_mode backup_mode,
|
|
size_t auto_backup_history_size,
|
|
const char *dir_core_assets, bool mute,
|
|
retro_task_callback_t cb, void *user_data);
|
|
|
|
/* An automatic backup that also installs a new core: @staged_path,
|
|
* extracted on the same volume as @core_path, replaces @core_path,
|
|
* and the core it replaces is moved into the backups as it is rather
|
|
* than compressed into them; where it cannot be moved it is copied as
|
|
* task_push_core_backup() would. @cb gets an error exactly when the
|
|
* new core could not be installed. */
|
|
void *task_push_core_backup_install(
|
|
const char *core_path, const char *staged_path,
|
|
const char *core_display_name, uint32_t crc,
|
|
size_t auto_backup_history_size,
|
|
const char *dir_core_assets, bool mute,
|
|
retro_task_callback_t cb, void *user_data);
|
|
|
|
/* NOTE: If 'core_loaded' is true, menu stack should be
|
|
* flushed if task_push_core_restore() returns true */
|
|
bool task_push_core_restore(const char *backup_path,
|
|
const char *dir_libretro,
|
|
bool *core_loaded);
|
|
|
|
bool task_push_pl_manager_reset_cores(const playlist_config_t *playlist_config);
|
|
bool task_push_pl_manager_clean_playlist(const playlist_config_t *playlist_config);
|
|
|
|
/* downscale_cap: if non-zero, the decoded image is capped to this many
|
|
* pixels on its longest side before upload, preserving aspect ratio.
|
|
* The sidebar thumbnail and the fullscreen view share one texture -
|
|
* going fullscreen only raises a flag, it never re-requests the image
|
|
* - so the cap has to be what the larger view can use, i.e. the
|
|
* display size. 0 disables it, for callers whose image is already
|
|
* display-sized (wallpaper) or drawn at a fixed small size (icons). */
|
|
bool task_push_image_load(const char *fullpath,
|
|
bool supports_rgba, unsigned upscale_threshold,
|
|
unsigned downscale_cap,
|
|
retro_task_callback_t cb, void *userdata);
|
|
|
|
enum task_image_load_flags
|
|
{
|
|
/* Decode in R,G,B,A memory order rather than ARGB words */
|
|
TASK_IMAGE_LOAD_RGBA = (1 << 0),
|
|
/* The caller uploads the image and takes RGBA half floats - linear
|
|
* scRGB, ->fp16 set - which an HDR video still is then decoded as
|
|
* wherever the driver offers IMAGE_PIXFMT_FP16. Such a still
|
|
* is never resampled: upscale_threshold and downscale_cap pass it
|
|
* by. Without the flag no load returns half floats. */
|
|
TASK_IMAGE_LOAD_HDR = (1 << 1)
|
|
};
|
|
|
|
/* task_push_image_load with its options as TASK_IMAGE_LOAD_* bits. */
|
|
bool task_push_image_load_ex(const char *fullpath, unsigned load_flags,
|
|
unsigned upscale_threshold, unsigned downscale_cap,
|
|
retro_task_callback_t cb, void *userdata);
|
|
|
|
/* For an image-load task whose file is a video (WEBM/MP4): take
|
|
* ownership of the decoder stream the still-frame decode left open,
|
|
* positioned just past the first displayed frame, together with the
|
|
* data_transfer whose buffer the stream borrows (its fill may still
|
|
* be in flight; the adopter pumps it on). Only valid during the
|
|
* task's completion callback (the task owns both until then and frees
|
|
* them right after). On success the caller must eventually close the
|
|
* stream with image_transfer_anim_stream_free(*stream, *type) and then
|
|
* release the buffer with data_transfer_free(*xfer_owner), in that
|
|
* order. Returns false (and takes nothing) for non-image tasks,
|
|
* non-video images, or when no stream is held. */
|
|
struct data_transfer;
|
|
bool task_image_detach_video_stream(retro_task_t *task,
|
|
void **stream, enum image_type_enum *type,
|
|
struct data_transfer **xfer_owner, void **buf, size_t *len);
|
|
|
|
/* What the image task learned about a PNG from the buffer it read:
|
|
* 1 the file is an APNG, 0 conclusively a still PNG, -1 unknown
|
|
* (not an image task, not a PNG, or the read did not complete).
|
|
* Same validity window as the detach above: the task's completion
|
|
* callback, while the task still owns its buffer. Lets the caller
|
|
* skip re-opening the file to answer a question the task's bytes
|
|
* already answer. */
|
|
int task_image_png_probe(retro_task_t *task);
|
|
|
|
/* A set of stills decoded together, across the cores at once: @n
|
|
* whole files at @paths, decoded and resampled as
|
|
* task_push_image_load_ex does each. On the main thread @cb is then
|
|
* called once per file, in order, with the image (NULL when the file
|
|
* could not be decoded or the set was cancelled; the caller's to free
|
|
* otherwise), the PNG verdict task_image_png_probe would give, and
|
|
* that file's @item_uds entry. @tag is the caller's, for
|
|
* task_image_set_tag. Video files take task_push_image_load_ex: a set
|
|
* has no decoder stream to hand over. The set decodes in one go on the
|
|
* task worker, so it is for a threaded task queue only; without one it
|
|
* would hold the main thread for all of it. */
|
|
typedef void (*task_image_set_cb_t)(struct texture_image *img,
|
|
int png_probe, void *item_ud);
|
|
bool task_push_image_load_set(const char *const *paths,
|
|
void *const *item_uds, unsigned n, unsigned load_flags,
|
|
unsigned upscale_threshold, unsigned downscale_cap,
|
|
task_image_set_cb_t cb, uint64_t tag);
|
|
|
|
/* The @tag an image set task was pushed with; false for any other
|
|
* task. Safe from a task_queue_find predicate. */
|
|
bool task_image_set_tag(retro_task_t *task, uint64_t *tag);
|
|
|
|
/* A content scan's outcome, handed to its callback as task_data and
|
|
* valid only during the call. Counts cover every playlist the scan
|
|
* writes; errors are files it could not read. */
|
|
typedef struct
|
|
{
|
|
unsigned added;
|
|
unsigned duplicates;
|
|
unsigned unmatched;
|
|
unsigned errors;
|
|
bool failed;
|
|
} task_dbscan_result_t;
|
|
|
|
#ifdef HAVE_LIBRETRODB
|
|
/* Scans @fullpath, a directory or a single file, against the content
|
|
* databases; the database and playlist directories come from the
|
|
* settings. @cb gets @user_data. False while a chain runs. */
|
|
bool task_push_dbscan(const char *fullpath, retro_task_callback_t cb,
|
|
void *user_data);
|
|
#endif
|
|
|
|
struct manual_content_scan_overrides;
|
|
|
|
enum task_dbscan_item_kind
|
|
{
|
|
TASK_DBSCAN_ITEM_PATH = 0, /* --scan */
|
|
TASK_DBSCAN_ITEM_REFRESH, /* --scan-refresh */
|
|
TASK_DBSCAN_ITEM_REFRESH_ALL /* --scan-refresh-all, Refresh All */
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
char *arg; /* as typed; NULL for REFRESH_ALL */
|
|
struct manual_content_scan_overrides *overrides; /* NULL: none */
|
|
enum task_dbscan_item_kind kind;
|
|
} task_dbscan_item_t;
|
|
|
|
enum task_dbscan_outcome
|
|
{
|
|
TASK_DBSCAN_RAN = 0, /* res holds the counts */
|
|
TASK_DBSCAN_FAILED,
|
|
TASK_DBSCAN_SKIPPED
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
unsigned ran; /* scans that ran and did not fail */
|
|
unsigned added; /* of those, the ones that added an entry */
|
|
unsigned failed;
|
|
unsigned skipped;
|
|
bool cancelled;
|
|
} task_dbscan_chain_result_t;
|
|
|
|
typedef void (*task_dbscan_item_cb_t)(const char *name,
|
|
enum task_dbscan_outcome outcome,
|
|
const task_dbscan_result_t *res, void *user_data);
|
|
typedef void (*task_dbscan_chain_cb_t)(
|
|
const task_dbscan_chain_result_t *res, void *user_data);
|
|
|
|
/* Runs @items in order, one task at a time: each step is pushed from
|
|
* the last one's callback, and a cancelled task ends the run. The
|
|
* chain owns @items from the call, whatever it returns. @item_cb: once
|
|
* per scan, failed item or skipped playlist; @done_cb: once at the end,
|
|
* from a task callback. @res is valid during the call only. False,
|
|
* calling neither, if out of memory or while a chain or a manual scan
|
|
* runs. Main thread only. */
|
|
bool task_push_dbscan_chain(task_dbscan_item_t *items, size_t count,
|
|
task_dbscan_item_cb_t item_cb, task_dbscan_chain_cb_t done_cb,
|
|
void *user_data);
|
|
|
|
/* Main thread only. */
|
|
bool task_dbscan_chain_is_running(void);
|
|
|
|
/* False while task_push_dbscan_chain() would refuse: a chain or a
|
|
* manual scan runs. Main thread only. */
|
|
bool task_dbscan_chain_can_start(void);
|
|
/* A scan asked for while a chain runs would use the settings the chain
|
|
* last loaded: true, with the message shown, when it must be refused. */
|
|
bool task_dbscan_chain_refuse(void);
|
|
/* The same for a new chain, which also waits for a running scan. */
|
|
bool task_dbscan_chain_refuse_start(void);
|
|
|
|
bool task_push_manual_content_scan(
|
|
bool do_menu_refresh,
|
|
retro_task_callback_t user_cb, void *user_data);
|
|
|
|
#ifdef HAVE_OVERLAY
|
|
bool task_push_overlay_load_default(
|
|
retro_task_callback_t cb,
|
|
const char *overlay_path,
|
|
bool is_osk,
|
|
void *user_data);
|
|
#endif
|
|
|
|
/* Open a streaming applier for the patch a load would apply, resolved
|
|
* with patch_content's own selection rules. NULL means "no streamable
|
|
* patch": load and call patch_content as before. See task_patch.c. */
|
|
struct patch_stream;
|
|
struct patch_stream *patch_content_stream_open(
|
|
bool is_ips_pref,
|
|
bool is_bps_pref,
|
|
bool is_ups_pref,
|
|
bool is_xdelta_pref,
|
|
const char *name_ips,
|
|
const char *name_bps,
|
|
const char *name_ups,
|
|
const char *name_xdelta,
|
|
size_t src_len,
|
|
void **patch_data,
|
|
const char **patch_path);
|
|
|
|
bool patch_content(
|
|
bool is_ips_pref,
|
|
bool is_bps_pref,
|
|
bool is_ups_pref,
|
|
bool is_xdelta_pref,
|
|
const char *name_ips,
|
|
const char *name_bps,
|
|
const char *name_ups,
|
|
const char *name_xdelta,
|
|
uint8_t **buf,
|
|
void *data);
|
|
|
|
bool task_check_decompress(const char *source_file);
|
|
|
|
void *task_push_decompress(
|
|
const char *source_file,
|
|
const char *target_dir,
|
|
const char *target_file,
|
|
const char *subdir,
|
|
const char *valid_ext,
|
|
retro_task_callback_t cb,
|
|
void *user_data,
|
|
void *frontend_userdata,
|
|
bool mute);
|
|
|
|
void task_file_load_handler(retro_task_t *task);
|
|
|
|
bool take_screenshot(
|
|
const char *screenshot_dir,
|
|
const char *path, bool silence,
|
|
bool has_valid_framebuffer, bool fullpath, bool use_thread);
|
|
|
|
/* What take_screenshot_notify()'s callback is told, as its task_data */
|
|
struct screenshot_result
|
|
{
|
|
const char *path;
|
|
/* The PNG, base64, read back on the task's thread once written; NULL
|
|
* past SCREENSHOT_IMAGE_MAX, for another format, or written without a
|
|
* task */
|
|
const char *png_base64;
|
|
size_t png_base64_len;
|
|
/* the picture's size */
|
|
unsigned width;
|
|
unsigned height;
|
|
};
|
|
|
|
/* The largest PNG handed back to the callback */
|
|
#define SCREENSHOT_IMAGE_MAX (4 * 1024 * 1024)
|
|
|
|
/* @cb, when it returns true, is told once the screenshot is written:
|
|
* task_data is a struct screenshot_result, and error is set if it could
|
|
* not be. Without @use_thread that is before this returns, with no task
|
|
* and no image. */
|
|
bool take_screenshot_notify(
|
|
const char *screenshot_dir,
|
|
const char *path, bool silence,
|
|
bool has_valid_framebuffer, bool fullpath, bool use_thread,
|
|
retro_task_callback_t cb, void *user_data);
|
|
|
|
/* The frame on screen, scaled to fit @max_width by @max_height and never
|
|
* up, as a PNG for @cb alone: struct screenshot_result's png_base64,
|
|
* with an empty path. Nothing is written and nothing shown; always a
|
|
* task, so @cb runs on a later frame. */
|
|
bool take_frame_notify(unsigned max_width, unsigned max_height,
|
|
retro_task_callback_t cb, void *user_data);
|
|
|
|
bool event_load_save_files(bool is_sram_load_disabled);
|
|
|
|
bool content_savefile_is_live(const char *path);
|
|
|
|
bool event_save_files(bool sram_used, bool compress_files,
|
|
const char *path_cheat_database);
|
|
|
|
void path_init_savefile_rtc(const char *savefile_path);
|
|
|
|
void *savefile_ptr_get(void);
|
|
|
|
void path_init_savefile_new(void);
|
|
|
|
/* Autoconfigure tasks */
|
|
|
|
/**
|
|
* Flags controlling how a device is autoconfigured.
|
|
*
|
|
* @see input_autoconfigure_connect_ex()
|
|
*/
|
|
enum autoconfig_handle_flags
|
|
{
|
|
AUTOCONF_FLAG_AUTOCONFIG_ENABLED = (1 << 0),
|
|
AUTOCONF_FLAG_SUPPRESS_NOTIFICATIONS = (1 << 1),
|
|
AUTOCONF_FLAG_SUPPRESS_FAILURE_NOTIF = (1 << 2),
|
|
/**
|
|
* Device has a known, authoritative mapping, so fallback profiles are treated as matches.
|
|
*
|
|
* This is used in the SDL3 driver, for instance, where mappings are provided directly.
|
|
*/
|
|
AUTOCONF_FLAG_HAS_STANDARD_MAPPING = (1 << 3)
|
|
};
|
|
|
|
void input_autoconfigure_blissbox_override_handler(
|
|
int vid, int pid, char *device_name, size_t len);
|
|
/* From a thread other than the main one, a connect or disconnect is
|
|
* handed to the main thread and returns true once it is queued; what
|
|
* it does is decided there. */
|
|
bool input_autoconfigure_connect(
|
|
const char *name,
|
|
const char *display_name,
|
|
const char *phys,
|
|
const char *driver,
|
|
unsigned port,
|
|
unsigned vid,
|
|
unsigned pid);
|
|
bool input_autoconfigure_connect_ex(
|
|
const char *name,
|
|
const char *display_name,
|
|
const char *phys,
|
|
const char *driver,
|
|
unsigned port,
|
|
unsigned vid,
|
|
unsigned pid,
|
|
uint8_t flags);
|
|
bool input_autoconfigure_disconnect(
|
|
unsigned port, const char *name);
|
|
bool input_autoconfigure_reconnect(unsigned port);
|
|
#if defined(HAVE_TEST_DRIVERS) || defined(HAVE_OPENXR)
|
|
bool input_autoconfigure_pending(void);
|
|
#endif
|
|
|
|
void set_save_state_in_background(bool state);
|
|
void set_save_state_disable_undo(bool disable);
|
|
|
|
#ifdef HAVE_CDROM
|
|
void task_push_cdrom_dump(const char *drive);
|
|
#endif
|
|
|
|
/* Menu explore tasks */
|
|
#if defined(HAVE_MENU) && defined(HAVE_LIBRETRODB)
|
|
bool task_push_menu_explore_init(const char *directory_playlist,
|
|
const char *directory_database);
|
|
bool menu_explore_init_in_progress(void *data);
|
|
void menu_explore_cancel_init_task(void);
|
|
|
|
/* Menu database info tasks
|
|
* (cache accessors with database types live in database_info.h) */
|
|
void menu_dbinfo_cache_free(void);
|
|
bool menu_dbinfo_load_in_progress(void *data);
|
|
void menu_dbinfo_cancel_task(void);
|
|
bool task_push_dbinfo_load(const char *path, const char *query);
|
|
#endif
|
|
|
|
extern const char* const input_builtin_autoconfs[];
|
|
|
|
/* cloud sync tasks */
|
|
void task_push_cloud_sync_update_driver(void);
|
|
/* The cb parameter is the callback that's called when the sync is done.
|
|
* Its error argument is non-NULL when the sync failed or finished with
|
|
* failures or conflicts. Returns false if no sync was queued. */
|
|
bool task_push_cloud_sync(retro_task_callback_t cb, void *user_data);
|
|
void task_push_cloud_sync_resolve_keep_local(void);
|
|
void task_push_cloud_sync_resolve_keep_server(void);
|
|
|
|
RETRO_END_DECLS
|
|
|
|
#endif
|