mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-16 16:00:30 +02:00
The libretro-common submodule pinned the standalone repository at 76a3d54. It is replaced by an in-tree copy of RetroArch master (b655a20) holding only what the core uses: the VFS, file, string, encoding, compat and time sources it already built, the headers they and the core include, the threading set - rthreads, retro_atomic, retro_spsc and retro_waitable_spsc, mpsc_stack, retro_triple_buffer, retro_eventcount, retro_asym_eventcount, retro_procbarrier and tpool, with features_cpu and rstrtod, which they need - and the codecs that replace the bundled zlib, zstd, libchdr, libzip and libpng: rinflate and rdeflate, rzstd, rchd with its LZMA and FLAC decoders, rzip_archive, rpng and crc32. stdstring.c, which nothing calls, is no longer built. The threading sources are always built, by both the static Makefile and CMake; the VFS set stays behind HAVE_LIBRETRO_VFS as before. The codecs are built by the change that switches the core over to them.
629 lines
29 KiB
C
629 lines
29 KiB
C
/* Copyright (C) 2010-2020 The RetroArch team
|
|
*
|
|
* ---------------------------------------------------------------------------------------
|
|
* The following license statement only applies to this file (image.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 __RARCH_IMAGE_CONTEXT_H
|
|
#define __RARCH_IMAGE_CONTEXT_H
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#include <retro_common_api.h>
|
|
|
|
#include <boolean.h>
|
|
|
|
RETRO_BEGIN_DECLS
|
|
|
|
enum image_process_code
|
|
{
|
|
IMAGE_PROCESS_ERROR = -2,
|
|
IMAGE_PROCESS_ERROR_END = -1,
|
|
IMAGE_PROCESS_NEXT = 0,
|
|
IMAGE_PROCESS_END = 1,
|
|
/* The transfer cannot advance until more of the file has been read
|
|
* into the buffer (see image_transfer_set_avail); nothing was
|
|
* consumed. Only the video still decoders (WEBM, MP4) return
|
|
* this, and only after the caller opts in by setting an avail
|
|
* short of the full length. */
|
|
IMAGE_PROCESS_WAIT = 2
|
|
};
|
|
|
|
struct texture_compressed; /* defined below, after enum image_type_enum */
|
|
|
|
struct texture_image
|
|
{
|
|
uint32_t *pixels;
|
|
unsigned width;
|
|
unsigned height;
|
|
bool supports_rgba;
|
|
/* When true, ->pixels holds packed XRGB2101010 (10-bit per channel,
|
|
* bits [29:20]=R [19:10]=G [9:0]=B) rather than 8-bit RGBA/BGRA. Only
|
|
* uploaded as such by drivers that answer TEXTURE_GPU_FORMAT_RGB10A2;
|
|
* others get an 8-bit copy via image_texture_narrow_10bit(). */
|
|
bool pix10;
|
|
/* When true, ->pixels holds RGBA half floats, eight bytes a pixel in
|
|
* memory order R,G,B,A - linear light, which no 8-bit encoding
|
|
* covers - rather than 32-bit texels. Only uploaded by drivers that
|
|
* answer TEXTURE_GPU_FORMAT_RGBA16F; exclusive with ->pix10. */
|
|
bool fp16;
|
|
/* Optional GPU-native compressed payload (BCn). When non-NULL a
|
|
* capable driver may upload it directly and leave ->pixels NULL;
|
|
* image_texture_realize_rgba() decodes to ->pixels on demand for
|
|
* drivers that cannot sample the format. */
|
|
struct texture_compressed *compressed;
|
|
};
|
|
|
|
enum image_type_enum
|
|
{
|
|
IMAGE_TYPE_NONE = 0,
|
|
IMAGE_TYPE_PNG,
|
|
IMAGE_TYPE_JPEG,
|
|
IMAGE_TYPE_BMP,
|
|
IMAGE_TYPE_TGA,
|
|
IMAGE_TYPE_WEBP,
|
|
IMAGE_TYPE_DDS,
|
|
IMAGE_TYPE_WEBM,
|
|
IMAGE_TYPE_MP4
|
|
};
|
|
|
|
#define IMAGE_MAX_MIPS 16
|
|
|
|
/* Several MIPS toolchains (RS90/Dingux, PSP, PS2, ...) predefine the bare
|
|
* macro `mips` as 1 in GNU mode, which collides with the `mips` field of
|
|
* struct texture_compressed below (and every `->mips` access downstream).
|
|
* RA never uses the legacy macro (it uses __mips__), so drop it here. */
|
|
#ifdef mips
|
|
#undef mips
|
|
#endif
|
|
|
|
/* GPU-native compressed texture formats (block-compressed). Producers
|
|
* (currently the DDS loader) report one of these when a texture can be
|
|
* uploaded to the GPU as-is; capable drivers skip the CPU decode to
|
|
* RGBA8 entirely. Extend with ETC2 or ASTC entries later. */
|
|
enum texture_gpu_format
|
|
{
|
|
TEXTURE_GPU_FORMAT_NONE = 0,
|
|
TEXTURE_GPU_FORMAT_BC1, /* DXT1 */
|
|
TEXTURE_GPU_FORMAT_BC2, /* DXT3 */
|
|
TEXTURE_GPU_FORMAT_BC3, /* DXT5 */
|
|
TEXTURE_GPU_FORMAT_BC4, /* RGTC1 (1 channel) */
|
|
TEXTURE_GPU_FORMAT_BC5, /* RGTC2 (2 channel) */
|
|
TEXTURE_GPU_FORMAT_BC6H_UF, /* BPTC unsigned HDR */
|
|
TEXTURE_GPU_FORMAT_BC6H_SF, /* BPTC signed HDR */
|
|
TEXTURE_GPU_FORMAT_BC7, /* BPTC LDR */
|
|
/* Not a compressed payload and never on a texture_compressed:
|
|
* packed XRGB2101010 in ->pixels, flagged by ->pix10. Asked of
|
|
* supports_texture_format to learn whether the driver's load and
|
|
* in-place update sample it as 10-bit rather than reading its words
|
|
* as 8-bit texels. */
|
|
TEXTURE_GPU_FORMAT_RGB10A2,
|
|
/* Likewise uncompressed: RGBA half floats in ->pixels, flagged by
|
|
* ->fp16, eight bytes a pixel in memory order R,G,B,A. Asked of
|
|
* supports_texture_format to learn whether the driver's load and
|
|
* in-place update keep them as floats. */
|
|
TEXTURE_GPU_FORMAT_RGBA16F,
|
|
/* Asked of supports_texture_format to learn whether an RGBA16F
|
|
* texture drawn in the menu or over content is shown as linear
|
|
* scRGB - 1.0 at 80 nits, the 709 primaries - rather than as an
|
|
* SDR-encoded one: true only while the output is HDR. */
|
|
TEXTURE_GPU_FORMAT_SCRGB
|
|
};
|
|
|
|
/* Numeric mip layout reported by a loader without decoding. Offsets are
|
|
* byte offsets from the start of the source file buffer. */
|
|
struct image_gpu_layout
|
|
{
|
|
enum texture_gpu_format format;
|
|
unsigned num_mips;
|
|
unsigned width[IMAGE_MAX_MIPS];
|
|
unsigned height[IMAGE_MAX_MIPS];
|
|
size_t offset[IMAGE_MAX_MIPS];
|
|
size_t size[IMAGE_MAX_MIPS];
|
|
};
|
|
|
|
struct texture_mip
|
|
{
|
|
const void *data;
|
|
unsigned width;
|
|
unsigned height;
|
|
size_t size;
|
|
};
|
|
|
|
/* Owned, self-contained compressed payload carried on a texture_image.
|
|
* storage holds a private copy of the source file (so the mip pointers
|
|
* outlive the loader's buffer) and doubles as the input for the CPU
|
|
* decode fallback in image_texture_realize_rgba(). */
|
|
struct texture_compressed
|
|
{
|
|
void *storage;
|
|
size_t storage_len;
|
|
struct texture_mip *mips;
|
|
unsigned num_mips;
|
|
enum texture_gpu_format format;
|
|
enum image_type_enum type; /* for the CPU-decode fallback */
|
|
};
|
|
|
|
enum image_type_enum image_texture_get_type(const char *path);
|
|
|
|
/* ---- The still loader ----------------------------------------------
|
|
* One decoder for every still the frontend or a core takes from a
|
|
* file: the bytes are the caller's, read whole or still arriving, and
|
|
* the decode runs in steps that stop at a time budget, at an abort
|
|
* hook, or at the byte frontier. image_texture_load() is this loader
|
|
* run to completion in one call. */
|
|
|
|
/* What the caller takes of a still, asked of it once by whoever knows
|
|
* (the video driver, a core's own renderer) and handed down. Zero is
|
|
* the ordinary 8-bit image, ARGB words. */
|
|
typedef struct
|
|
{
|
|
/* Memory-order R,G,B,A rather than ARGB words */
|
|
bool rgba;
|
|
/* XRGB2101010 where the file has more than 8 bits a channel */
|
|
bool want_10bit;
|
|
/* Linear scRGB half floats where the source is HDR (video stills) */
|
|
bool want_fp16;
|
|
/* A GPU-native compressed payload (BCn) as it lies in the file,
|
|
* rather than its CPU decode; the caller then samples it as such or
|
|
* decodes it later with image_texture_realize_rgba() */
|
|
bool want_compressed;
|
|
} image_texture_request_t;
|
|
|
|
typedef struct image_loader image_loader_t;
|
|
|
|
enum image_loader_state
|
|
{
|
|
IMAGE_LOADER_ERROR = -1,
|
|
IMAGE_LOADER_RUNNING, /* more steps to take */
|
|
IMAGE_LOADER_WAIT, /* needs bytes not yet available */
|
|
IMAGE_LOADER_DONE /* image_loader_finish() has the image */
|
|
};
|
|
|
|
/* Whether a decode of @type may start on the first @avail bytes of
|
|
* a file still being read: the header is resident for the decoders
|
|
* that paint from a prefix (PNG, JPEG, TGA, BMP, the video stills),
|
|
* the still's chunk is whole for WEBP. False means wait for the whole
|
|
* file. */
|
|
bool image_loader_ready(enum image_type_enum type,
|
|
const void *buf, size_t avail);
|
|
|
|
/* A loader for a still of @type. @req may be NULL for the ordinary
|
|
* image. NULL when out of memory. */
|
|
image_loader_t *image_loader_new(enum image_type_enum type,
|
|
const image_texture_request_t *req);
|
|
|
|
/* The file's bytes: @buf of @len bytes once fully read, of which
|
|
* @avail are resident now (@len for a whole file). The buffer is the
|
|
* caller's and stays where it is until the loader is freed. False
|
|
* when the decoder refused the start. */
|
|
bool image_loader_start(image_loader_t *l, const void *buf, size_t len,
|
|
size_t avail);
|
|
|
|
/* More of the file has arrived: the first @avail bytes are resident
|
|
* ((size_t)-1: all of them). */
|
|
void image_loader_set_avail(image_loader_t *l, size_t avail);
|
|
|
|
/* Asked between steps of the decode: true abandons it, and the loader
|
|
* reports IMAGE_LOADER_ERROR. For decodes that must stop promptly at
|
|
* shutdown or once their result is no longer wanted. */
|
|
void image_loader_set_abort(image_loader_t *l,
|
|
bool (*should_abort)(void *ud), void *ud);
|
|
|
|
/* Decode until @now's clock reaches @deadline, at least one iteration
|
|
* and, between a transfer and its pixels, never both in one step;
|
|
* @now NULL runs until the decode is done, aborts, or wants bytes. */
|
|
enum image_loader_state image_loader_step(image_loader_t *l,
|
|
int64_t (*now)(void), int64_t deadline);
|
|
|
|
/* The decoded image, the loader's no more: @img's pixels or compressed
|
|
* payload are the caller's to free with image_texture_free(). Only
|
|
* after IMAGE_LOADER_DONE. */
|
|
bool image_loader_finish(image_loader_t *l, struct texture_image *img);
|
|
|
|
/* Whether the loader's PNG is animated: 1 yes, 0 a still, -1 unknown
|
|
* (not a PNG, or the file is not wholly resident). */
|
|
int image_loader_png_probe(const image_loader_t *l);
|
|
|
|
/* The animation stream a video still's decode opened, detached for
|
|
* the caller to play on; NULL when there is none. The stream borrows
|
|
* the loader's buffer, which the caller keeps alive for it. */
|
|
void *image_loader_detach_anim_stream(image_loader_t *l);
|
|
|
|
void image_loader_free(image_loader_t *l);
|
|
|
|
/* Resample a decoded still in place: a whole-factor upscale when an
|
|
* edge is under @upscale_threshold, then a box reduction to keep the
|
|
* longer edge within @downscale_cap; 0 skips either. Half-float
|
|
* images are left as they are. In formats/image_texture_scale.c,
|
|
* which brings the scaler with it. */
|
|
bool image_texture_scale(struct texture_image *img,
|
|
unsigned upscale_threshold, unsigned downscale_cap);
|
|
|
|
bool image_texture_load_buffer(struct texture_image *img,
|
|
enum image_type_enum type, void *s, size_t len);
|
|
|
|
/* The loader run to completion over a whole buffer or a file, with
|
|
* @req naming what the caller takes (NULL: the ordinary image). The
|
|
* abort hook is asked between steps; it may be NULL. False leaves
|
|
* @img empty. */
|
|
bool image_texture_load_buffer_request(struct texture_image *img,
|
|
enum image_type_enum type, const void *buf, size_t len,
|
|
const image_texture_request_t *req,
|
|
bool (*should_abort)(void *ud), void *ud);
|
|
bool image_texture_load_request(struct texture_image *img,
|
|
const char *path, const image_texture_request_t *req,
|
|
bool (*should_abort)(void *ud), void *ud);
|
|
|
|
/* image_texture_load_request answering, from the bytes it read, whether
|
|
* the file is an animated PNG: 1 yes, 0 a still, -1 not a PNG or no
|
|
* decode. Spares a caller that keeps an animation's bytes a second
|
|
* read of every still to ask. @png_probe may be NULL. */
|
|
bool image_texture_load_request_ex(struct texture_image *img,
|
|
const char *path, const image_texture_request_t *req,
|
|
bool (*should_abort)(void *ud), void *ud, int *png_probe);
|
|
|
|
/* Run @fn for every index below @n, across the cores at once where
|
|
* there are threads: on Apple over the dispatch pool, elsewhere on
|
|
* threads of its own with the caller working alongside, and in order
|
|
* on one thread where there is only one. Returns once every call has.
|
|
* In formats/image_texture_set.c. */
|
|
void image_texture_set_run(unsigned n,
|
|
void (*fn)(unsigned i, void *ud), void *ud);
|
|
|
|
/* image_texture_set_run with @thread_done called on each thread of
|
|
* the set's own as it finishes, for state it kept per thread - the
|
|
* data_transfer pool above all, which a thread that exits with it
|
|
* full would leave resident for good. Not called on the caller's
|
|
* thread, nor on a dispatch pool's, which live on. May be NULL. */
|
|
void image_texture_set_run_ex(unsigned n,
|
|
void (*fn)(unsigned i, void *ud), void *ud,
|
|
void (*thread_done)(void));
|
|
|
|
/* Decode the @n files @paths name into @imgs together, each as
|
|
* image_texture_load_request does with @req; a path that is NULL,
|
|
* empty or unreadable leaves its image empty. Returns how many
|
|
* decoded. In formats/image_texture_set.c. */
|
|
unsigned image_texture_load_set(const char *const *paths,
|
|
struct texture_image *imgs, unsigned n,
|
|
const image_texture_request_t *req);
|
|
|
|
/* ->pix10 is an ask on the way in and an answer on the way out: set
|
|
* it before the call to have a decoder that can emit XRGB2101010 do
|
|
* so, and read it after to find out whether it did. Clear on entry
|
|
* means the ordinary 8-bit image, as before. */
|
|
bool image_texture_load(struct texture_image *img, const char *path);
|
|
|
|
/* image_texture_load with an abort hook: both decode stages are
|
|
* incremental (one chunk / one pass per step) and @should_abort is
|
|
* asked between steps; returning true abandons the decode, which then
|
|
* fails cleanly. For decodes on worker threads that must stop promptly
|
|
* at shutdown or when their result is no longer wanted. @should_abort
|
|
* may be NULL. */
|
|
bool image_texture_load_ex(struct texture_image *img, const char *path,
|
|
bool (*should_abort)(void *ud), void *ud);
|
|
void image_texture_free(struct texture_image *img);
|
|
|
|
/* Force a CPU decode of a compressed texture_image into ->pixels (RGBA8).
|
|
* No-op returning true if ->pixels is already present. The fallback when
|
|
* a driver cannot sample img->compressed->format. */
|
|
bool image_texture_realize_rgba(struct texture_image *img);
|
|
|
|
/* Narrow a texture_image whose ->pixels hold packed XRGB2101010 down to
|
|
* 8 bits a channel in place (and clear ->pix10), for drivers that cannot
|
|
* sample a 10-bit texture: ARGB8888 words, or memory-order R,G,B,A when
|
|
* ->supports_rgba is set, so ->supports_rgba stays true of the result.
|
|
* No-op unless ->pix10 is set. */
|
|
void image_texture_narrow_10bit(struct texture_image *img);
|
|
|
|
/* Rewrite ->pixels, linear 32-bit texels, in place as GX RGBA8 tiles:
|
|
* the layout the GameCube/Wii GPU samples straight from memory, 4x4
|
|
* tiles of 64 bytes holding the AR halves of a tile's sixteen texels
|
|
* and then their GB halves. ->width and ->height are rounded down to
|
|
* multiples of 4, which the layout requires. Decoders always emit
|
|
* linear images; only a consumer that hands the pixels to the GX
|
|
* itself asks for this. False, with @img untouched, when the four-row
|
|
* scratch cannot be allocated. */
|
|
bool image_texture_tile_gx(struct texture_image *img);
|
|
|
|
/* Write @width x @height linear 32-bit texels, @src (ARGB8888 words,
|
|
* or memory-order R,G,B,A when @rgba), to @dst as GX RGBA8 tiles of a
|
|
* texture rounded up to multiples of 4 a side, the padding clear: the
|
|
* layout image_texture_tile_gx() makes, but in a buffer of its own and
|
|
* keeping every texel. @dst holds image_texture_tile_gx_size() bytes. */
|
|
void image_texture_tile_gx_copy(uint16_t *dst, const uint32_t *src,
|
|
unsigned width, unsigned height, bool rgba);
|
|
|
|
/* The bytes image_texture_tile_gx_copy() writes for @width x @height */
|
|
size_t image_texture_tile_gx_size(unsigned width, unsigned height);
|
|
|
|
/* Image transfer */
|
|
|
|
void image_transfer_free(void *data, enum image_type_enum type);
|
|
|
|
void *image_transfer_new(enum image_type_enum type);
|
|
|
|
bool image_transfer_start(void *data, enum image_type_enum type);
|
|
|
|
void image_transfer_set_buffer_ptr(
|
|
void *data,
|
|
enum image_type_enum type,
|
|
void *ptr,
|
|
size_t len);
|
|
|
|
int image_transfer_process(
|
|
void *data,
|
|
enum image_type_enum type,
|
|
uint32_t **buf,
|
|
size_t len,
|
|
unsigned *width,
|
|
unsigned *height,
|
|
bool supports_rgba);
|
|
|
|
/* Report the GPU-native compressed mip layout of an already-started
|
|
* transfer without decoding. Returns false for formats that must be
|
|
* CPU-decoded (non-DDS, uncompressed DDS, premultiplied, BC4/5/6H). */
|
|
bool image_transfer_get_gpu_layout(
|
|
void *data,
|
|
enum image_type_enum type,
|
|
size_t len,
|
|
struct image_gpu_layout *out);
|
|
|
|
bool image_transfer_iterate(void *data, enum image_type_enum type);
|
|
|
|
/* True when the last image_transfer_iterate stopped because the decoder
|
|
* reached the resident byte frontier declared by
|
|
* image_transfer_set_avail, rather than because the image finished.
|
|
* Both cases return false from iterate, so a caller feeding a growing
|
|
* read MUST consult this before concluding the transfer is complete -
|
|
* treating a wall as completion decodes a partially-gathered image and
|
|
* fails. Always false for types without an avail wall. */
|
|
bool image_transfer_need_more(void *data, enum image_type_enum type);
|
|
|
|
/* Video-to-image transfers (WEBM, MP4) keep their decoder stream open
|
|
* after a successful image_transfer_process, positioned just past the
|
|
* first displayed frame. This takes ownership of that stream so the
|
|
* caller can continue the video as an animation without re-opening the
|
|
* file; the returned handle is the same opaque stream the
|
|
* image_transfer_anim_stream_* helpers operate on (free it with
|
|
* image_transfer_anim_stream_free). It BORROWS the buffer given via
|
|
* image_transfer_set_buffer_ptr, which must outlive it. Returns NULL
|
|
* for other types, when no stream is held, or if it was already
|
|
* detached; an undetached stream is closed by image_transfer_free. */
|
|
void *image_transfer_detach_anim_stream(void *data,
|
|
enum image_type_enum type);
|
|
|
|
bool image_transfer_is_valid(void *data, enum image_type_enum type);
|
|
|
|
/* True if the last processed frame was written as packed XRGB2101010
|
|
* (10-bit) rather than 8-bit RGBA: 10-bit was requested and the source
|
|
* could supply it. Only PNG, WEBM and MP4 can report this; false for
|
|
* every other type. */
|
|
bool image_transfer_is_10bit(void *data, enum image_type_enum type);
|
|
|
|
/* Ask a video still (WEBM, MP4) for linear scRGB half floats from an
|
|
* HDR (PQ or HLG) source - RGBA half floats, 8 bytes a pixel, in the
|
|
* frame image_transfer_process hands out - and whether the last frame
|
|
* came out so. A no-op and false for every other type and source. Only
|
|
* for a caller that can take them: nothing narrows half floats. */
|
|
void image_transfer_set_want_fp16(void *data, enum image_type_enum type,
|
|
bool want);
|
|
bool image_transfer_is_fp16(void *data, enum image_type_enum type);
|
|
|
|
/* Ask a decoder to emit packed XRGB2101010 instead of 8-bit RGBA.
|
|
* Honoured by PNG (16-bit-per-channel RGB sources) and by the video
|
|
* types (10-bit HDR sources); ignored by every other type, and by an
|
|
* 8-bit source of an honouring type. */
|
|
void image_transfer_set_want_10bit(void *data, enum image_type_enum type,
|
|
int want);
|
|
|
|
/* Animation. The whole-buffer form below is animated WEBP only; the
|
|
* streaming form further down also covers APNG, WEBM and MP4.
|
|
*
|
|
* image_transfer_anim_new returns an opaque animation handle, or NULL
|
|
* for still images / unsupported types, so a caller can try it first and
|
|
* fall back to the single-frame image_transfer_* path. Frames are fully
|
|
* composited RGBA canvases (memory order R,G,B,A); the caller advances
|
|
* frames on its own clock using each frame's duration in milliseconds. */
|
|
|
|
void *image_transfer_anim_new(void *buf, size_t len,
|
|
enum image_type_enum type);
|
|
|
|
void image_transfer_anim_free(void *anim, enum image_type_enum type);
|
|
|
|
int image_transfer_anim_num_frames(void *anim, enum image_type_enum type);
|
|
|
|
void image_transfer_anim_get_info(void *anim, enum image_type_enum type,
|
|
unsigned *width, unsigned *height, int *loop_count);
|
|
|
|
const uint32_t *image_transfer_anim_get_frame(void *anim,
|
|
enum image_type_enum type, int index, int *duration_ms);
|
|
|
|
/* Streaming animation: memory use independent of frame count. The
|
|
* buffer passed to image_transfer_anim_stream_new is BORROWED and must
|
|
* outlive the stream. next() returns the stream's internal canvas
|
|
* (valid until the next call, do not free); NULL means end of one
|
|
* pass - rewind to loop. */
|
|
|
|
void *image_transfer_anim_stream_new(void *buf, size_t len,
|
|
enum image_type_enum type);
|
|
|
|
/* Progressive open over a partially-resident buffer: only the first
|
|
* 'avail' bytes are guaranteed present. On success the stream decodes
|
|
* forward as far as 'avail' allows; move the bound with
|
|
* image_transfer_anim_stream_set_avail as more arrives. need_more (may
|
|
* be NULL) is set when the header/index needed to open is not yet
|
|
* resident and a larger prefix should be retried; NULL with it clear
|
|
* is conclusive (a still, or malformed). Every streaming type (APNG,
|
|
* animated WEBP, WEBM, MP4) has a partial open; a type compiled out
|
|
* returns NULL with need_more clear. */
|
|
/* need_lo/need_hi (optional): a precise byte range that unblocks a
|
|
* stalled progressive open, when the container can name one (MP4's
|
|
* box headers and moov body). 0/0 otherwise; the caller then grows
|
|
* the available prefix instead. */
|
|
void *image_transfer_anim_stream_new_avail(void *buf, size_t len,
|
|
size_t avail, enum image_type_enum type, int *need_more,
|
|
size_t *need_lo, size_t *need_hi);
|
|
|
|
void image_transfer_anim_stream_free(void *stream,
|
|
enum image_type_enum type);
|
|
|
|
void image_transfer_anim_stream_get_info(void *stream,
|
|
enum image_type_enum type,
|
|
unsigned *width, unsigned *height, int *num_frames, int *loop_count);
|
|
|
|
const uint32_t *image_transfer_anim_stream_next(void *stream,
|
|
enum image_type_enum type, int *duration_ms);
|
|
|
|
/* Ask the stream to emit ARGB words (non-zero) or the default R,G,B,A
|
|
* memory order (zero) from the next frame on. Returns true when the
|
|
* stream type honours the request (WEBM, MP4, and animated WEBP - the
|
|
* video streams bake the order in their blit, WEBP in its sub-frame
|
|
* decode stores, converting its persistent canvas once if the order
|
|
* changes mid-animation) so the caller can skip its own R/B swizzle
|
|
* pass; false for types that always emit the default order, where the
|
|
* caller must keep converting. */
|
|
bool image_transfer_anim_stream_set_argb(void *stream,
|
|
enum image_type_enum type, int argb);
|
|
|
|
/* Ask the stream to decode its frames straight into @out (width *
|
|
* height words of the caller's), which image_transfer_anim_stream_next
|
|
* then returns, instead of into a frame of its own that the caller
|
|
* would copy from. NULL restores the stream's own frame. Returns true
|
|
* when the stream type does so (WEBM, MP4: the blit out of the
|
|
* decoder's planes has one destination either way); false for APNG
|
|
* and WEBP, whose frames are composed on a persistent canvas, where
|
|
* the caller keeps copying. @out must stay valid until the next call
|
|
* that decodes has returned. */
|
|
/* Behind the clock: while @behind is set, pictures nothing references
|
|
* are consumed without being decoded and their presentation slots
|
|
* pass, so the stream catches up; what is shown is decoded exactly as
|
|
* before. Only the MP4 codecs (H.264, HEVC) have such pictures; for
|
|
* the rest this is a no-op. Clear it once caught up. */
|
|
/* The stream's H.264 decoder (an rh264_video*), for a bench to ask
|
|
* what its pipeline did; NULL for any other type. */
|
|
void *image_transfer_anim_stream_h264(void *stream, enum image_type_enum type);
|
|
void *image_transfer_anim_stream_h265(void *stream, enum image_type_enum type);
|
|
|
|
void image_transfer_anim_stream_set_catchup(void *stream,
|
|
enum image_type_enum type, int behind);
|
|
|
|
/* HDR video sources: whether the stream's source is PQ or HLG; asking
|
|
* for linear scRGB half floats for it, which the video streams honour
|
|
* when they decode into the caller's frame
|
|
* (image_transfer_anim_stream_set_output) - 8 bytes a pixel then; and
|
|
* whether the last frame came out so. False and a no-op for every type
|
|
* without such a source. */
|
|
bool image_transfer_anim_stream_is_hdr(const void *stream,
|
|
enum image_type_enum type);
|
|
void image_transfer_anim_stream_set_want_fp16(void *stream,
|
|
enum image_type_enum type, bool want);
|
|
bool image_transfer_anim_stream_is_fp16(const void *stream,
|
|
enum image_type_enum type);
|
|
|
|
bool image_transfer_anim_stream_set_output(void *stream,
|
|
enum image_type_enum type, uint32_t *out);
|
|
|
|
/* Have the stream convert each decoded frame to pixels in @bands row
|
|
* bands on @pool (an rthreads tpool_t with at least bands - 1 threads;
|
|
* the decoding thread takes one band and joins the rest), so a large
|
|
* frame's colour conversion is spread over cores, and decode a VP9
|
|
* frame's tile columns on the same threads where the stream carries
|
|
* more than one. NULL or bands <= 1 keeps all of it on the decoding
|
|
* thread as before. Returns true for the
|
|
* stream types that convert this way (WEBM, MP4); APNG and WEBP
|
|
* compose their frames and have no such pass. The pool is the
|
|
* caller's and must outlive every decode made while it is set. */
|
|
bool image_transfer_anim_stream_set_blit_pool(void *stream,
|
|
enum image_type_enum type, void *pool, unsigned bands);
|
|
|
|
/* For decoding a still from a file whose read is still in progress:
|
|
* declare how many leading bytes of the buffer are valid. Monotonic.
|
|
* Honoured by PNG, JPEG, WEBM and MP4, which report the wall two
|
|
* different ways: the video types return IMAGE_PROCESS_WAIT from their
|
|
* process step, while PNG and JPEG stop iterating with
|
|
* image_transfer_need_more() true. A no-op for BMP, TGA, WEBP and
|
|
* DDS, whose transfers must keep seeing fully-resident buffers. */
|
|
void image_transfer_set_avail(void *data, enum image_type_enum type,
|
|
size_t avail);
|
|
|
|
/* Declare the output byte order before the transfer starts, so
|
|
* decoders that emit final pixels during transfer (JPEG's fused
|
|
* iterate+resample) can use the caller's order directly. */
|
|
void image_transfer_set_rgba(void *data, enum image_type_enum type,
|
|
bool rgba);
|
|
|
|
/* The stream-level counterpart, for an animation stream adopted from
|
|
* a still whose file read was still in flight: the demuxer's byte
|
|
* wall was captured at open, and nothing else raises it once the
|
|
* still's task is gone - without this, a stream adopted at N bytes
|
|
* read treats N as the end of the file and loops the animation
|
|
* there, forever. Call with the full length once the read
|
|
* completes (or progressively, should a streaming consumer appear).
|
|
* An exact store for every streaming type: a windowing feeder lowers
|
|
* it when it takes pages back, and the stream then refuses (NULL from
|
|
* next(), nothing consumed) a frame whose bytes lie past it. */
|
|
void image_transfer_anim_stream_set_avail(void *stream,
|
|
enum image_type_enum type, size_t avail);
|
|
|
|
/* Bounded-memory streaming: media_floor is the fixed byte offset
|
|
* where media data begins; consumed is the byte offset the decoder's
|
|
* next read lands on, rising through a pass and dropping back to the
|
|
* floor on rewind. A feeder keeps [consumed - margin, consumed +
|
|
* lookahead) resident and can free below that. Every streaming type
|
|
* carries the cursor; 0 means the stream has not indexed anything
|
|
* yet (anchor at the floor).
|
|
*
|
|
* next_span names the byte range [lo, hi) the next frame occupies
|
|
* when the container indexes its frames (APNG, animated WEBP), so a
|
|
* feeder can make a frame larger than its lookahead resident before
|
|
* asking for it - without this a lossless 4K frame past the lookahead
|
|
* would never become readable and the stream would sit at the wall
|
|
* forever. 0/0 for the video types (packet-sized reads well inside
|
|
* any lookahead) and for a frame not indexed yet. */
|
|
size_t image_transfer_anim_stream_media_floor(void *stream,
|
|
enum image_type_enum type);
|
|
/* Container duration in nanoseconds for the video types, 0 for the
|
|
* frame-indexed ones (WEBP, APNG carry per-frame delays only) and
|
|
* when the file does not say. Lets a windowed reader size its
|
|
* lookahead to the bitrate instead of a fixed byte count. */
|
|
int64_t image_transfer_anim_stream_duration_ns(void *stream,
|
|
enum image_type_enum type);
|
|
size_t image_transfer_anim_stream_consumed(void *stream,
|
|
enum image_type_enum type);
|
|
void image_transfer_anim_stream_next_span(void *stream,
|
|
enum image_type_enum type, size_t *lo, size_t *hi);
|
|
|
|
/* Companion to the above for WEBM, whose timestamp pre-scan is
|
|
* truncated by the wall (timestamps live in the block headers): once
|
|
* the buffer is complete, finish the scan so per-frame durations
|
|
* match a stream opened over the whole file. No-op for MP4 (its
|
|
* scan reads the moov tables and is never truncated) and for types
|
|
* without a scan. */
|
|
void image_transfer_anim_stream_complete_scan(void *stream,
|
|
enum image_type_enum type, const void *buf, size_t len);
|
|
|
|
void image_transfer_anim_stream_rewind(void *stream,
|
|
enum image_type_enum type);
|
|
|
|
RETRO_END_DECLS
|
|
|
|
#endif
|