first commit
Some checks failed
/ buid (push) Has been cancelled

This commit is contained in:
2026-04-16 14:48:09 +07:00
commit 4b968a3347
5625 changed files with 1685474 additions and 0 deletions

View File

@ -0,0 +1,200 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_CACHE_H_
#define LIBPLACEBO_CACHE_H_
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <libplacebo/config.h>
#include <libplacebo/common.h>
#include <libplacebo/log.h>
PL_API_BEGIN
typedef struct pl_cache_obj {
// Cache object key. This will uniquely identify this cached object.
uint64_t key;
// Cache data pointer and length. 0-length cached objects are invalid
// and will be silently dropped. You can explicitly remove a cached
// object by overwriting it with a length 0 object.
void *data;
size_t size;
// Free callback, to free memory associated with `data`. (Optional)
// Will be called when the object is either explicitly deleted, culled
// due to hitting size limits, or on pl_cache_destroy().
void (*free)(void *data);
} pl_cache_obj;
struct pl_cache_params {
// Optional `pl_log` that is used for logging internal events related
// to the cache, such as insertions, saving and loading.
pl_log log;
// Size limits. If 0, no limit is imposed.
//
// Note: libplacebo will never detect or invalidate stale cache entries, so
// setting an upper size limit is strongly recommended
size_t max_object_size;
size_t max_total_size;
// Optional external callback to call after a cached object is modified
// (including deletion and (re-)insertion). Note that this is not called on
// objects which are merely pruned from the cache due to `max_total_size`,
// so users must rely on some external mechanism to prune stale entries or
// enforce size limits.
//
// Note: `pl_cache_load` does not trigger this callback.
// Note: Ownership of `obj` does *not* pass to the caller.
// Note: This function must be thread safe.
void (*set)(void *priv, pl_cache_obj obj);
// Optional external callback to call on a cache miss. Ownership of the
// returned object passes to the `pl_cache`. Objects returned by this
// callback *should* have a valid `free` callback, unless lifetime can be
// externally managed and guaranteed to outlive the `pl_cache`.
//
// Note: This function must be thread safe.
pl_cache_obj (*get)(void *priv, uint64_t key);
// External context for insert/lookup.
void *priv;
};
#define pl_cache_params(...) (&(struct pl_cache_params) { __VA_ARGS__ })
PL_API extern const struct pl_cache_params pl_cache_default_params;
// Thread-safety: Safe
//
// Note: In any context in which `pl_cache` is used, users may also pass NULL
// to disable caching. In other words, NULL is a valid `pl_cache`.
typedef const struct pl_cache_t {
struct pl_cache_params params;
} *pl_cache;
// Create a new cache. This function will never fail.
PL_API pl_cache pl_cache_create(const struct pl_cache_params *params);
// Destroy a `pl_cache` object, including all underlying objects.
PL_API void pl_cache_destroy(pl_cache *cache);
// Explicitly clear all objects in the cache without destroying it. This is
// similar to `pl_cache_destroy`, but the cache remains valid afterwards.
//
// Note: Objects destroyed in this way *not* propagated to the `set` callback.
PL_API void pl_cache_reset(pl_cache cache);
// Return the current internal number of objects and total size (bytes)
PL_API int pl_cache_objects(pl_cache cache);
PL_API size_t pl_cache_size(pl_cache cache);
// --- Cache saving and loading APIs
// Serialize the internal state of a `pl_cache` into an abstract cache
// object that can be e.g. saved to disk and loaded again later. Returns the
// number of objects saved.
//
// Note: Using `save/load` is largely redundant with using `insert/lookup`
// callbacks, and the user should decide whether to use the explicit API or the
// callback-based API.
PL_API int pl_cache_save_ex(pl_cache cache,
void (*write)(void *priv, size_t size, const void *ptr),
void *priv);
// Load the result of a previous `pl_cache_save` call. Any duplicate entries in
// the `pl_cache` will be overwritten. Returns the number of objects loaded, or
// a negative number on serious error (e.g. corrupt header)
//
// Note: This does not trigger the `update` callback.
PL_API int pl_cache_load_ex(pl_cache cache,
bool (*read)(void *priv, size_t size, void *ptr),
void *priv);
// --- Convenience wrappers around pl_cache_save/load_ex
// Writes data directly to a pointer. Returns the number of bytes that *would*
// have been written, so this can be used on a size 0 buffer to get the required
// total size.
PL_API size_t pl_cache_save(pl_cache cache, uint8_t *data, size_t size);
// Reads data directly from a pointer. This still reads from `data`, so it does
// not avoid a copy.
PL_API int pl_cache_load(pl_cache cache, const uint8_t *data, size_t size);
// Writes/loads data to/from a FILE stream at the current position.
#define pl_cache_save_file(c, file) pl_cache_save_ex(c, pl_write_file_cb, file)
#define pl_cache_load_file(c, file) pl_cache_load_ex(c, pl_read_file_cb, file)
static inline void pl_write_file_cb(void *priv, size_t size, const void *ptr)
{
(void) fwrite(ptr, 1, size, (FILE *) priv);
}
static inline bool pl_read_file_cb(void *priv, size_t size, void *ptr)
{
return fread(ptr, 1, size, (FILE *) priv) == size;
}
// --- Object modification API. Mostly intended for internal use.
// Insert a new cached object into a `pl_cache`. Returns whether successful.
// Overwrites any existing cached object with that signature, so this can be
// used to e.g. delete objects as well (set their size to 0). On success,
// ownership of `obj` passes to the `pl_cache`.
//
// Note: If `object.free` is NULL, this will perform an internal memdup. To
// bypass this (e.g. when directly adding externally managed memory), you can
// set the `free` callback to an explicit noop function.
//
// Note: `obj->data/free` will be reset to NULL on successful insertion.
PL_API bool pl_cache_try_set(pl_cache cache, pl_cache_obj *obj);
// Variant of `pl_cache_try_set` that simply frees `obj` on failure.
PL_API void pl_cache_set(pl_cache cache, pl_cache_obj *obj);
// Looks up `obj->key` in the object cache. If successful, `obj->data` is
// set to memory owned by the caller, which must be either explicitly
// re-inserted, or explicitly freed (using obj->free).
//
// Note: On failure, `obj->data/size/free` are reset to NULL.
PL_API bool pl_cache_get(pl_cache cache, pl_cache_obj *obj);
// Run a callback on every object currently stored in `cache`.
//
// Note: Running any `pl_cache_*` function on `cache` from this callback is
// undefined behavior.
PL_API void pl_cache_iterate(pl_cache cache,
void (*cb)(void *priv, pl_cache_obj obj),
void *priv);
// Utility wrapper to free a `pl_cache_obj` if necessary (and sanitize it)
static inline void pl_cache_obj_free(pl_cache_obj *obj)
{
if (obj->free)
obj->free(obj->data);
obj->data = NULL;
obj->free = NULL;
obj->size = 0;
}
PL_API_END
#endif // LIBPLACEBO_CACHE_H_

View File

@ -0,0 +1,719 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_COLORSPACE_H_
#define LIBPLACEBO_COLORSPACE_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <libplacebo/common.h>
PL_API_BEGIN
// The underlying color representation (e.g. RGB, XYZ or YCbCr)
enum pl_color_system {
PL_COLOR_SYSTEM_UNKNOWN = 0,
// YCbCr-like color systems:
PL_COLOR_SYSTEM_BT_601, // ITU-R Rec. BT.601 (SD)
PL_COLOR_SYSTEM_BT_709, // ITU-R Rec. BT.709 (HD)
PL_COLOR_SYSTEM_SMPTE_240M, // SMPTE-240M
PL_COLOR_SYSTEM_BT_2020_NC, // ITU-R Rec. BT.2020 (non-constant luminance)
PL_COLOR_SYSTEM_BT_2020_C, // ITU-R Rec. BT.2020 (constant luminance)
PL_COLOR_SYSTEM_BT_2100_PQ, // ITU-R Rec. BT.2100 ICtCp PQ variant
PL_COLOR_SYSTEM_BT_2100_HLG, // ITU-R Rec. BT.2100 ICtCp HLG variant
PL_COLOR_SYSTEM_DOLBYVISION, // Dolby Vision (see pl_dovi_metadata)
PL_COLOR_SYSTEM_YCGCO, // YCgCo (derived from RGB)
// Other color systems:
PL_COLOR_SYSTEM_RGB, // Red, Green and Blue
PL_COLOR_SYSTEM_XYZ, // Digital Cinema Distribution Master (XYZ)
PL_COLOR_SYSTEM_COUNT
};
PL_API bool pl_color_system_is_ycbcr_like(enum pl_color_system sys);
// Returns true for color systems that are linear transformations of the RGB
// equivalent, i.e. are simple matrix multiplications. For color systems with
// this property, `pl_color_repr_decode` is sufficient for conversion to RGB.
PL_API bool pl_color_system_is_linear(enum pl_color_system sys);
// Guesses the best YCbCr-like colorspace based on a image given resolution.
// This only picks conservative values. (In particular, BT.2020 is never
// auto-guessed, even for 4K resolution content)
PL_API enum pl_color_system pl_color_system_guess_ycbcr(int width, int height);
// Friendly names for the canonical channel names and order.
enum pl_channel {
PL_CHANNEL_NONE = -1,
PL_CHANNEL_A = 3, // alpha
// RGB system
PL_CHANNEL_R = 0,
PL_CHANNEL_G = 1,
PL_CHANNEL_B = 2,
// YCbCr-like systems
PL_CHANNEL_Y = 0,
PL_CHANNEL_CB = 1,
PL_CHANNEL_CR = 2,
// Aliases for Cb/Cr
PL_CHANNEL_U = 1,
PL_CHANNEL_V = 2
// There are deliberately no names for the XYZ system to avoid
// confusion due to PL_CHANNEL_Y.
};
// The numerical range of the representation (where applicable).
enum pl_color_levels {
PL_COLOR_LEVELS_UNKNOWN = 0,
PL_COLOR_LEVELS_LIMITED, // Limited/TV range, e.g. 16-235
PL_COLOR_LEVELS_FULL, // Full/PC range, e.g. 0-255
PL_COLOR_LEVELS_COUNT,
// Compatibility aliases
PL_COLOR_LEVELS_TV = PL_COLOR_LEVELS_LIMITED,
PL_COLOR_LEVELS_PC = PL_COLOR_LEVELS_FULL,
};
// The alpha representation mode.
enum pl_alpha_mode {
PL_ALPHA_UNKNOWN = 0, // or no alpha channel present
PL_ALPHA_INDEPENDENT, // alpha channel is separate from the video
PL_ALPHA_PREMULTIPLIED, // alpha channel is multiplied into the colors
PL_ALPHA_MODE_COUNT,
};
// The underlying bit-wise representation of a color sample. For example,
// a 10-bit TV-range YCbCr value uploaded to a 16 bit texture would have
// sample_depth=16 color_depth=10 bit_shift=0.
//
// For another example, a 12-bit XYZ full range sample shifted to 16-bits with
// the lower 4 bits all set to 0 would have sample_depth=16 color_depth=12
// bit_shift=4. (libavcodec likes outputting this type of `xyz12`)
//
// To explain the meaning of `sample_depth` further; the consideration factor
// here is the fact that GPU sampling will normalized the sampled color to the
// range 0.0 - 1.0 in a manner dependent on the number of bits in the texture
// format. So if you upload a 10-bit YCbCr value unpadded as 16-bit color
// samples, all of the sampled values will be extremely close to 0.0. In such a
// case, `pl_color_repr_normalize` would return a high scaling factor, which
// would pull the color up to their 16-bit range.
struct pl_bit_encoding {
int sample_depth; // the number of bits the color is stored/sampled as
int color_depth; // the effective number of bits of the color information
int bit_shift; // a representational bit shift applied to the color
};
// Returns whether two bit encodings are exactly identical.
PL_API bool pl_bit_encoding_equal(const struct pl_bit_encoding *b1,
const struct pl_bit_encoding *b2);
// Parsed metadata from the Dolby Vision RPU
struct pl_dovi_metadata {
// Colorspace transformation metadata
float nonlinear_offset[3]; // input offset ("ycc_to_rgb_offset")
pl_matrix3x3 nonlinear; // before PQ, also called "ycc_to_rgb"
pl_matrix3x3 linear; // after PQ, also called "rgb_to_lms"
// Reshape data, grouped by component
struct pl_reshape_data {
uint8_t num_pivots;
float pivots[9]; // normalized to [0.0, 1.0] based on BL bit depth
uint8_t method[8]; // 0 = polynomial, 1 = MMR
// Note: these must be normalized (divide by coefficient_log2_denom)
float poly_coeffs[8][3]; // x^0, x^1, x^2, unused must be 0
uint8_t mmr_order[8]; // 1, 2 or 3
float mmr_constant[8];
float mmr_coeffs[8][3 /* order */][7];
} comp[3];
};
// Struct describing the underlying color system and representation. This
// information is needed to convert an encoded color to a normalized RGB triple
// in the range 0-1.
struct pl_color_repr {
enum pl_color_system sys;
enum pl_color_levels levels;
enum pl_alpha_mode alpha;
struct pl_bit_encoding bits; // or {0} if unknown
// Metadata for PL_COLOR_SYSTEM_DOLBYVISION. Note that, for the sake of
// efficiency, this is treated purely as an opaque reference - functions
// like pl_color_repr_equal will merely do a pointer equality test.
//
// The only functions that actually dereference it in any way are
// pl_color_repr_decode, pl_shader_decode_color and pl_render_image(_mix).
const struct pl_dovi_metadata *dovi;
};
// Some common color representations. It's worth pointing out that all of these
// presets leave `alpha` and `bits` as unknown - that is, only the system and
// levels are predefined
PL_API extern const struct pl_color_repr pl_color_repr_unknown;
PL_API extern const struct pl_color_repr pl_color_repr_rgb;
PL_API extern const struct pl_color_repr pl_color_repr_sdtv;
PL_API extern const struct pl_color_repr pl_color_repr_hdtv; // also Blu-ray
PL_API extern const struct pl_color_repr pl_color_repr_uhdtv; // SDR, NCL system
PL_API extern const struct pl_color_repr pl_color_repr_jpeg;
// Returns whether two colorspace representations are exactly identical.
PL_API bool pl_color_repr_equal(const struct pl_color_repr *c1,
const struct pl_color_repr *c2);
// Replaces unknown values in the first struct by those of the second struct.
PL_API void pl_color_repr_merge(struct pl_color_repr *orig,
const struct pl_color_repr *update);
// This function normalizes the color representation such that
// color_depth=sample_depth and bit_shift=0; and returns the scaling factor
// that must be multiplied into the color value to accomplish this, assuming
// it has already been sampled by the GPU. If unknown, the color and sample
// depth will both be inferred as 8 bits for the purposes of this conversion.
PL_API float pl_color_repr_normalize(struct pl_color_repr *repr);
// Guesses the best color levels based on the specified color levels and
// falling back to using the color system instead. YCbCr-like systems are
// assumed to be TV range, otherwise this defaults to PC range.
PL_API enum pl_color_levels pl_color_levels_guess(const struct pl_color_repr *repr);
// The colorspace's primaries (gamut)
enum pl_color_primaries {
PL_COLOR_PRIM_UNKNOWN = 0,
// Standard gamut:
PL_COLOR_PRIM_BT_601_525, // ITU-R Rec. BT.601 (525-line = NTSC, SMPTE-C)
PL_COLOR_PRIM_BT_601_625, // ITU-R Rec. BT.601 (625-line = PAL, SECAM)
PL_COLOR_PRIM_BT_709, // ITU-R Rec. BT.709 (HD), also sRGB
PL_COLOR_PRIM_BT_470M, // ITU-R Rec. BT.470 M
PL_COLOR_PRIM_EBU_3213, // EBU Tech. 3213-E / JEDEC P22 phosphors
// Wide gamut:
PL_COLOR_PRIM_BT_2020, // ITU-R Rec. BT.2020 (UltraHD)
PL_COLOR_PRIM_APPLE, // Apple RGB
PL_COLOR_PRIM_ADOBE, // Adobe RGB (1998)
PL_COLOR_PRIM_PRO_PHOTO, // ProPhoto RGB (ROMM)
PL_COLOR_PRIM_CIE_1931, // CIE 1931 RGB primaries
PL_COLOR_PRIM_DCI_P3, // DCI-P3 (Digital Cinema)
PL_COLOR_PRIM_DISPLAY_P3, // DCI-P3 (Digital Cinema) with D65 white point
PL_COLOR_PRIM_V_GAMUT, // Panasonic V-Gamut (VARICAM)
PL_COLOR_PRIM_S_GAMUT, // Sony S-Gamut
PL_COLOR_PRIM_FILM_C, // Traditional film primaries with Illuminant C
PL_COLOR_PRIM_ACES_AP0, // ACES Primaries #0 (ultra wide)
PL_COLOR_PRIM_ACES_AP1, // ACES Primaries #1
PL_COLOR_PRIM_COUNT
};
PL_API bool pl_color_primaries_is_wide_gamut(enum pl_color_primaries prim);
// Guesses the best primaries based on a resolution. This always guesses
// conservatively, i.e. it will never return a wide gamut color space even if
// the resolution is 4K.
PL_API enum pl_color_primaries pl_color_primaries_guess(int width, int height);
// The colorspace's transfer function (gamma / EOTF)
enum pl_color_transfer {
PL_COLOR_TRC_UNKNOWN = 0,
// Standard dynamic range:
PL_COLOR_TRC_BT_1886, // ITU-R Rec. BT.1886 (CRT emulation + OOTF)
PL_COLOR_TRC_SRGB, // IEC 61966-2-4 sRGB (CRT emulation)
PL_COLOR_TRC_LINEAR, // Linear light content
PL_COLOR_TRC_GAMMA18, // Pure power gamma 1.8
PL_COLOR_TRC_GAMMA20, // Pure power gamma 2.0
PL_COLOR_TRC_GAMMA22, // Pure power gamma 2.2
PL_COLOR_TRC_GAMMA24, // Pure power gamma 2.4
PL_COLOR_TRC_GAMMA26, // Pure power gamma 2.6
PL_COLOR_TRC_GAMMA28, // Pure power gamma 2.8
PL_COLOR_TRC_PRO_PHOTO, // ProPhoto RGB (ROMM)
PL_COLOR_TRC_ST428, // Digital Cinema Distribution Master (XYZ)
// High dynamic range:
PL_COLOR_TRC_PQ, // ITU-R BT.2100 PQ (perceptual quantizer), aka SMPTE ST2048
PL_COLOR_TRC_HLG, // ITU-R BT.2100 HLG (hybrid log-gamma), aka ARIB STD-B67
PL_COLOR_TRC_V_LOG, // Panasonic V-Log (VARICAM)
PL_COLOR_TRC_S_LOG1, // Sony S-Log1
PL_COLOR_TRC_S_LOG2, // Sony S-Log2
PL_COLOR_TRC_COUNT
};
// Returns the nominal peak of a given transfer function, relative to the
// reference white. This refers to the highest encodable signal level.
// Always equal to 1.0 for SDR curves.
//
// Note: For HLG in particular, which is scene-referred, this returns the
// highest nominal peak in scene-referred space (3.77), which may be different
// from the actual peak in display space after application of the HLG OOTF.
PL_API float pl_color_transfer_nominal_peak(enum pl_color_transfer trc);
static inline bool pl_color_transfer_is_hdr(enum pl_color_transfer trc)
{
return pl_color_transfer_nominal_peak(trc) > 1.0;
}
// This defines the display-space standard reference white level (in cd/m^2)
// that is assumed for SDR content, for use when mapping between HDR and SDR in
// display space. See ITU-R Report BT.2408 for more information.
#define PL_COLOR_SDR_WHITE 203.0f
// This defines the assumed contrast level of an unknown SDR display. This
// will be used to determine the black point in the absence of any tagged
// minimum luminance, relative to the tagged maximum luminance (or
// PL_COLOR_SDR_WHITE in the absence of all tagging)
#define PL_COLOR_SDR_CONTRAST 1000.0f
// This defines the default black point assumed for "infinite contrast" HDR
// displays. This is not exactly 0.0 because a value of 0.0 is interpreted
// as "unknown / missing metadata" inside struct pl_hdr_metadata, and also
// to avoid numerical issues in a variety of tone mapping functions.
// Essentially, a black level below this number is functionally meaningless
// inside libplacebo, and will be clamped to this value regardless.
//
// The value used here (1e-6) is about one 13-bit PQ step above absolute zero,
// which is a small fraction of the human JND at this brightness level, and also
// about 3 bits above the floating point machine epsilon.
#define PL_COLOR_HDR_BLACK 1e-6f
// This defines the assumed peak brightness of a HLG display with no HDR10
// metadata. This is set to the brightness of a "nominal" HLG reference display.
#define PL_COLOR_HLG_PEAK 1000.0f
// Represents a single CIE xy coordinate (e.g. CIE Yxy with Y = 1.0)
struct pl_cie_xy {
float x, y;
};
// Creates a pl_cie_xyz from raw XYZ values
static inline struct pl_cie_xy pl_cie_from_XYZ(float X, float Y, float Z)
{
float k = 1.0f / (X + Y + Z);
struct pl_cie_xy xy = { k * X, k * Y };
return xy;
}
// Recovers (X / Y) from a CIE xy value.
static inline float pl_cie_X(struct pl_cie_xy xy)
{
return xy.x / xy.y;
}
// Recovers (Z / Y) from a CIE xy value.
static inline float pl_cie_Z(struct pl_cie_xy xy)
{
return (1 - xy.x - xy.y) / xy.y;
}
static inline bool pl_cie_xy_equal(const struct pl_cie_xy *a,
const struct pl_cie_xy *b)
{
return a->x == b->x && a->y == b->y;
}
// Computes the CIE xy chromaticity coordinates of a CIE D-series illuminant
// with the given correlated color temperature.
//
// `temperature` must be between 2500 K and 25000 K, inclusive.
PL_API struct pl_cie_xy pl_white_from_temp(float temperature);
// Represents the raw physical primaries corresponding to a color space.
struct pl_raw_primaries {
struct pl_cie_xy red, green, blue, white;
};
// Returns whether two raw primaries are exactly identical.
PL_API bool pl_raw_primaries_equal(const struct pl_raw_primaries *a,
const struct pl_raw_primaries *b);
// Returns whether two raw primaries are approximately equal
PL_API bool pl_raw_primaries_similar(const struct pl_raw_primaries *a,
const struct pl_raw_primaries *b);
// Replaces unknown values in the first struct by those of the second struct.
PL_API void pl_raw_primaries_merge(struct pl_raw_primaries *orig,
const struct pl_raw_primaries *update);
// Returns the raw primaries for a given color space.
PL_API const struct pl_raw_primaries *pl_raw_primaries_get(enum pl_color_primaries prim);
enum pl_hdr_scaling {
PL_HDR_NORM = 0, // 0.0 is absolute black, 1.0 is PL_COLOR_SDR_WHITE
PL_HDR_SQRT, // sqrt() of PL_HDR_NORM values
PL_HDR_NITS, // absolute brightness in raw cd/m²
PL_HDR_PQ, // absolute brightness in PQ (0.0 to 1.0)
PL_HDR_SCALING_COUNT,
};
// Generic helper for performing HDR scale conversions.
PL_API float pl_hdr_rescale(enum pl_hdr_scaling from, enum pl_hdr_scaling to, float x);
enum pl_hdr_metadata_type {
PL_HDR_METADATA_ANY = 0,
PL_HDR_METADATA_NONE,
PL_HDR_METADATA_HDR10, // HDR10 static mastering display metadata
PL_HDR_METADATA_HDR10PLUS, // HDR10+ dynamic metadata
PL_HDR_METADATA_CIE_Y, // CIE Y derived dynamic luminance metadata
PL_HDR_METADATA_TYPE_COUNT,
};
// Bezier curve for HDR metadata
struct pl_hdr_bezier {
float target_luma; // target luminance (cd/m²) for this OOTF
float knee_x, knee_y; // cross-over knee point (0-1)
float anchors[15]; // intermediate bezier curve control points (0-1)
uint8_t num_anchors;
};
// Represents raw HDR metadata as defined by SMPTE 2086 / CTA 861.3, which is
// often attached to HDR sources and can be forwarded to HDR-capable displays,
// or used to guide the libplacebo built-in tone mapping. Values left as 0
// are treated as unknown by libplacebo.
//
// Note: This means that a value of `min_luma == 0.0` gets treated as "minimum
// luminance not known", which in practice may end up inferring a default
// contrast of 1000:1 for SDR transfer functions. To avoid this, the user should
// set these fields to a low positive value, e.g. PL_COLOR_HDR_BLACK, to signal
// a "zero" black point (i.e. infinite contrast display).
struct pl_hdr_metadata {
// --- PL_HDR_METADATA_HDR10
// Mastering display metadata.
struct pl_raw_primaries prim; // mastering display primaries
float min_luma, max_luma; // min/max luminance (in cd/m²)
// Content light level. (Note: this is ignored by libplacebo itself)
float max_cll; // max content light level (in cd/m²)
float max_fall; // max frame average light level (in cd/m²)
// --- PL_HDR_METADATA_HDR10PLUS
float scene_max[3]; // maxSCL in cd/m² per component (RGB)
float scene_avg; // average of maxRGB in cd/m²
struct pl_hdr_bezier ootf; // reference OOTF (optional)
// --- PL_HDR_METADATA_CIE_Y
float max_pq_y; // maximum PQ luminance (in PQ, 0-1)
float avg_pq_y; // averaged PQ luminance (in PQ, 0-1)
};
PL_API extern const struct pl_hdr_metadata pl_hdr_metadata_empty; // equal to {0}
PL_API extern const struct pl_hdr_metadata pl_hdr_metadata_hdr10; // generic HDR10 display
// Returns whether two sets of HDR metadata are exactly identical.
PL_API bool pl_hdr_metadata_equal(const struct pl_hdr_metadata *a,
const struct pl_hdr_metadata *b);
// Replaces unknown values in the first struct by those of the second struct.
PL_API void pl_hdr_metadata_merge(struct pl_hdr_metadata *orig,
const struct pl_hdr_metadata *update);
// Returns `true` if `data` contains a complete set of a given metadata type.
// Note: for PL_HDR_METADATA_HDR10, only `min_luma` and `max_luma` are
// considered - CLL/FALL and primaries are irrelevant for HDR tone-mapping.
PL_API bool pl_hdr_metadata_contains(const struct pl_hdr_metadata *data,
enum pl_hdr_metadata_type type);
// Rendering intent for colorspace transformations. These constants match the
// ICC specification (Table 23)
enum pl_rendering_intent {
PL_INTENT_AUTO = -1, // not a valid ICC intent, but used to auto-infer
PL_INTENT_PERCEPTUAL = 0,
PL_INTENT_RELATIVE_COLORIMETRIC = 1,
PL_INTENT_SATURATION = 2,
PL_INTENT_ABSOLUTE_COLORIMETRIC = 3
};
// Struct describing a physical color space. This information is needed to
// turn a normalized RGB triple into its physical meaning, as well as to convert
// between color spaces.
struct pl_color_space {
enum pl_color_primaries primaries;
enum pl_color_transfer transfer;
// HDR metadata for this color space, if present. (Optional)
struct pl_hdr_metadata hdr;
};
#define pl_color_space(...) (&(struct pl_color_space) { __VA_ARGS__ })
// Returns whether or not a color space is considered as effectively HDR.
// This is true when the effective signal peak is greater than the SDR
// reference white (1.0), taking into account `csp->hdr`.
PL_API bool pl_color_space_is_hdr(const struct pl_color_space *csp);
// Returns whether or not a color space is "black scaled", in which case 0.0 is
// the true black point. This is true for SDR signals other than BT.1886, as
// well as for HLG.
PL_API bool pl_color_space_is_black_scaled(const struct pl_color_space *csp);
struct pl_nominal_luma_params {
// The color space to infer luminance from
const struct pl_color_space *color;
// Which type of metadata to draw values from
enum pl_hdr_metadata_type metadata;
// This field controls the scaling of `out_*`
enum pl_hdr_scaling scaling;
// Fields to write the detected nominal luminance to. (Optional)
//
// For SDR displays, this will default to a contrast level of 1000:1 unless
// indicated otherwise in the `min/max_luma` static HDR10 metadata fields.
float *out_min;
float *out_max;
// Field to write the detected average luminance to, or 0.0 in the absence
// of dynamic metadata. (Optional)
float *out_avg;
};
#define pl_nominal_luma_params(...) \
(&(struct pl_nominal_luma_params) { __VA_ARGS__ })
// Returns the effective luminance described by a pl_color_space.
PL_API void pl_color_space_nominal_luma_ex(const struct pl_nominal_luma_params *params);
// Backwards compatibility wrapper for `pl_color_space_nominal_luma_ex`
PL_DEPRECATED PL_API void pl_color_space_nominal_luma(const struct pl_color_space *csp,
float *out_min, float *out_max);
// Replaces unknown values in the first struct by those of the second struct.
PL_API void pl_color_space_merge(struct pl_color_space *orig,
const struct pl_color_space *update);
// Returns whether two colorspaces are exactly identical.
PL_API bool pl_color_space_equal(const struct pl_color_space *c1,
const struct pl_color_space *c2);
// Go through a color-space and explicitly default all unknown fields to
// reasonable values. After this function is called, none of the values will be
// PL_COLOR_*_UNKNOWN or 0.0, except for the dynamic HDR metadata fields.
PL_API void pl_color_space_infer(struct pl_color_space *space);
// Like `pl_color_space_infer`, but takes default values from the reference
// color space (excluding certain special cases like HDR or wide gamut).
PL_API void pl_color_space_infer_ref(struct pl_color_space *space,
const struct pl_color_space *ref);
// Infer both the source and destination gamut simultaneously, and also adjust
// values for optimal display. This is mostly the same as
// `pl_color_space_infer(src)` followed by `pl_color_space_infer_ref`, but also
// takes into account the SDR contrast levels and PQ black points. This is
// basically the logic used by `pl_shader_color_map` and `pl_renderer` to
// decide the output color space in a conservative way and compute the final
// end-to-end color transformation that needs to be done.
PL_API void pl_color_space_infer_map(struct pl_color_space *src,
struct pl_color_space *dst);
// Some common color spaces. Note: These don't necessarily have all fields
// filled, in particular `hdr` is left unset.
PL_API extern const struct pl_color_space pl_color_space_unknown;
PL_API extern const struct pl_color_space pl_color_space_srgb;
PL_API extern const struct pl_color_space pl_color_space_bt709;
PL_API extern const struct pl_color_space pl_color_space_hdr10;
PL_API extern const struct pl_color_space pl_color_space_bt2020_hlg;
PL_API extern const struct pl_color_space pl_color_space_monitor; // typical display
// This represents metadata about extra operations to perform during colorspace
// conversion, which correspond to artistic adjustments of the color.
struct pl_color_adjustment {
// Brightness boost. 0.0 = neutral, 1.0 = solid white, -1.0 = solid black
float brightness;
// Contrast boost. 1.0 = neutral, 0.0 = solid black
float contrast;
// Saturation gain. 1.0 = neutral, 0.0 = grayscale
float saturation;
// Hue shift, corresponding to a rotation around the [U, V] subvector, in
// radians. 0.0 = neutral
float hue;
// Gamma adjustment. 1.0 = neutral, 0.0 = solid black
float gamma;
// Color temperature shift. 0.0 = 6500 K, -1.0 = 3000 K, 1.0 = 10000 K
float temperature;
};
#define PL_COLOR_ADJUSTMENT_NEUTRAL \
.contrast = 1.0, \
.saturation = 1.0, \
.gamma = 1.0,
#define pl_color_adjustment(...) (&(struct pl_color_adjustment) { PL_COLOR_ADJUSTMENT_NEUTRAL __VA_ARGS__ })
PL_API extern const struct pl_color_adjustment pl_color_adjustment_neutral;
// Represents the chroma placement with respect to the luma samples. This is
// only relevant for YCbCr-like colorspaces with chroma subsampling.
enum pl_chroma_location {
PL_CHROMA_UNKNOWN = 0,
PL_CHROMA_LEFT, // MPEG2/4, H.264
PL_CHROMA_CENTER, // MPEG1, JPEG
PL_CHROMA_TOP_LEFT,
PL_CHROMA_TOP_CENTER,
PL_CHROMA_BOTTOM_LEFT,
PL_CHROMA_BOTTOM_CENTER,
PL_CHROMA_COUNT,
};
// Fills *x and *y with the offset in luma pixels corresponding to a given
// chroma location.
//
// Note: PL_CHROMA_UNKNOWN defaults to PL_CHROMA_LEFT
PL_API void pl_chroma_location_offset(enum pl_chroma_location loc, float *x, float *y);
// Returns an RGB->XYZ conversion matrix for a given set of primaries.
// Multiplying this into the RGB color transforms it to CIE XYZ, centered
// around the color space's white point.
PL_API pl_matrix3x3 pl_get_rgb2xyz_matrix(const struct pl_raw_primaries *prim);
// Similar to pl_get_rgb2xyz_matrix, but gives the inverse transformation.
PL_API pl_matrix3x3 pl_get_xyz2rgb_matrix(const struct pl_raw_primaries *prim);
// Returns a primary adaptation matrix, which converts from one set of
// primaries to another. This is an RGB->RGB transformation. For rendering
// intents other than PL_INTENT_ABSOLUTE_COLORIMETRIC, the white point is
// adapted using the Bradford matrix.
PL_API pl_matrix3x3 pl_get_color_mapping_matrix(const struct pl_raw_primaries *src,
const struct pl_raw_primaries *dst,
enum pl_rendering_intent intent);
// Return a chromatic adaptation matrix, which converts from one white point to
// another, using the Bradford matrix. This is an RGB->RGB transformation.
PL_API pl_matrix3x3 pl_get_adaptation_matrix(struct pl_cie_xy src, struct pl_cie_xy dst);
// Returns true if 'b' is entirely contained in 'a'. Useful for figuring out if
// colorimetric clipping will occur or not.
PL_API bool pl_primaries_superset(const struct pl_raw_primaries *a,
const struct pl_raw_primaries *b);
// Returns true if `prim` forms a nominally valid set of primaries. This does
// not check whether or not these primaries are actually physically realisable,
// merely that they satisfy the requirements for colorspace math (to avoid NaN).
PL_API bool pl_primaries_valid(const struct pl_raw_primaries *prim);
// Returns true if two primaries are 'compatible', which is the case if
// they preserve the relationship between primaries (red=red, green=green,
// blue=blue). In other words, this is false for synthetic primaries that have
// channels misordered from the convention (e.g. for some test ICC profiles).
PL_API bool pl_primaries_compatible(const struct pl_raw_primaries *a,
const struct pl_raw_primaries *b);
// Clip points in the first gamut (src) to be fully contained inside the second
// gamut (dst). Only works on compatible primaries (pl_primaries_compatible).
PL_API struct pl_raw_primaries
pl_primaries_clip(const struct pl_raw_primaries *src,
const struct pl_raw_primaries *dst);
// Primary-dependent RGB->LMS matrix for the IPTPQc4 color system. This is
// derived from the HPE XYZ->LMS matrix with 4% crosstalk added.
PL_API pl_matrix3x3 pl_ipt_rgb2lms(const struct pl_raw_primaries *prim);
PL_API pl_matrix3x3 pl_ipt_lms2rgb(const struct pl_raw_primaries *prim);
// Primary-independent L'M'S' -> IPT matrix for the IPTPQc4 color system, and
// its inverse. This is identical to the Ebner & Fairchild (1998) IPT matrix.
PL_API extern const pl_matrix3x3 pl_ipt_lms2ipt;
PL_API extern const pl_matrix3x3 pl_ipt_ipt2lms;
// Cone types involved in human vision
enum pl_cone {
PL_CONE_L = 1 << 0,
PL_CONE_M = 1 << 1,
PL_CONE_S = 1 << 2,
// Convenience aliases
PL_CONE_NONE = 0,
PL_CONE_LM = PL_CONE_L | PL_CONE_M,
PL_CONE_MS = PL_CONE_M | PL_CONE_S,
PL_CONE_LS = PL_CONE_L | PL_CONE_S,
PL_CONE_LMS = PL_CONE_L | PL_CONE_M | PL_CONE_S,
};
// Structure describing parameters for simulating color blindness
struct pl_cone_params {
enum pl_cone cones; // Which cones are *affected* by the vision model
float strength; // Coefficient for how strong the defect is
// (1.0 = Unaffected, 0.0 = Full blindness)
};
#define pl_cone_params(...) (&(struct pl_cone_params) { __VA_ARGS__ })
// Built-in color blindness models
PL_API extern const struct pl_cone_params pl_vision_normal; // No distortion (92%)
PL_API extern const struct pl_cone_params pl_vision_protanomaly; // Red deficiency (0.66%)
PL_API extern const struct pl_cone_params pl_vision_protanopia; // Red absence (0.59%)
PL_API extern const struct pl_cone_params pl_vision_deuteranomaly; // Green deficiency (2.7%)
PL_API extern const struct pl_cone_params pl_vision_deuteranopia; // Green absence (0.56%)
PL_API extern const struct pl_cone_params pl_vision_tritanomaly; // Blue deficiency (0.01%)
PL_API extern const struct pl_cone_params pl_vision_tritanopia; // Blue absence (0.016%)
PL_API extern const struct pl_cone_params pl_vision_monochromacy; // Blue cones only (<0.001%)
PL_API extern const struct pl_cone_params pl_vision_achromatopsia; // Rods only (<0.0001%)
// Returns a cone adaptation matrix. Applying this to an RGB color in the given
// color space will apply the given cone adaptation coefficients for simulating
// a type of color blindness.
//
// For the color blindness models which don't entail complete loss of a cone,
// you can partially counteract the effect by using a similar model with the
// `strength` set to its inverse. For example, to partially counteract
// deuteranomaly, you could generate a cone matrix for PL_CONE_M with the
// strength 2.0 (or some other number above 1.0).
PL_API pl_matrix3x3 pl_get_cone_matrix(const struct pl_cone_params *params,
const struct pl_raw_primaries *prim);
// Returns a color decoding matrix for a given combination of source color
// representation and adjustment parameters. This mutates `repr` to reflect the
// change. If `params` is NULL, it defaults to &pl_color_adjustment_neutral.
//
// This function always performs a conversion to RGB. To convert to other
// colorspaces (e.g. between YUV systems), obtain a second YUV->RGB matrix
// and invert it using `pl_transform3x3_invert`.
//
// Note: For BT.2020 constant-luminance, this outputs chroma information in the
// range [-0.5, 0.5]. Since the CL system conversion is non-linear, further
// processing must be done by the caller. The channel order is CrYCb.
//
// Note: For BT.2100 ICtCp, this outputs in the color space L'M'S'. Further
// non-linear processing must be done by the caller.
//
// Note: XYZ system is expected to be in DCDM X'Y'Z' encoding (ST 428-1), in
// practice this means normalizing by (48.0 / 52.37) factor and applying 2.6 gamma
PL_API pl_transform3x3 pl_color_repr_decode(struct pl_color_repr *repr,
const struct pl_color_adjustment *params);
// Common struct to describe an ICC profile
struct pl_icc_profile {
// Points to the in-memory representation of the ICC profile. This is
// allowed to be NULL, in which case the `pl_icc_profile` represents "no
// profile”.
const void *data;
size_t len;
// If a profile is set, this signature must uniquely identify it (including
// across restarts, for caching), ideally using a checksum of the profile
// contents. The user is free to choose the method of determining this
// signature, but note the existence of the
// `pl_icc_profile_compute_signature` helper.
uint64_t signature;
};
#define pl_icc_profile(...) &(struct pl_icc_profile) { __VA_ARGS__ }
// This doesn't do a comparison of the actual contents, only of the signature.
PL_API bool pl_icc_profile_equal(const struct pl_icc_profile *p1,
const struct pl_icc_profile *p2);
// Sets `signature` to a hash of `profile->data`, if non-NULL. Provided as a
// convenience function for the sake of users ingesting arbitrary ICC profiles
// from sources where they can't reliably detect profile changes.
//
// Note: This is based on a very fast hash, and will compute a signature for
// even large (10 MB) ICC profiles in, typically, a fraction of a millisecond.
PL_API void pl_icc_profile_compute_signature(struct pl_icc_profile *profile);
PL_API_END
#endif // LIBPLACEBO_COLORSPACE_H_

View File

@ -0,0 +1,244 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_COMMON_H_
#define LIBPLACEBO_COMMON_H_
#include <stdbool.h>
#include <libplacebo/config.h>
PL_API_BEGIN
// Some common utility types. These are overloaded to support 2D, 3D and
// integer/float variants.
typedef struct pl_rect2d {
int x0, y0;
int x1, y1;
} pl_rect2d;
typedef struct pl_rect3d {
int x0, y0, z0;
int x1, y1, z1;
} pl_rect3d;
typedef struct pl_rect2df {
float x0, y0;
float x1, y1;
} pl_rect2df;
typedef struct pl_rect3df {
float x0, y0, z0;
float x1, y1, z1;
} pl_rect3df;
// These macros will work for any of the above pl_rect variants (with enough
// dimensions). Careful: double-evaluation hazard
#define pl_rect_w(r) ((r).x1 - (r).x0)
#define pl_rect_h(r) ((r).y1 - (r).y0)
#define pl_rect_d(r) ((r).z1 - (r).z0)
#define pl_rect2d_eq(a, b) \
((a).x0 == (b).x0 && (a).x1 == (b).x1 && \
(a).y0 == (b).y0 && (a).y1 == (b).y1)
#define pl_rect3d_eq(a, b) \
((a).x0 == (b).x0 && (a).x1 == (b).x1 && \
(a).y0 == (b).y0 && (a).y1 == (b).y1 && \
(a).z0 == (b).z0 && (a).z1 == (b).z1)
// "Normalize" a rectangle: This ensures d1 >= d0 for all dimensions.
PL_API void pl_rect2d_normalize(pl_rect2d *rc);
PL_API void pl_rect3d_normalize(pl_rect3d *rc);
PL_API void pl_rect2df_normalize(pl_rect2df *rc);
PL_API void pl_rect3df_normalize(pl_rect3df *rc);
// Return the rounded form of a rect.
PL_API pl_rect2d pl_rect2df_round(const pl_rect2df *rc);
PL_API pl_rect3d pl_rect3df_round(const pl_rect3df *rc);
// Represents a row-major matrix, i.e. the following matrix
// [ a11 a12 a13 ]
// [ a21 a22 a23 ]
// [ a31 a32 a33 ]
// is represented in C like this:
// { { a11, a12, a13 },
// { a21, a22, a23 },
// { a31, a32, a33 } };
typedef struct pl_matrix3x3 {
float m[3][3];
} pl_matrix3x3;
PL_API extern const pl_matrix3x3 pl_matrix3x3_identity;
// Applies a matrix to a float vector in-place.
PL_API void pl_matrix3x3_apply(const pl_matrix3x3 *mat, float vec[3]);
// Applies a matrix to a pl_rect3df
PL_API void pl_matrix3x3_apply_rc(const pl_matrix3x3 *mat, pl_rect3df *rc);
// Scales a color matrix by a linear factor.
PL_API void pl_matrix3x3_scale(pl_matrix3x3 *mat, float scale);
// Inverts a matrix. Only use where precision is not that important.
PL_API void pl_matrix3x3_invert(pl_matrix3x3 *mat);
// Composes/multiplies two matrices. Multiples B into A, i.e.
// A := A * B
PL_API void pl_matrix3x3_mul(pl_matrix3x3 *a, const pl_matrix3x3 *b);
// Flipped version of `pl_matrix3x3_mul`.
// B := A * B
PL_API void pl_matrix3x3_rmul(const pl_matrix3x3 *a, pl_matrix3x3 *b);
// Represents an affine transformation, which is basically a 3x3 matrix
// together with a column vector to add onto the output.
typedef struct pl_transform3x3 {
pl_matrix3x3 mat;
float c[3];
} pl_transform3x3;
PL_API extern const pl_transform3x3 pl_transform3x3_identity;
// Applies a transform to a float vector in-place.
PL_API void pl_transform3x3_apply(const pl_transform3x3 *t, float vec[3]);
// Applies a transform to a pl_rect3df
PL_API void pl_transform3x3_apply_rc(const pl_transform3x3 *t, pl_rect3df *rc);
// Scales the output of a transform by a linear factor. Since an affine
// transformation is non-linear, this does not commute. If you want to scale
// the *input* of a transform, use pl_matrix3x3_scale on `t.mat`.
PL_API void pl_transform3x3_scale(pl_transform3x3 *t, float scale);
// Inverts a transform. Only use where precision is not that important.
PL_API void pl_transform3x3_invert(pl_transform3x3 *t);
// 2D analog of the above structs. Since these are featured less prominently,
// we omit some of the other helper functions.
typedef struct pl_matrix2x2 {
float m[2][2];
} pl_matrix2x2;
PL_API extern const pl_matrix2x2 pl_matrix2x2_identity;
PL_API pl_matrix2x2 pl_matrix2x2_rotation(float angle);
PL_API void pl_matrix2x2_apply(const pl_matrix2x2 *mat, float vec[2]);
PL_API void pl_matrix2x2_apply_rc(const pl_matrix2x2 *mat, pl_rect2df *rc);
PL_API void pl_matrix2x2_mul(pl_matrix2x2 *a, const pl_matrix2x2 *b);
PL_API void pl_matrix2x2_rmul(const pl_matrix2x2 *a, pl_matrix2x2 *b);
PL_API void pl_matrix2x2_scale(pl_matrix2x2 *mat, float scale);
PL_API void pl_matrix2x2_invert(pl_matrix2x2 *mat);
typedef struct pl_transform2x2 {
pl_matrix2x2 mat;
float c[2];
} pl_transform2x2;
PL_API extern const pl_transform2x2 pl_transform2x2_identity;
PL_API void pl_transform2x2_apply(const pl_transform2x2 *t, float vec[2]);
PL_API void pl_transform2x2_apply_rc(const pl_transform2x2 *t, pl_rect2df *rc);
PL_API void pl_transform2x2_mul(pl_transform2x2 *a, const pl_transform2x2 *b);
PL_API void pl_transform2x2_rmul(const pl_transform2x2 *a, pl_transform2x2 *b);
PL_API void pl_transform2x2_scale(pl_transform2x2 *t, float scale);
PL_API void pl_transform2x2_invert(pl_transform2x2 *t);
// Compute new bounding box of a transformation (as applied to a given rect).
PL_API pl_rect2df pl_transform2x2_bounds(const pl_transform2x2 *t,
const pl_rect2df *rc);
// Helper functions for dealing with aspect ratios and stretched/scaled rects.
// Return the (absolute) aspect ratio (width/height) of a given pl_rect2df.
// This will always be a positive number, even if `rc` is flipped.
PL_API float pl_rect2df_aspect(const pl_rect2df *rc);
// Set the aspect of a `rc` to a given aspect ratio with an extra 'panscan'
// factor choosing the balance between shrinking and growing the `rc` to meet
// this aspect ratio.
//
// Notes:
// - If `panscan` is 0.0, this function will only ever shrink the `rc`.
// - If `panscan` is 1.0, this function will only ever grow the `rc`.
// - If `panscan` is 0.5, this function is area-preserving.
PL_API void pl_rect2df_aspect_set(pl_rect2df *rc, float aspect, float panscan);
// Set one rect's aspect to that of another
#define pl_rect2df_aspect_copy(rc, src, panscan) \
pl_rect2df_aspect_set((rc), pl_rect2df_aspect(src), (panscan))
// 'Fit' one rect inside another. `rc` will be set to the same size and aspect
// ratio as `src`, but with the size limited to fit inside the original `rc`.
// Like `pl_rect2df_aspect_set`, `panscan` controls the pan&scan factor.
PL_API void pl_rect2df_aspect_fit(pl_rect2df *rc, const pl_rect2df *src, float panscan);
// Scale rect in each direction while keeping it centered.
PL_API void pl_rect2df_stretch(pl_rect2df *rc, float stretch_x, float stretch_y);
// Offset rect by an arbitrary offset factor. If the corresponding dimension
// of a rect is flipped, so too is the applied offset.
PL_API void pl_rect2df_offset(pl_rect2df *rc, float offset_x, float offset_y);
// Scale a rect uniformly in both dimensions.
#define pl_rect2df_zoom(rc, zoom) pl_rect2df_stretch((rc), (zoom), (zoom))
// Rotation in degrees clockwise
typedef int pl_rotation;
enum {
PL_ROTATION_0 = 0,
PL_ROTATION_90 = 1,
PL_ROTATION_180 = 2,
PL_ROTATION_270 = 3,
PL_ROTATION_360 = 4, // equivalent to PL_ROTATION_0
// Note: Values outside the range [0,4) are legal, including negatives.
};
// Constrains to the interval [PL_ROTATION_0, PL_ROTATION_360).
static inline pl_rotation pl_rotation_normalize(pl_rotation rot)
{
return (rot % PL_ROTATION_360 + PL_ROTATION_360) % PL_ROTATION_360;
}
// Rotates the coordinate system of a `pl_rect2d(f)` in a certain direction.
// For example, calling this with PL_ROTATION_90 will correspond to rotating
// the coordinate system 90° to the right (so the x axis becomes the y axis).
//
// The resulting rect is re-normalized in the same coordinate system.
PL_API void pl_rect2df_rotate(pl_rect2df *rc, pl_rotation rot);
// Returns the aspect ratio in a rotated frame of reference.
static inline float pl_aspect_rotate(float aspect, pl_rotation rot)
{
return (rot % PL_ROTATION_180) ? 1.0 / aspect : aspect;
}
#define pl_rect2df_aspect_set_rot(rc, aspect, rot, panscan) \
pl_rect2df_aspect_set((rc), pl_aspect_rotate((aspect), (rot)), (panscan))
#define pl_rect2df_aspect_copy_rot(rc, src, panscan, rot) \
pl_rect2df_aspect_set_rot((rc), pl_rect2df_aspect(src), (rot), (panscan))
PL_API_END
#endif // LIBPLACEBO_COMMON_H_

View File

@ -0,0 +1,113 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_CONFIG_H_
#define LIBPLACEBO_CONFIG_H_
// Increased any time the library changes in a fundamental/major way.
#define PL_MAJOR_VER 6
// Increased any time the API changes. (Note: Does not reset when PL_MAJOR_VER
// is increased)
#define PL_API_VER 338
// Increased any time a fix is made to a given API version.
#define PL_FIX_VER (pl_fix_ver())
// Friendly name (`git describe`) for the overall version of the library
#define PL_VERSION (pl_version())
// Feature tests. These aren't described in further detail, but may be useful
// for programmers wanting to programmatically check for feature support
// in their compiled libplacebo versions.
#undef PL_HAVE_D3D11
#define PL_HAVE_DOVI 1
#define PL_HAVE_GL_PROC_ADDR 1
#undef PL_HAVE_GLSLANG
#define PL_HAVE_LCMS 1
#undef PL_HAVE_LIBDOVI
#undef PL_HAVE_OPENGL
#define PL_HAVE_SHADERC 1
#define PL_HAVE_VK_PROC_ADDR 1
#define PL_HAVE_VULKAN 1
#undef PL_HAVE_XXHASH
// Extra compiler-specific stuff
#ifndef PL_DEPRECATED
# if defined(_MSC_VER)
# define PL_DEPRECATED
# else
# define PL_DEPRECATED __attribute__((deprecated))
# endif
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifndef PL_DEPRECATED_ENUMERATOR
# if (defined(__GNUC__) && (__GNUC__ >= 6)) || __has_feature(enumerator_attributes)
# define PL_DEPRECATED_ENUMERATOR PL_DEPRECATED
# else
# define PL_DEPRECATED_ENUMERATOR
# endif
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
# ifdef PL_EXPORT
# define PL_API __declspec(dllexport)
# else
# ifndef PL_STATIC
# define PL_API __declspec(dllimport)
# else
# define PL_API
# endif
# endif
#else
# define PL_API __attribute__ ((visibility ("default")))
#endif
// C++ compatibility
#ifdef __cplusplus
# define PL_API_BEGIN extern "C" {
# define PL_API_END }
#else
# define PL_API_BEGIN
# define PL_API_END
#endif
#ifndef __cplusplus
// Disable this warning because libplacebo's params macros override fields
# pragma GCC diagnostic ignored "-Woverride-init"
#endif
// Extra helper macros
#define PL_TOSTRING_INNER(x) #x
#define PL_TOSTRING(x) PL_TOSTRING_INNER(x)
// Deprecated macro for back-compatibility
#define PL_STRUCT(name) struct name##_t
PL_API_BEGIN
PL_API int pl_fix_ver(void);
PL_API const char *pl_version(void);
PL_API_END
#endif // LIBPLACEBO_CONFIG_H_

View File

@ -0,0 +1,248 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_D3D11_H_
#define LIBPLACEBO_D3D11_H_
#include <windows.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <libplacebo/gpu.h>
#include <libplacebo/swapchain.h>
PL_API_BEGIN
// Structure representing the actual D3D11 device and associated GPU instance
typedef const struct pl_d3d11_t {
pl_gpu gpu;
// The D3D11 device in use. The user is free to use this for their own
// purposes, including taking a reference to the device (with AddRef) and
// using it beyond the lifetime of the pl_d3d11 that created it (though if
// this is done with debug enabled, it will confuse the leak checker.)
ID3D11Device *device;
// True if the device is using a software (WARP) adapter
bool software;
} *pl_d3d11;
struct pl_d3d11_params {
// The Direct3D 11 device to use. Optional, if NULL then libplacebo will
// create its own ID3D11Device using the options below. If set, all the
// options below will be ignored.
ID3D11Device *device;
// --- Adapter selection options
// The adapter to use. This overrides adapter_luid.
IDXGIAdapter *adapter;
// The LUID of the adapter to use. If adapter and adapter_luid are unset,
// the default adapter will be used instead.
LUID adapter_luid;
// Allow a software (WARP) adapter when selecting the adapter automatically.
// Note that sometimes the default adapter will be a software adapter. This
// is because, on Windows 8 and up, if there are no hardware adapters,
// Windows will pretend the WARP adapter is the default hardware adapter.
bool allow_software;
// Always use a software adapter. This is mainly for testing purposes.
bool force_software;
// --- Device creation options
// Enable the debug layer (D3D11_CREATE_DEVICE_DEBUG)
// Also logs IDXGIInfoQueue messages
bool debug;
// Extra flags to pass to D3D11CreateDevice (D3D11_CREATE_DEVICE_FLAG).
// libplacebo should be compatible with any flags passed here.
UINT flags;
// The minimum and maximum allowable feature levels for the created device.
// libplacebo will attempt to create a device with the highest feature level
// between min_feature_level and max_feature_level (inclusive.) If there are
// no supported feature levels in this range, `pl_d3d11_create` will either
// return NULL or fall back to the software adapter, depending on whether
// `allow_software` is set.
//
// Normally there is no reason to set `max_feature_level` other than to test
// if a program works at lower feature levels.
//
// Note that D3D_FEATURE_LEVEL_9_3 and below (known as 10level9) are highly
// restrictive. These feature levels are supported on a best-effort basis.
// They represent very old DirectX 9 compatible PC and laptop hardware
// (2001-2007, GeForce FX, 6, 7, ATI R300-R500, GMA 950-X3000) and some
// less-old mobile devices (Surface RT, Surface 2.) Basic video rendering
// should work, but the full pl_gpu API will not be available and advanced
// shaders will probably fail. The hardware is probably too slow for these
// anyway.
//
// Known restrictions of 10level9 devices include:
// D3D_FEATURE_LEVEL_9_3 and below:
// - `pl_pass_run_params->index_buf` will not work (but `index_data` will)
// - Dimensions of 3D textures must be powers of two
// - Shaders cannot use gl_FragCoord
// - Shaders cannot use texelFetch
// D3D_FEATURE_LEVEL_9_2 and below:
// - Fragment shaders have no dynamic flow control and very strict limits
// on the number of constants, temporary registers and instructions.
// Whether a shader meets the requirements will depend on how it's
// compiled and optimized, but it's likely that only simple shaders will
// work.
// D3D_FEATURE_LEVEL_9_1:
// - No high-bit-depth formats with PL_FMT_CAP_RENDERABLE or
// PL_FMT_CAP_LINEAR
//
// If these restrictions are undesirable and you don't need to support
// ancient hardware, set `min_feature_level` to D3D_FEATURE_LEVEL_10_0.
int min_feature_level; // Defaults to D3D_FEATURE_LEVEL_9_1 if unset
int max_feature_level; // Defaults to D3D_FEATURE_LEVEL_12_1 if unset
// Allow up to N in-flight frames. Similar to swapchain_depth for Vulkan and
// OpenGL, though with DXGI this is a device-wide setting that affects all
// swapchains (except for waitable swapchains.) See the documentation for
// `pl_swapchain_latency` for more information.
int max_frame_latency;
};
// Default/recommended parameters. Should generally be safe and efficient.
#define PL_D3D11_DEFAULTS \
.allow_software = true,
#define pl_d3d11_params(...) (&(struct pl_d3d11_params) { PL_D3D11_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_d3d11_params pl_d3d11_default_params;
// Creates a new Direct3D 11 device based on the given parameters, or wraps an
// existing device, and initializes a new GPU instance. If params is left as
// NULL, it defaults to &pl_d3d11_default_params. If an existing device is
// provided in params->device, `pl_d3d11_create` will take a reference to it
// that will be released in `pl_d3d11_destroy`.
PL_API pl_d3d11 pl_d3d11_create(pl_log log, const struct pl_d3d11_params *params);
// Release the D3D11 device.
//
// Note that all libplacebo objects allocated from this pl_d3d11 object (e.g.
// via `d3d11->gpu` or using `pl_d3d11_create_swapchain`) *must* be explicitly
// destroyed by the user before calling this.
PL_API void pl_d3d11_destroy(pl_d3d11 *d3d11);
// For a `pl_gpu` backed by `pl_d3d11`, this function can be used to retrieve
// the underlying `pl_d3d11`. Returns NULL for any other type of `gpu`.
PL_API pl_d3d11 pl_d3d11_get(pl_gpu gpu);
struct pl_d3d11_swapchain_params {
// The Direct3D 11 swapchain to wrap. Optional. If NULL, libplacebo will
// create its own swapchain using the options below. If set, all the
// swapchain creation options will be ignored.
//
// The provided swapchain must have been created by the same device used
// by `gpu` and must not have multisampled backbuffers.
IDXGISwapChain *swapchain;
// --- Swapchain creation options
// Initial framebuffer width and height. If both width and height are set to
// 0 and window is non-NULL, the client area of the window is used instead.
// For convenience, if either component would be 0, it is set to 1 instead.
// This is because Windows can have 0-sized windows, but not 0-sized
// swapchains.
int width;
int height;
// The handle of the output window. In Windows 8 and up this is optional
// because you can output to a CoreWindow or create a composition swapchain
// instead.
HWND window;
// A pointer to the CoreWindow to output to. If both this and `window` are
// NULL, CreateSwapChainForComposition will be used to create the swapchain.
IUnknown *core_window;
// If set, libplacebo will create a swapchain that uses the legacy bitblt
// presentation model (with the DXGI_SWAP_EFFECT_DISCARD swap effect.) This
// tends to give worse performance and frame pacing in windowed mode and it
// prevents borderless fullscreen optimizations, but it might be necessary
// to work around buggy drivers, especially with DXGI 1.2 in the Platform
// Update for Windows 7. When unset, libplacebo will try to use the flip
// presentation model and only fall back to bitblt if flip is unavailable.
bool blit;
// additional swapchain flags
// No validation on these flags is being performed, and swapchain creation
// may fail if an unsupported combination is requested.
UINT flags;
// --- Swapchain usage behavior options
// Disable using a 10-bit swapchain format for SDR output
bool disable_10bit_sdr;
};
#define pl_d3d11_swapchain_params(...) (&(struct pl_d3d11_swapchain_params) { __VA_ARGS__ })
// Creates a new Direct3D 11 swapchain, or wraps an existing one. If an existing
// swapchain is provided in params->swapchain, `pl_d3d11_create_swapchain` will
// take a reference to it that will be released in `pl_swapchain_destroy`.
PL_API pl_swapchain pl_d3d11_create_swapchain(pl_d3d11 d3d11,
const struct pl_d3d11_swapchain_params *params);
// Takes a `pl_swapchain` created by pl_d3d11_create_swapchain and returns a
// reference to the underlying IDXGISwapChain. This increments the refcount, so
// call IDXGISwapChain::Release when finished with it.
PL_API IDXGISwapChain *pl_d3d11_swapchain_unwrap(pl_swapchain sw);
struct pl_d3d11_wrap_params {
// The D3D11 texture to wrap, or a texture array containing the texture to
// wrap. Must be a ID3D11Texture1D, ID3D11Texture2D or ID3D11Texture3D
// created by the same device used by `gpu`, must have D3D11_USAGE_DEFAULT,
// and must not be mipmapped or multisampled.
ID3D11Resource *tex;
// If tex is a texture array, this is the array member to use as the pl_tex.
int array_slice;
// If tex is a video resource (eg. DXGI_FORMAT_AYUV, DXGI_FORMAT_NV12,
// DXGI_FORMAT_P010, etc.,) it can be wrapped as a pl_tex by specifying the
// type and size of the shader view. For planar video formats, the plane
// that is wrapped depends on the chosen format.
//
// If tex is not a video resource, these fields are unnecessary. The correct
// format will be determined automatically. If tex is not 2D, these fields
// are ignored.
//
// For a list of supported video formats and their corresponding view
// formats and sizes, see:
// https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#VideoViews
DXGI_FORMAT fmt;
int w;
int h;
};
#define pl_d3d11_wrap_params(...) (&(struct pl_d3d11_wrap_params) { __VA_ARGS__ })
// Wraps an external texture into a pl_tex abstraction. `pl_d3d11_wrap` takes a
// reference to the texture, which is released when `pl_tex_destroy` is called.
//
// This function may fail due to incompatible formats, incompatible flags or
// other reasons, in which case it will return NULL.
PL_API pl_tex pl_d3d11_wrap(pl_gpu gpu, const struct pl_d3d11_wrap_params *params);
PL_API_END
#endif // LIBPLACEBO_D3D11_H_

View File

@ -0,0 +1,239 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_DISPATCH_H_
#define LIBPLACEBO_DISPATCH_H_
#include <libplacebo/shaders.h>
#include <libplacebo/gpu.h>
PL_API_BEGIN
// Thread-safety: Safe
typedef struct pl_dispatch_t *pl_dispatch;
// Creates a new shader dispatch object. This object provides a translation
// layer between generated shaders (pl_shader) and the ra context such that it
// can be used to execute shaders. This dispatch object will also provide
// shader caching (for efficient re-use).
PL_API pl_dispatch pl_dispatch_create(pl_log log, pl_gpu gpu);
PL_API void pl_dispatch_destroy(pl_dispatch *dp);
// Reset/increments the internal counters of the pl_dispatch. This must be
// called whenever the user is going to begin with a new frame, in order to
// perform garbage collection and advance the state of the internal PRNG.
//
// Note that shaders generated by `pl_dispatch` are therefore entirely
// deterministic, as long as the sequence of calls (and inputs to the shader)
// are the same.
PL_API void pl_dispatch_reset_frame(pl_dispatch dp);
// Returns a blank pl_shader object, suitable for recording rendering commands.
// For more information, see the header documentation in `shaders/*.h`.
PL_API pl_shader pl_dispatch_begin(pl_dispatch dp);
// Struct passed to `info_callback`. Only valid until that function returns.
struct pl_dispatch_info {
// Information about the shader for this shader execution, as well as a
// 64-bit signature uniquely identifying it.
pl_shader_info shader;
uint64_t signature;
// A list of execution times for this pass, in nanoseconds. May be empty.
uint64_t samples[256];
int num_samples;
// As a convenience, this contains the last, average and peak of the above
// list of samples. If `num_samples` is 0, these values are also 0.
uint64_t last;
uint64_t peak;
uint64_t average;
};
// Helper function to make a copy of `pl_dispatch_info`, while overriding
// (and dereferencing) whatever was previously stored there.
static inline void pl_dispatch_info_move(struct pl_dispatch_info *dst,
const struct pl_dispatch_info *src)
{
pl_shader_info_deref(&dst->shader);
*dst = *src;
dst->shader = pl_shader_info_ref(src->shader);
}
// Set up a dispatch callback for this `pl_dispatch` object. The given callback
// will be run for every successfully dispatched shader. Call this again with
// `cb == NULL` to disable.
PL_API void pl_dispatch_callback(pl_dispatch dp, void *priv,
void (*cb)(void *priv,
const struct pl_dispatch_info *));
struct pl_dispatch_params {
// The shader to execute. The pl_dispatch will take over ownership
// of this shader, and return it back to the internal pool.
//
// This shader must have a compatible signature, i.e. inputs
// `PL_SHADER_SIG_NONE` and outputs `PL_SHADER_SIG_COLOR`.
pl_shader *shader;
// The texture to render to. This must have params compatible with the
// shader, i.e. `target->params.renderable` for fragment shaders and
// `target->params.storable` for compute shaders.
//
// Note: Even when not using compute shaders, users are advised to always
// set `target->params.storable` if permitted by the `pl_fmt`, since this
// allows the use of compute shaders instead of full-screen quads, which is
// faster on some platforms.
pl_tex target;
// The target rect to render to. Optional, if left as {0}, then the
// entire texture will be rendered to.
pl_rect2d rect;
// If set, enables and controls the blending for this pass. Optional. When
// using this with fragment shaders, `target->params.fmt->caps` must
// include `PL_FMT_CAP_BLENDABLE`.
const struct pl_blend_params *blend_params;
// If set, records the execution time of this dispatch into the given
// timer object. Optional.
//
// Note: If this is set, `pl_dispatch` cannot internally measure the
// execution time of the shader, which means `pl_dispatch_info.samples` may
// be empty as a result.
pl_timer timer;
};
#define pl_dispatch_params(...) (&(struct pl_dispatch_params) { __VA_ARGS__ })
// Dispatch a generated shader (via the pl_shader mechanism). Returns whether
// or not the dispatch was successful.
PL_API bool pl_dispatch_finish(pl_dispatch dp, const struct pl_dispatch_params *params);
struct pl_dispatch_compute_params {
// The shader to execute. This must be a compute shader with the input
// set to PL_SHADER_SIG_NONE. The output, if it has any, is ignored.
pl_shader *shader;
// The number of work groups to dispatch in each dimension. If this is left
// as [0} and `width/height` are both set, the number of work groups will
// be inferred from the shader's `compute_group_sizes`.
int dispatch_size[3];
// If set, simulate vertex attributes (similar to `pl_dispatch_finish`)
// according to the given dimensions. The first two components of the
// thread's global ID will be interpreted as the X and Y locations.
//
// Optional, ignored if either component is left as 0.
int width, height;
// If set, records the execution time of this dispatch into the given
// timer object. Optional.
//
// Note: If this is set, `pl_dispatch` cannot internally measure the
// execution time of the shader, which means `pl_dispatch_info.samples` may
// be empty as a result.
pl_timer timer;
};
#define pl_dispatch_compute_params(...) (&(struct pl_dispatch_compute_params) { __VA_ARGS__ })
// A variant of `pl_dispatch_finish`, this one only dispatches a compute shader
// while ignoring its output (if it has one). It's only useful for shaders
// which have otherwise observable side effects (such as updating state
// objects).
PL_API bool pl_dispatch_compute(pl_dispatch dp, const struct pl_dispatch_compute_params *params);
enum pl_vertex_coords {
PL_COORDS_ABSOLUTE, // Absolute/integer `target` coordinates
PL_COORDS_RELATIVE, // Relative `target` coordinates in range [0, 1]
PL_COORDS_NORMALIZED, // GL-normalized coordinates in range [-1, 1]
};
struct pl_dispatch_vertex_params {
// The shader to execute. This must be a raster shader with the input set
// to `PL_SHADER_SIG_NONE` and the output set to `PL_SHADER_SIG_COLOR`.
//
// Additionally, the shader must not have any attached vertex attributes.
pl_shader *shader;
// The texture to render to. Requires `target->params.renderable`.
pl_tex target;
// The target rect to clip the rendering to. (Optional)
pl_rect2d scissors;
// If set, enables and controls the blending for this pass. Optional. When
// enabled, `target->params.fmt->caps` must include `PL_FMT_CAP_BLENDABLE`.
const struct pl_blend_params *blend_params;
// The description of the vertex format, including offsets.
//
// Note: `location` is ignored and can safely be left unset.
const struct pl_vertex_attrib *vertex_attribs;
int num_vertex_attribs;
size_t vertex_stride;
// The index of the vertex position in `vertex_attribs`, as well as the
// interpretation of its contents.
int vertex_position_idx;
enum pl_vertex_coords vertex_coords;
bool vertex_flipped; // flip all vertex y coordinates
// Type and number of vertices to render.
enum pl_prim_type vertex_type;
int vertex_count;
// Vertex data. See `pl_pass_run_params.vertex_data`.
const void *vertex_data;
pl_buf vertex_buf;
size_t buf_offset;
// Index data. See `pl_pass_run_params.index_data`. Optional.
const void *index_data;
enum pl_index_format index_fmt;
pl_buf index_buf;
size_t index_offset;
// If set, records the execution time of this dispatch into the given
// timer object. Optional.
//
// Note: If this is set, `pl_dispatch` cannot internally measure the
// execution time of the shader, which means `pl_dispatch_info.samples` may
// be empty as a result.
pl_timer timer;
};
#define pl_dispatch_vertex_params(...) (&(struct pl_dispatch_vertex_params) { __VA_ARGS__ })
// Dispatch a generated shader using custom vertices, rather than using a quad
// generated by the dispatch. This allows the use of e.g. custom fragment
// shaders for things like rendering custom UI elements, or possibly doing
// advanced things like sampling from a cube map or spherical video.
PL_API bool pl_dispatch_vertex(pl_dispatch dp, const struct pl_dispatch_vertex_params *params);
// Cancel an active shader without submitting anything. Useful, for example,
// if the shader was instead merged into a different shader.
PL_API void pl_dispatch_abort(pl_dispatch dp, pl_shader *sh);
// Deprecated in favor of `pl_cache_save/pl_cache_load` on the `pl_cache`
// associated with the `pl_gpu` this dispatch is using.
PL_DEPRECATED PL_API size_t pl_dispatch_save(pl_dispatch dp, uint8_t *out_cache);
PL_DEPRECATED PL_API void pl_dispatch_load(pl_dispatch dp, const uint8_t *cache);
PL_API_END
#endif // LIBPLACEBO_DISPATCH_H

View File

@ -0,0 +1,82 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_DITHER_H_
#define LIBPLACEBO_DITHER_H_
#include <libplacebo/common.h>
PL_API_BEGIN
// Generates a deterministic NxN bayer (ordered) dither matrix, storing the
// result in `data`. `size` must be a power of two. The resulting matrix will
// be roughly uniformly distributed within the range [0,1).
PL_API void pl_generate_bayer_matrix(float *data, int size);
// Generates a random NxN blue noise texture. storing the result in `data`.
// `size` must be a positive power of two no larger than 256. The resulting
// texture will be roughly uniformly distributed within the range [0,1).
//
// Note: This function is very, *very* slow for large sizes. Generating a
// dither matrix with size 256 can take several seconds on a modern processor.
PL_API void pl_generate_blue_noise(float *data, int size);
// Defines the border of all error diffusion kernels
#define PL_EDF_MIN_DX (-2)
#define PL_EDF_MAX_DX (2)
#define PL_EDF_MAX_DY (2)
struct pl_error_diffusion_kernel {
const char *name; // Short and concise identifier
const char *description; // Longer / friendly name
// The minimum value such that a (y, x) -> (y, x + y * shift) mapping will
// make all error pushing operations affect next column (and after it)
// only.
//
// Higher shift values are significantly more computationally intensive.
int shift;
// The diffusion factor for (y, x) is pattern[y][x - PL_EDF_MIN_DX] / divisor.
int pattern[PL_EDF_MAX_DY + 1][PL_EDF_MAX_DX - PL_EDF_MIN_DX + 1];
int divisor;
};
// Algorithms with shift=1:
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_simple;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_false_fs;
// Algorithms with shift=2:
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_sierra_lite;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_floyd_steinberg;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_atkinson;
// Algorithms with shift=3, probably too heavy for low end GPUs:
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_jarvis_judice_ninke;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_stucki;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_burkes;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_sierra2;
PL_API extern const struct pl_error_diffusion_kernel pl_error_diffusion_sierra3;
// A list of built-in error diffusion kernels, terminated by NULL
PL_API extern const struct pl_error_diffusion_kernel * const pl_error_diffusion_kernels[];
PL_API extern const int pl_num_error_diffusion_kernels; // excluding trailing NULL
// Find the error diffusion kernel with the given name, or NULL on failure.
PL_API const struct pl_error_diffusion_kernel *pl_find_error_diffusion_kernel(const char *name);
PL_API_END
#endif // LIBPLACEBO_DITHER_H_

View File

@ -0,0 +1,131 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_DUMMY_H_
#define LIBPLACEBO_DUMMY_H_
#include <libplacebo/gpu.h>
PL_API_BEGIN
// The functions in this file allow creating and manipulating "dummy" contexts.
// A dummy context isn't actually mapped by the GPU, all data exists purely on
// the CPU. It also isn't capable of compiling or executing any shaders, any
// attempts to do so will simply fail.
//
// The main use case for this dummy context is for users who want to generate
// advanced shaders that depend on specific GLSL features or support for
// certain types of GPU resources (e.g. LUTs). This dummy context allows such
// shaders to be generated, with all of the referenced shader objects and
// textures simply containing their data in a host-accessible way.
struct pl_gpu_dummy_params {
// These GPU parameters correspond to their equivalents in `pl_gpu`, and
// must obey the same rules as documented there. The values from
// `pl_gpu_dummy_default_params` are set to support pretty much everything
// and are set for GLSL version 450.
//
// Individual fields such as `glsl.compute` or `glsl.version` description
// can and should be overridden by the user based on their requirements.
// Individual limits should ideally be set based on the corresponding
// `glGet` queries etc.
struct pl_glsl_version glsl;
struct pl_gpu_limits limits;
};
#define PL_GPU_DUMMY_DEFAULTS \
.glsl = { \
.version = 450, \
.gles = false, \
.vulkan = false, \
.compute = true, \
.max_shmem_size = SIZE_MAX, \
.max_group_threads = 1024, \
.max_group_size = { 1024, 1024, 1024 }, \
.subgroup_size = 32, \
.min_gather_offset = INT16_MIN, \
.max_gather_offset = INT16_MAX, \
}, \
.limits = { \
/* pl_gpu */ \
.callbacks = false, \
.thread_safe = true, \
/* pl_buf */ \
.max_buf_size = SIZE_MAX, \
.max_ubo_size = SIZE_MAX, \
.max_ssbo_size = SIZE_MAX, \
.max_vbo_size = SIZE_MAX, \
.max_mapped_size = SIZE_MAX, \
.max_buffer_texels = UINT64_MAX, \
/* pl_tex */ \
.max_tex_1d_dim = UINT32_MAX, \
.max_tex_2d_dim = UINT32_MAX, \
.max_tex_3d_dim = UINT32_MAX, \
.buf_transfer = true, \
.align_tex_xfer_pitch = 1, \
.align_tex_xfer_offset = 1, \
/* pl_pass */ \
.max_variable_comps = SIZE_MAX, \
.max_constants = SIZE_MAX, \
.max_pushc_size = SIZE_MAX, \
.max_dispatch = { UINT32_MAX, UINT32_MAX, UINT32_MAX }, \
.fragment_queues = 0, \
.compute_queues = 0, \
},
#define pl_gpu_dummy_params(...) (&(struct pl_gpu_dummy_params) { PL_GPU_DUMMY_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_gpu_dummy_params pl_gpu_dummy_default_params;
// Create a dummy GPU context based on the given parameters. This GPU will have
// a format for each host-representable type (i.e. intN_t, floats and doubles),
// in the canonical channel order RGBA. These formats will have every possible
// capability activated, respectively.
//
// If `params` is left as NULL, it defaults to `&pl_gpu_dummy_params`.
PL_API pl_gpu pl_gpu_dummy_create(pl_log log, const struct pl_gpu_dummy_params *params);
PL_API void pl_gpu_dummy_destroy(pl_gpu *gpu);
// Back-doors into the `pl_tex` and `pl_buf` representations. These allow you
// to access the raw data backing this object. Textures are always laid out in
// a tightly packed manner.
//
// For "placeholder" dummy textures, this always returns NULL.
PL_API uint8_t *pl_buf_dummy_data(pl_buf buf);
PL_API uint8_t *pl_tex_dummy_data(pl_tex tex);
// Skeleton of `pl_tex_params` containing only the fields relevant to
// `pl_tex_dummy_create`, plus the extra `sampler_type` field.
struct pl_tex_dummy_params {
int w, h, d;
pl_fmt format;
enum pl_sampler_type sampler_type;
void *user_data;
};
#define pl_tex_dummy_params(...) (&(struct pl_tex_dummy_params) { __VA_ARGS__ })
// Allows creating a "placeholder" dummy texture. This is basically a texture
// that isn't even backed by anything. All `pl_tex_*` operations (other than
// `pl_tex_destroy`) performed on it will simply fail.
//
// All of the permissions will be set to `false`, except `sampleable`, which is
// set to `true`. (So you can use it as an input to shader sampling functions)
PL_API pl_tex pl_tex_dummy_create(pl_gpu gpu, const struct pl_tex_dummy_params *params);
PL_API_END
#endif // LIBPLACEBO_DUMMY_H_

View File

@ -0,0 +1,415 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_FILTER_KERNELS_H_
#define LIBPLACEBO_FILTER_KERNELS_H_
#include <stdbool.h>
#include <libplacebo/log.h>
PL_API_BEGIN
#define PL_FILTER_MAX_PARAMS 2
// Invocation parameters for a given kernel
struct pl_filter_ctx {
float radius;
float params[PL_FILTER_MAX_PARAMS];
};
// Represents a single filter function, i.e. kernel or windowing function.
struct pl_filter_function {
// The cosmetic name associated with this filter function.
const char *name;
// The radius of the filter function. For resizable filters, this gives
// the radius needed to represent a single filter lobe (tap).
float radius;
// If true, the filter function is resizable (see pl_filter_config.radius)
bool resizable;
// If true, the filter function is tunable (see pl_filter_config.params)
bool tunable[PL_FILTER_MAX_PARAMS];
// If the relevant parameter is tunable, this contains the default values.
float params[PL_FILTER_MAX_PARAMS];
// The underlying filter function itself: Computes the weight as a function
// of the offset. All filter functions must be normalized such that x=0 is
// the center point, and in particular weight(0) = 1.0. The functions may
// be undefined for values of x outside [0, radius].
double (*weight)(const struct pl_filter_ctx *f, double x);
// If true, this filter represents an opaque placeholder for a more
// sophisticated filter function which does not fit into the pl_filter
// framework. `weight()` will always return 0.0.
bool opaque;
};
// Deprecated function, merely checks a->weight == b->weight
PL_DEPRECATED PL_API bool
pl_filter_function_eq(const struct pl_filter_function *a,
const struct pl_filter_function *b);
// Box filter: Entirely 1.0 within the radius, entirely 0.0 outside of it.
// This is also sometimes called a Dirichlet window
PL_API extern const struct pl_filter_function pl_filter_function_box;
// Triangle filter: Linear transitions from 1.0 at x=0 to 0.0 at x=radius.
// This is also sometimes called a Bartlett window.
PL_API extern const struct pl_filter_function pl_filter_function_triangle;
// Cosine filter: Ordinary cosine function, single lobe.
PL_API extern const struct pl_filter_function pl_filter_function_cosine;
// Hann function: Cosine filter named after Julius von Hann. Also commonly
// mislabeled as a "Hanning" function, due to its similarly to the Hamming
// function.
PL_API extern const struct pl_filter_function pl_filter_function_hann;
// Hamming function: Cosine filter named after Richard Hamming.
PL_API extern const struct pl_filter_function pl_filter_function_hamming;
// Welch filter: Polynomial function consisting of a single parabolic section.
PL_API extern const struct pl_filter_function pl_filter_function_welch;
// Kaiser filter: Approximation of the DPSS window using Bessel functions.
// Also sometimes called a Kaiser-Bessel window.
// Parameter [0]: Shape (alpha). Determines the trade-off between the main lobe
// and the side lobes.
PL_API extern const struct pl_filter_function pl_filter_function_kaiser;
// Blackman filter: Cosine filter named after Ralph Beebe Blackman.
// Parameter [0]: Scale (alpha). Influences the shape. The defaults result in
// zeros at the third and fourth sidelobes.
PL_API extern const struct pl_filter_function pl_filter_function_blackman;
// Bohman filter: 2nd order Cosine filter.
PL_API extern const struct pl_filter_function pl_filter_function_bohman;
// Gaussian function: Similar to the Gaussian distribution, this defines a
// bell curve function.
// Parameter [0]: Scale (t), increasing makes the result blurrier.
PL_API extern const struct pl_filter_function pl_filter_function_gaussian;
// Quadratic function: 2nd order approximation of the gaussian function. Also
// sometimes called a "quadric" window.
PL_API extern const struct pl_filter_function pl_filter_function_quadratic;
// Sinc function: Widely used for both kernels and windows, sinc(x) = sin(x)/x.
PL_API extern const struct pl_filter_function pl_filter_function_sinc;
// Jinc function: Similar to sinc, but extended to the 2D domain. Widely
// used as the kernel of polar (EWA) filters. Also sometimes called a Sombrero
// function.
PL_API extern const struct pl_filter_function pl_filter_function_jinc;
// Sphinx function: Similar to sinc and jinx, but extended to the 3D domain.
// The name is derived from "spherical" sinc. Can be used to filter 3D signals
// in theory.
PL_API extern const struct pl_filter_function pl_filter_function_sphinx;
// B/C-tunable Spline function: This is a family of commonly used spline
// functions with two tunable parameters. Does not need to be windowed.
// Parameter [0]: "B"
// Parameter [1]: "C"
// Some popular variants of this function are:
// B = 1.0, C = 0.0: "base" Cubic (blurry)
// B = 0.0, C = 0.0: Hermite filter (blocky)
// B = 0.0, C = 0.5: Catmull-Rom filter (sharp)
// B = 1/3, C = 1/3: Mitchell-Netravali filter (soft, doesn't ring)
// B ≈ 0.37, C ≈ 0.31: Robidoux filter (used by ImageMagick)
// B ≈ 0.26, C ≈ 0.37: RobidouxSharp filter (sharper variant of Robidoux)
PL_API extern const struct pl_filter_function pl_filter_function_cubic;
PL_API extern const struct pl_filter_function pl_filter_function_hermite;
#define pl_filter_function_bicubic pl_filter_function_cubic
#define pl_filter_function_bcspline pl_filter_function_cubic
// Cubic splines with 2/3/4 taps. Referred to as "spline16", "spline36", and
// "spline64" mainly for historical reasons, based on the number of pixels in
// their window when using them as 2D orthogonal filters. Do not need to be
// windowed.
PL_API extern const struct pl_filter_function pl_filter_function_spline16;
PL_API extern const struct pl_filter_function pl_filter_function_spline36;
PL_API extern const struct pl_filter_function pl_filter_function_spline64;
// Special filter function for the built-in oversampling algorithm. This is an
// opaque filter with no meaningful representation. though it has one tunable
// parameter controlling the threshold at which to switch back to ordinary
// nearest neighbour sampling. (See `pl_shader_sample_oversample`)
PL_API extern const struct pl_filter_function pl_filter_function_oversample;
// A list of built-in filter functions, terminated by NULL
//
// Note: May contain extra aliases for the above functions.
PL_API extern const struct pl_filter_function * const pl_filter_functions[];
PL_API extern const int pl_num_filter_functions; // excluding trailing NULL
// Find the filter function with the given name, or NULL on failure.
PL_API const struct pl_filter_function *pl_find_filter_function(const char *name);
// Backwards compatibility with the older configuration API. Redundant with
// `pl_filter_function.name`. May be formally deprecated in the future.
struct pl_filter_function_preset {
const char *name;
const struct pl_filter_function *function;
};
// A list of built-in filter function presets, terminated by {0}
PL_API extern const struct pl_filter_function_preset pl_filter_function_presets[];
PL_API extern const int pl_num_filter_function_presets; // excluding trailing {0}
// Find the filter function preset with the given name, or NULL on failure.
PL_API const struct pl_filter_function_preset *pl_find_filter_function_preset(const char *name);
// Different usage domains for a filter
enum pl_filter_usage {
PL_FILTER_UPSCALING = (1 << 0),
PL_FILTER_DOWNSCALING = (1 << 1),
PL_FILTER_FRAME_MIXING = (1 << 2),
PL_FILTER_SCALING = PL_FILTER_UPSCALING | PL_FILTER_DOWNSCALING,
PL_FILTER_ALL = PL_FILTER_SCALING | PL_FILTER_FRAME_MIXING,
};
// Represents a tuned combination of filter functions, plus parameters
struct pl_filter_config {
// The cosmetic name associated with this filter config. Optional for
// user-provided configs, but always set by built-in configurations.
const char *name;
// Longer / friendly name. Always set for built-in configurations,
// except for names which are merely aliases of other filters.
const char *description;
// Allowed and recommended usage domains (respectively)
//
// When it is desired to maintain a simpler user interface, it may be
// recommended to include only scalers whose recommended usage domains
// includes the relevant context in which it will be used.
enum pl_filter_usage allowed;
enum pl_filter_usage recommended;
// The kernel function and (optionally) windowing function.
const struct pl_filter_function *kernel;
const struct pl_filter_function *window;
// The radius. Ignored if !kernel->resizable. Optional, defaults to
// kernel->radius if unset.
float radius;
// Parameters for the respective filter function. Ignored if not tunable.
float params[PL_FILTER_MAX_PARAMS];
float wparams[PL_FILTER_MAX_PARAMS];
// Represents a clamping coefficient for negative weights. A value of 0.0
// (the default) represents no clamping. A value of 1.0 represents full
// clamping, i.e. all negative weights will be clamped to 0. Values in
// between will be linearly scaled.
float clamp;
// Additional blur coefficient. This effectively stretches the kernel,
// without changing the effective radius of the filter radius. Setting this
// to a value of 0.0 is equivalent to disabling it. Values significantly
// below 1.0 may seriously degrade the visual output, and should be used
// with care.
float blur;
// Additional taper coefficient. This essentially flattens the function's
// center. The values within [-taper, taper] will return 1.0, with the
// actual function being squished into the remainder of [taper, radius].
// Defaults to 0.0.
float taper;
// If true, this filter is intended to be used as a polar/2D filter (EWA)
// instead of a separable/1D filter. Does not affect the actual sampling,
// but provides information about how the results are to be interpreted.
bool polar;
// Antiringing strength. A value of 0.0 disables antiringing, and a value
// of 1.0 enables full-strength antiringing. Defaults to 0.0 if
// unspecified.
//
// Note: This is only included in `pl_filter_config` for convenience. Does
// not affect the actual filter sampling, but provides information to the
// downstream consumer of the `pl_filter`.
float antiring;
};
PL_API bool pl_filter_config_eq(const struct pl_filter_config *a,
const struct pl_filter_config *b);
// Samples a given filter configuration at a given x coordinate, while
// respecting all parameters of the configuration.
PL_API double pl_filter_sample(const struct pl_filter_config *c, double x);
// A list of built-in filter configurations. Since they are just combinations
// of the above filter functions, they are not described in much further
// detail.
PL_API extern const struct pl_filter_config pl_filter_spline16; // 2 taps
PL_API extern const struct pl_filter_config pl_filter_spline36; // 3 taps
PL_API extern const struct pl_filter_config pl_filter_spline64; // 4 taps
PL_API extern const struct pl_filter_config pl_filter_nearest;
PL_API extern const struct pl_filter_config pl_filter_box;
PL_API extern const struct pl_filter_config pl_filter_bilinear;
PL_API extern const struct pl_filter_config pl_filter_gaussian;
// Sinc family (all configured to 3 taps):
PL_API extern const struct pl_filter_config pl_filter_sinc; // unwindowed
PL_API extern const struct pl_filter_config pl_filter_lanczos; // sinc-sinc
PL_API extern const struct pl_filter_config pl_filter_ginseng; // sinc-jinc
PL_API extern const struct pl_filter_config pl_filter_ewa_jinc; // unwindowed
PL_API extern const struct pl_filter_config pl_filter_ewa_lanczos; // jinc-jinc
PL_API extern const struct pl_filter_config pl_filter_ewa_lanczossharp;
PL_API extern const struct pl_filter_config pl_filter_ewa_lanczos4sharpest;
PL_API extern const struct pl_filter_config pl_filter_ewa_ginseng; // jinc-sinc
PL_API extern const struct pl_filter_config pl_filter_ewa_hann; // jinc-hann
// Spline family
PL_API extern const struct pl_filter_config pl_filter_bicubic;
PL_API extern const struct pl_filter_config pl_filter_hermite;
PL_API extern const struct pl_filter_config pl_filter_catmull_rom;
PL_API extern const struct pl_filter_config pl_filter_mitchell;
PL_API extern const struct pl_filter_config pl_filter_mitchell_clamp; // clamp = 1.0
PL_API extern const struct pl_filter_config pl_filter_robidoux;
PL_API extern const struct pl_filter_config pl_filter_robidouxsharp;
PL_API extern const struct pl_filter_config pl_filter_ewa_robidoux;
PL_API extern const struct pl_filter_config pl_filter_ewa_robidouxsharp;
// Special/opaque filters
PL_API extern const struct pl_filter_config pl_filter_oversample;
// Backwards compatibility
#define pl_filter_triangle pl_filter_bilinear
#define pl_oversample_frame_mixer pl_filter_oversample
// A list of built-in filter configs, terminated by NULL
PL_API extern const struct pl_filter_config * const pl_filter_configs[];
PL_API extern const int pl_num_filter_configs; // excluding trailing NULL
// Find the filter config with the given name, or NULL on failure.
// `usage` restricts the valid usage (based on `pl_filter_config.allowed`).
PL_API const struct pl_filter_config *
pl_find_filter_config(const char *name, enum pl_filter_usage usage);
// Backward compatibility with the previous filter configuration API. Redundant
// with pl_filter_config.name/description. May be deprecated in the future.
struct pl_filter_preset {
const char *name;
const struct pl_filter_config *filter;
// Longer / friendly name, or NULL for aliases
const char *description;
};
// A list of built-in filter presets, terminated by {0}
PL_API extern const struct pl_filter_preset pl_filter_presets[];
PL_API extern const int pl_num_filter_presets; // excluding trailing {0}
// Find the filter preset with the given name, or NULL on failure.
PL_API const struct pl_filter_preset *pl_find_filter_preset(const char *name);
// Parameters for filter generation.
struct pl_filter_params {
// The particular filter configuration to be sampled. config.kernel must
// be set to a valid pl_filter_function.
struct pl_filter_config config;
// The precision of the resulting LUT. A value of 64 should be fine for
// most practical purposes, but higher or lower values may be justified
// depending on the use case. This value must be set to something > 0.
int lut_entries;
// --- Polar filers only (config.polar)
// As a micro-optimization, all samples below this cutoff value will be
// ignored when updating the cutoff radius. Setting it to a value of 0.0
// disables this optimization.
float cutoff;
// --- Separable filters only (!config.polar)
// Indicates the maximum row size that is supported by the calling code, or
// 0 for no limit.
int max_row_size;
// Indicates the row stride alignment. For some use cases (e.g. uploading
// the weights as a texture), there are certain alignment requirements for
// each row. The chosen row_size will always be a multiple of this value.
// Specifying 0 indicates no alignment requirements.
int row_stride_align;
// --- Deprecated options
float filter_scale PL_DEPRECATED; // no effect, use `config.blur` instead
};
#define pl_filter_params(...) (&(struct pl_filter_params) { __VA_ARGS__ })
// Represents an initialized instance of a particular filter, with a
// precomputed LUT. The interpretation of the LUT depends on the type of the
// filter (polar or separable).
typedef const struct pl_filter_t {
// Deep copy of the parameters, for convenience.
struct pl_filter_params params;
// Contains the true radius of the computed filter. This may be
// smaller than the configured radius depending on the exact filter
// parameters used. Mainly relevant for polar filters, since
// it affects the value range of *weights.
float radius;
// Radius of the first zero crossing (main lobe size).
float radius_zero;
// The computed look-up table (LUT). For polar filters, this is interpreted
// as a 1D array with dimensions [lut_entries] containing the raw filter
// samples on the scale [0, radius]. For separable (non-polar) filters,
// this is interpreted as a 2D array with dimensions
// [lut_entries][row_stride]. The inner rows contain the `row_size` samples
// to convolve with the corresponding input pixels. The outer coordinate is
// used to very the fractional offset (phase). So for example, if the
// sample position to reconstruct is directly aligned with the source
// texels, you would use the values from weights[0]. If the sample position
// to reconstruct is exactly half-way between two source texels (180° out
// of phase), you would use the values from weights[lut_entries/2].
const float *weights;
// --- separable filters only (!params.config.polar)
// The number of source texels to convolve over for each row. This value
// will never exceed the given `max_row_size`. If the filter ends up
// cut off because of this, the bool `insufficient` will be set to true.
int row_size;
bool insufficient;
// The separation (in *weights) between each row of the filter. Always
// a multiple of params.row_stride_align.
int row_stride;
// --- deprecated / removed fields
float radius_cutoff PL_DEPRECATED; // identical to `radius`
} *pl_filter;
// Generate (compute) a filter instance based on a given filter configuration.
// The resulting pl_filter must be freed with `pl_filter_free` when no longer
// needed. Returns NULL if filter generation fails due to invalid parameters
// (i.e. missing a required parameter).
PL_API pl_filter pl_filter_generate(pl_log log, const struct pl_filter_params *params);
PL_API void pl_filter_free(pl_filter *filter);
PL_API_END
#endif // LIBPLACEBO_FILTER_KERNELS_H_

View File

@ -0,0 +1,182 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_GAMUT_MAPPING_H_
#define LIBPLACEBO_GAMUT_MAPPING_H_
#include <libplacebo/common.h>
#include <libplacebo/colorspace.h>
PL_API_BEGIN
struct pl_gamut_map_params;
struct pl_gamut_map_function {
const char *name; // Identifier
const char *description; // Friendly / longer name
// The gamut-mapping function itself. Iterates over all values in `lut`,
// and adapts them as needed.
void (*map)(float *lut, const struct pl_gamut_map_params *params);
// Returns true if `map` supports both stretching and contracting the
// gamut. In this case, `map` is always executed, even if the output gamut
// is larger than the input gamut.
bool bidirectional;
// Private data. Unused by libplacebo, but may be accessed by `map`.
void *priv;
};
struct pl_gamut_map_constants {
// (Relative) chromaticity protection zone for perceptual mapping [0,1]
float perceptual_deadzone;
// Strength of the perceptual saturation mapping component [0,1]
float perceptual_strength;
// I vs C curve gamma to use for colorimetric clipping [0,10]
float colorimetric_gamma;
// Knee point to use for softclipping methods (perceptual, softclip) [0,1]
float softclip_knee;
// Desaturation strength (for softclip only) [0,1]
float softclip_desat;
};
#define PL_GAMUT_MAP_CONSTANTS \
.colorimetric_gamma = 1.80f, \
.softclip_knee = 0.70f, \
.softclip_desat = 0.35f, \
.perceptual_deadzone = 0.30f, \
.perceptual_strength = 0.80f,
struct pl_gamut_map_params {
// If `function` is NULL, defaults to `pl_gamut_map_clip`.
const struct pl_gamut_map_function *function;
// The desired input/output primaries. This affects the subjective color
// volume in which the desired mapping shall take place.
struct pl_raw_primaries input_gamut;
struct pl_raw_primaries output_gamut;
// Minimum/maximum luminance (PQ) of the target display. Note that the same
// value applies to both the input and output, since it's assumed that tone
// mapping has already happened by this stage. This effectively defines the
// legal gamut boundary in RGB space.
//
// This also defines the I channel value range, for `pl_gamut_map_generate`
float min_luma;
float max_luma;
// Common constants, should be initialized to PL_GAMUT_MAP_CONSTANTS if
// not intending to override them further.
struct pl_gamut_map_constants constants;
// -- LUT generation options (for `pl_gamut_map_generate` only)
// The size of the resulting LUT, per channel.
//
// Note: For quality, it's generally best to increase h > I > C
int lut_size_I;
int lut_size_C;
int lut_size_h;
// The stride (in number of floats) between elements in the resulting LUT.
int lut_stride;
// -- Removed parameters
float chroma_margin PL_DEPRECATED; // non-functional
};
#define pl_gamut_map_params(...) (&(struct pl_gamut_map_params) { \
.constants = { PL_GAMUT_MAP_CONSTANTS }, \
__VA_ARGS__ \
})
// Note: Only does pointer equality testing on `function`
PL_API bool pl_gamut_map_params_equal(const struct pl_gamut_map_params *a,
const struct pl_gamut_map_params *b);
// Returns true if the given gamut mapping configuration effectively represents
// a no-op configuration. Gamut mapping can be skipped in this case.
PL_API bool pl_gamut_map_params_noop(const struct pl_gamut_map_params *params);
// Generate a gamut-mapping LUT for a given configuration. LUT samples are
// stored as IPTPQc4 values, but the LUT itself is indexed by IChPQc4,spanning
// the effective range [min_luma, max_luma] × [0, 0.5] × [-pi,pi].
//
// This ordering is designed to keep frequently co-occurring values close in
// memory, while permitting simple wrapping of the 'h' component.
PL_API void pl_gamut_map_generate(float *out, const struct pl_gamut_map_params *params);
// Samples a gamut mapping function for a single IPTPQc4 value. The input
// values are updated in-place.
PL_API void pl_gamut_map_sample(float x[3], const struct pl_gamut_map_params *params);
// Performs no gamut-mapping, just hard clips out-of-range colors per-channel.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_clip;
// Performs a perceptually balanced (saturation) gamut mapping, using a soft
// knee function to preserve in-gamut colors, followed by a final softclip
// operation. This works bidirectionally, meaning it can both compress and
// expand the gamut. Behaves similar to a blend of `saturation` and `softclip`.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_perceptual;
// Performs a perceptually balanced gamut mapping using a soft knee function to
// roll-off clipped regions, and a hue shifting function to preserve saturation.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_softclip;
// Performs relative colorimetric clipping, while maintaining an exponential
// relationship between brightness and chromaticity.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_relative;
// Performs simple RGB->RGB saturation mapping. The input R/G/B channels are
// mapped directly onto the output R/G/B channels. Will never clip, but will
// distort all hues and/or result in a faded look.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_saturation;
// Performs absolute colorimetric clipping. Like pl_gamut_map_relative, but
// does not adapt the white point.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_absolute;
// Performs constant-luminance colorimetric clipping, desaturing colors
// towards white until they're in-range.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_desaturate;
// Uniformly darkens the input slightly to prevent clipping on blown-out
// highlights, then clamps colorimetrically to the input gamut boundary,
// biased slightly to preserve chromaticity over luminance.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_darken;
// Performs no gamut mapping, but simply highlights out-of-gamut pixels.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_highlight;
// Linearly/uniformly desaturates the image in order to bring the entire
// image into the target gamut.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_linear;
// A list of built-in gamut mapping functions, terminated by NULL
PL_API extern const struct pl_gamut_map_function * const pl_gamut_map_functions[];
PL_API extern const int pl_num_gamut_map_functions; // excluding trailing NULL
// Find the gamut mapping function with the given name, or NULL on failure.
PL_API const struct pl_gamut_map_function *pl_find_gamut_map_function(const char *name);
PL_API_END
#endif // LIBPLACEBO_GAMUT_MAPPING_H_

View File

@ -0,0 +1,113 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_LOG_H_
#define LIBPLACEBO_LOG_H_
#include <libplacebo/config.h>
#include <libplacebo/common.h>
PL_API_BEGIN
// The log level associated with a given log message.
enum pl_log_level {
PL_LOG_NONE = 0,
PL_LOG_FATAL, // results in total loss of function of a major component
PL_LOG_ERR, // serious error; may result in degraded function
PL_LOG_WARN, // warning; potentially bad, probably user-relevant
PL_LOG_INFO, // informational message, also potentially harmless errors
PL_LOG_DEBUG, // verbose debug message, informational
PL_LOG_TRACE, // very noisy trace of activity,, usually benign
PL_LOG_ALL = PL_LOG_TRACE,
};
struct pl_log_params {
// Logging callback. All messages, informational or otherwise, will get
// redirected to this callback. The logged messages do not include trailing
// newlines. Optional.
void (*log_cb)(void *log_priv, enum pl_log_level level, const char *msg);
void *log_priv;
// The current log level. Controls the level of message that will be
// redirected to the log callback. Setting this to PL_LOG_ALL means all
// messages will be forwarded, but doing so indiscriminately can result
// in increased CPU usage as it may enable extra debug paths based on the
// configured log level.
enum pl_log_level log_level;
};
#define pl_log_params(...) (&(struct pl_log_params) { __VA_ARGS__ })
PL_API extern const struct pl_log_params pl_log_default_params;
// Thread-safety: Safe
//
// Note: In any context in which `pl_log` is used, users may also pass NULL
// to disable logging. In other words, NULL is a valid `pl_log`.
typedef const struct pl_log_t {
struct pl_log_params params;
} *pl_log;
#define pl_log_glue1(x, y) x##y
#define pl_log_glue2(x, y) pl_log_glue1(x, y)
// Force a link error in the case of linking against an incompatible API
// version.
#define pl_log_create pl_log_glue2(pl_log_create_, PL_API_VER)
// Creates a pl_log. `api_ver` is for historical reasons and ignored currently.
// `params` defaults to `&pl_log_default_params` if left as NULL.
//
// Note: As a general rule, any `params` struct used as an argument to a
// function need only live until the corresponding function returns.
PL_API pl_log pl_log_create(int api_ver, const struct pl_log_params *params);
// Destroy a `pl_log` object.
//
// Note: As a general rule, all `_destroy` functions take the pointer to the
// object to free as their parameter. This pointer is overwritten by NULL
// afterwards. Calling a _destroy function on &{NULL} is valid, but calling it
// on NULL itself is invalid.
PL_API void pl_log_destroy(pl_log *log);
// Update the parameters of a `pl_log` without destroying it. This can be
// used to change the log function, log context or log level retroactively.
// `params` defaults to `&pl_log_default_params` if left as NULL.
//
// Returns the previous params, atomically.
PL_API struct pl_log_params pl_log_update(pl_log log, const struct pl_log_params *params);
// Like `pl_log_update` but only updates the log level, leaving the log
// callback intact.
//
// Returns the previous log level, atomically.
PL_API enum pl_log_level pl_log_level_update(pl_log log, enum pl_log_level level);
// Two simple, stream-based loggers. You can use these as the log_cb. If you
// also set log_priv to a FILE* (e.g. stdout or stderr) it will be printed
// there; otherwise, it will be printed to stdout or stderr depending on the
// log level.
//
// The version with colors will use ANSI escape sequences to indicate the log
// level. The version without will use explicit prefixes.
PL_API void pl_log_simple(void *stream, enum pl_log_level level, const char *msg);
PL_API void pl_log_color(void *stream, enum pl_log_level level, const char *msg);
// Backwards compatibility with older versions of libplacebo
#define pl_context pl_log
#define pl_context_params pl_log_params
PL_API_END
#endif // LIBPLACEBO_LOG_H_

View File

@ -0,0 +1,230 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_OPENGL_H_
#define LIBPLACEBO_OPENGL_H_
#include <string.h>
#include <libplacebo/gpu.h>
#include <libplacebo/swapchain.h>
PL_API_BEGIN
// Note on thread safety: The thread safety of `pl_opengl` and any associated
// GPU objects follows the same thread safety rules as the underlying OpenGL
// context. In other words, they must only be called from the thread the OpenGL
// context is current on.
typedef const struct pl_opengl_t {
pl_gpu gpu;
// Detected GL version
int major, minor;
// List of GL/EGL extensions, provided for convenience
const char * const *extensions;
int num_extensions;
} *pl_opengl;
static inline bool pl_opengl_has_ext(pl_opengl gl, const char *ext)
{
for (int i = 0; i < gl->num_extensions; i++)
if (!strcmp(ext, gl->extensions[i]))
return true;
return false;
}
typedef void (*pl_voidfunc_t)(void);
struct pl_opengl_params {
// Main gl*GetProcAddr function. This will be used to load all GL/EGL
// functions. Optional - if unspecified, libplacebo will default to an
// internal loading logic which should work on most platforms.
pl_voidfunc_t (*get_proc_addr_ex)(void *proc_ctx, const char *procname);
void *proc_ctx;
// Simpler API for backwards compatibility / convenience. (This one
// directly matches the signature of most gl*GetProcAddr library functions)
pl_voidfunc_t (*get_proc_addr)(const char *procname);
// Enable OpenGL debug report callbacks. May have little effect depending
// on whether or not the GL context was initialized with appropriate
// debugging enabled.
bool debug;
// Allow the use of (suspected) software rasterizers and renderers. These
// can be useful for debugging purposes, but normally, their use is
// undesirable when GPU-accelerated processing is expected.
bool allow_software;
// Restrict the maximum allowed GLSL version. (Mainly for testing)
int max_glsl_version;
// Optional. Required when importing/exporting dmabufs as textures.
void *egl_display;
void *egl_context;
// Optional callbacks to bind/release the OpenGL context on the current
// thread. If these are specified, then the resulting `pl_gpu` will have
// `pl_gpu_limits.thread_safe` enabled, and may therefore be used from any
// thread without first needing to bind the OpenGL context.
//
// If the user is re-using the same OpenGL context in non-libplacebo code,
// then these callbacks should include whatever synchronization is
// necessary to prevent simultaneous use between libplacebo and the user.
bool (*make_current)(void *priv);
void (*release_current)(void *priv);
void *priv;
};
// Default/recommended parameters
#define pl_opengl_params(...) (&(struct pl_opengl_params) { __VA_ARGS__ })
PL_API extern const struct pl_opengl_params pl_opengl_default_params;
// Creates a new OpenGL renderer based on the given parameters. This will
// internally use whatever platform-defined mechanism (WGL, X11, EGL) is
// appropriate for loading the OpenGL function calls, so the user doesn't need
// to pass in a `getProcAddress` callback. If `params` is left as NULL, it
// defaults to `&pl_opengl_default_params`. The context must be active when
// calling this function, and must remain active whenever calling any
// libplacebo function on the resulting `pl_opengl` or `pl_gpu`.
//
// Note that creating multiple `pl_opengl` instances from the same OpenGL
// context is undefined behavior.
PL_API pl_opengl pl_opengl_create(pl_log log, const struct pl_opengl_params *params);
// All resources allocated from the `pl_gpu` contained by this `pl_opengl` must
// be explicitly destroyed by the user before calling `pl_opengl_destroy`.
PL_API void pl_opengl_destroy(pl_opengl *gl);
// For a `pl_gpu` backed by `pl_opengl`, this function can be used to retrieve
// the underlying `pl_opengl`. Returns NULL for any other type of `gpu`.
PL_API pl_opengl pl_opengl_get(pl_gpu gpu);
struct pl_opengl_framebuffer {
// ID of the framebuffer, or 0 to use the context's default framebuffer.
int id;
// If true, then the framebuffer is assumed to be "flipped" relative to
// normal GL semantics, i.e. set this to `true` if the first pixel is the
// top left corner.
bool flipped;
};
struct pl_opengl_swapchain_params {
// Set this to the platform-specific function to swap buffers, e.g.
// glXSwapBuffers, eglSwapBuffers etc. This will be called internally by
// `pl_swapchain_swap_buffers`. Required, unless you never call that
// function.
void (*swap_buffers)(void *priv);
// Initial framebuffer description. This can be changed later on using
// `pl_opengl_swapchain_update_fb`.
struct pl_opengl_framebuffer framebuffer;
// Attempt forcing a specific latency. If this is nonzero, then
// `pl_swapchain_swap_buffers` will wait until fewer than N frames are "in
// flight" before returning. Setting this to a high number generally
// accomplished nothing, because the OpenGL driver typically limits the
// number of buffers on its own. But setting it to a low number like 2 or
// even 1 can reduce latency (at the cost of throughput).
int max_swapchain_depth;
// Arbitrary user pointer that gets passed to `swap_buffers` etc.
void *priv;
};
#define pl_opengl_swapchain_params(...) (&(struct pl_opengl_swapchain_params) { __VA_ARGS__ })
// Creates an instance of `pl_swapchain` tied to the active context.
// Note: Due to OpenGL semantics, users *must* call `pl_swapchain_resize`
// before attempting to use this swapchain, otherwise calls to
// `pl_swapchain_start_frame` will fail.
PL_API pl_swapchain pl_opengl_create_swapchain(pl_opengl gl,
const struct pl_opengl_swapchain_params *params);
// Update the framebuffer description. After calling this function, users
// *must* call `pl_swapchain_resize` before attempting to use the swapchain
// again, otherwise calls to `pl_swapchain_start_frame` will fail.
PL_API void pl_opengl_swapchain_update_fb(pl_swapchain sw,
const struct pl_opengl_framebuffer *fb);
struct pl_opengl_wrap_params {
// The GLuint texture object itself. Optional. If no texture is provided,
// then only the opaque framebuffer `fbo` will be wrapped, leaving the
// resulting `pl_tex` object with some operations (such as sampling) being
// unsupported.
unsigned int texture;
// The GLuint associated framebuffer. Optional. If this is not specified,
// then libplacebo will attempt creating a framebuffer from the provided
// texture object (if possible).
//
// Note: As a special case, if neither a texture nor an FBO are provided,
// this is equivalent to wrapping the OpenGL default framebuffer (id 0).
unsigned int framebuffer;
// The image's dimensions (unused dimensions must be 0)
int width;
int height;
int depth;
// Texture-specific fields:
//
// Note: These are only relevant if `texture` is provided.
// The GLenum for the texture target to use, e.g. GL_TEXTURE_2D. Optional.
// If this is left as 0, the target is inferred from the number of
// dimensions. Users may want to set this to something specific like
// GL_TEXTURE_EXTERNAL_OES depending on the nature of the texture.
unsigned int target;
// The texture's GLint sized internal format (e.g. GL_RGBA16F). Required.
int iformat;
};
#define pl_opengl_wrap_params(...) (&(struct pl_opengl_wrap_params) { __VA_ARGS__ })
// Wraps an external OpenGL object into a `pl_tex` abstraction. Due to the
// internally synchronized nature of OpenGL, no explicit synchronization
// is needed between libplacebo `pl_tex_` operations, and host accesses to
// the texture. Wrapping the same OpenGL texture multiple times is permitted.
// Note that this function transfers no ownership.
//
// This wrapper can be destroyed by simply calling `pl_tex_destroy` on it,
// which will *not* destroy the user-provided OpenGL texture or framebuffer.
//
// This function may fail, in which case it returns NULL.
PL_API pl_tex pl_opengl_wrap(pl_gpu gpu, const struct pl_opengl_wrap_params *params);
// Analogous to `pl_opengl_wrap`, this function takes any `pl_tex` (including
// ones created by `pl_tex_create`) and unwraps it to expose the underlying
// OpenGL texture to the user. Note that this function transfers no ownership,
// i.e. the texture object and framebuffer shall not be destroyed by the user.
//
// Returns the OpenGL texture. `out_target` and `out_iformat` will be updated
// to hold the target type and internal format, respectively. (Optional)
//
// For renderable/blittable textures, `out_fbo` will be updated to the ID of
// the framebuffer attached to this texture, or 0 if there is none. (Optional)
PL_API unsigned int pl_opengl_unwrap(pl_gpu gpu, pl_tex tex, unsigned int *out_target,
int *out_iformat, unsigned int *out_fbo);
PL_API_END
#endif // LIBPLACEBO_OPENGL_H_

View File

@ -0,0 +1,201 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_OPTIONS_H_
#define LIBPLACEBO_OPTIONS_H_
#include <libplacebo/renderer.h>
PL_API_BEGIN
// High-level heap-managed struct containing storage for all options implied by
// pl_render_params, including a high-level interface for serializing,
// deserializing and interfacing with them in a programmatic way.
typedef const struct pl_opt_t *pl_opt;
typedef struct pl_options_t {
// Non-NULL `params.*_params` pointers must always point into this struct
struct pl_render_params params;
// Backing storage for all of the various rendering parameters. Whether
// or not these params are active is determined by whether or not
// `params.*_params` is set to this address or NULL.
struct pl_deband_params deband_params;
struct pl_sigmoid_params sigmoid_params;
struct pl_color_adjustment color_adjustment;
struct pl_peak_detect_params peak_detect_params;
struct pl_color_map_params color_map_params;
struct pl_dither_params dither_params;
struct pl_icc_params icc_params PL_DEPRECATED;
struct pl_cone_params cone_params;
struct pl_blend_params blend_params;
struct pl_deinterlace_params deinterlace_params;
struct pl_distort_params distort_params;
// Backing storage for "custom" scalers. `params.upscaler` etc. will
// always be a pointer either to a built-in pl_filter_config, or one of
// these structs. `name`, `description` and `allowed` will always be
// valid for the respective type of filter config.
struct pl_filter_config upscaler;
struct pl_filter_config downscaler;
struct pl_filter_config plane_upscaler;
struct pl_filter_config plane_downscaler;
struct pl_filter_config frame_mixer;
} *pl_options;
// Allocate a new set of render params, with internally backed storage for
// all parameters. Initialized to an "empty" config (PL_RENDER_DEFAULTS),
// equivalent to `&pl_render_fast_params`. To initialize the struct instead to
// the recommended default parameters, use `pl_options_reset` with
// `pl_render_default_params`.
//
// If `log` is provided, errors related to parsing etc. will be logged there.
PL_API pl_options pl_options_alloc(pl_log log);
PL_API void pl_options_free(pl_options *opts);
// Resets all options to their default values from a given struct. If `preset`
// is NULL, `opts` is instead reset back to the initial "empty" configuration,
// with all options disabled, as if it was freshly allocated.
//
// Note: This function will also reset structs which were not included in
// `preset`, such as any custom upscalers.
PL_API void pl_options_reset(pl_options opts, const struct pl_render_params *preset);
typedef const struct pl_opt_data_t {
// Original options struct.
pl_options opts;
// Triggering option for this callback invocation.
pl_opt opt;
// The raw data associated with this option. Always some pointer into
// `opts`. Note that only PL_OPT_BOOL, PL_OPT_INT and PL_OPT_FLOAT have
// a fixed representation, for other fields its usefulness is dubious.
const void *value;
// The underlying data, as a formatted, locale-invariant string. Lifetime
// is limited until the return of this callback.
const char *text;
} *pl_opt_data;
// Query a single option from `opts` by key, or NULL if none was found.
// The resulting pointer is only valid until the next pl_options_* call.
PL_API pl_opt_data pl_options_get(pl_options opts, const char *key);
// Update an option from a formatted value string (see `pl_opt_data.text`).
// This can be used for all type of options, even non-string ones. In this case,
// `value` will be parsed according to the option type.
//
// Returns whether successful.
PL_API bool pl_options_set_str(pl_options opts, const char *key, const char *value);
// Programmatically iterate over options set in a `pl_options`, running the
// provided callback on each entry.
PL_API void pl_options_iterate(pl_options opts,
void (*cb)(void *priv, pl_opt_data data),
void *priv);
// Serialize a `pl_options` structs to a comma-separated key/value string. The
// returned string has a lifetime valid until either the next call to
// `pl_options_save`, or until the `pl_options` is freed.
PL_API const char *pl_options_save(pl_options opts);
// Parse a `pl_options` struct from a key/value string, in standard syntax
// "key1=value1,key2=value2,...", and updates `opts` with the new values.
// Valid separators include whitespace, commas (,) and (semi)colons (:;).
//
// Returns true if no errors occurred.
PL_API bool pl_options_load(pl_options opts, const char *str);
// Helpers for interfacing with `opts->params.hooks`. Note that using any of
// these helpers will overwrite the array by an internally managed pointer,
// so care must be taken when combining them with external management of
// this memory. Negative indices are possible and are counted relative to the
// end of the list.
//
// Note: These hooks are *not* included in pl_options_save() and related.
PL_API void pl_options_add_hook(pl_options opts, const struct pl_hook *hook);
PL_API void pl_options_insert_hook(pl_options opts, const struct pl_hook *hook, int idx);
PL_API void pl_options_remove_hook_at(pl_options opts, int idx);
// Underlying options system and list
//
// Note: By necessity, this option list does not cover every single field
// present in `pl_render_params`. In particular, fields like `info_callback`,
// `lut` and `hooks` cannot be configured through the options system, as doing
// so would require interop with C code or I/O. (However, see
// `pl_options_add_hook` and related)
enum pl_option_type {
// Accepts `yes/no`, `on/off`, `true/false` and variants
PL_OPT_BOOL,
// Parsed as human-readable locale-invariant (C) numbers, scientific
// notation accepted for floats
PL_OPT_INT,
PL_OPT_FLOAT,
// Parsed as a short string containing only alphanumerics and _-,
// corresponding to some name/identifier. Catch-all bucket for several
// other types of options, such as presets, struct pointers, and functions
//
// Note: These options do not correspond to actual strings in C, the
// underlying type of option will determine the values of `size` and
// corresponding interpretation of pointers.
PL_OPT_STRING,
PL_OPT_TYPE_COUNT,
};
struct pl_opt_t {
// Programmatic key uniquely identifying this option.
const char *key;
// Longer, human readable friendly name
const char *name;
// Data type of option, affects how it is parsed. This field is purely
// informative for the user, the actual implementation may vary.
enum pl_option_type type;
// Minimum/maximum value ranges for numeric options (int / float)
// If both are 0.0, these limits are disabled/ignored.
float min, max;
// If true, this option is considered deprecated and may be removed
// in the future.
bool deprecated;
// If true, this option is considered a 'preset' (read-only), which can
// be loaded but not saved. (The equivalent underlying options this preset
// corresponds to will be saved instead)
bool preset;
// Internal implementation details (for parsing/saving), opaque to user
const void *priv;
};
// A list of options, terminated by {0} for convenience
PL_API extern const struct pl_opt_t pl_option_list[];
PL_API extern const int pl_option_count; // excluding terminating {0}
// Returns the `pl_option` associated with a given key, or NULL
PL_API pl_opt pl_find_option(const char *key);
PL_API_END
#endif // LIBPLACEBO_OPTIONS_H_

View File

@ -0,0 +1,847 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_RENDERER_H_
#define LIBPLACEBO_RENDERER_H_
#include <libplacebo/config.h>
#include <libplacebo/colorspace.h>
#include <libplacebo/filters.h>
#include <libplacebo/gpu.h>
#include <libplacebo/shaders/colorspace.h>
#include <libplacebo/shaders/deinterlacing.h>
#include <libplacebo/shaders/dithering.h>
#include <libplacebo/shaders/film_grain.h>
#include <libplacebo/shaders/icc.h>
#include <libplacebo/shaders/lut.h>
#include <libplacebo/shaders/sampling.h>
#include <libplacebo/shaders/custom.h>
#include <libplacebo/swapchain.h>
PL_API_BEGIN
// Thread-safety: Unsafe
typedef struct pl_renderer_t *pl_renderer;
// Enum values used in pl_renderer_errors_t as a bit positions for error flags
enum pl_render_error {
PL_RENDER_ERR_NONE = 0,
PL_RENDER_ERR_FBO = 1 << 0,
PL_RENDER_ERR_SAMPLING = 1 << 1,
PL_RENDER_ERR_DEBANDING = 1 << 2,
PL_RENDER_ERR_BLENDING = 1 << 3,
PL_RENDER_ERR_OVERLAY = 1 << 4,
PL_RENDER_ERR_PEAK_DETECT = 1 << 5,
PL_RENDER_ERR_FILM_GRAIN = 1 << 6,
PL_RENDER_ERR_FRAME_MIXING = 1 << 7,
PL_RENDER_ERR_DEINTERLACING = 1 << 8,
PL_RENDER_ERR_ERROR_DIFFUSION = 1 << 9,
PL_RENDER_ERR_HOOKS = 1 << 10,
PL_RENDER_ERR_CONTRAST_RECOVERY = 1 << 11,
};
// Struct describing current renderer state, including internal processing errors,
// as well as list of signatures of disabled hooks.
struct pl_render_errors {
enum pl_render_error errors;
// List containing signatures of disabled hooks
const uint64_t *disabled_hooks;
int num_disabled_hooks;
};
// Creates a new renderer object, which is backed by a GPU context. This is a
// high-level object that takes care of the rendering chain as a whole, from
// the source textures to the finished frame.
PL_API pl_renderer pl_renderer_create(pl_log log, pl_gpu gpu);
PL_API void pl_renderer_destroy(pl_renderer *rr);
// Returns current renderer state, see pl_render_errors.
PL_API struct pl_render_errors pl_renderer_get_errors(pl_renderer rr);
// Clears errors state of renderer. If `errors` is NULL, all render errors will
// be cleared. Otherwise only selected errors/hooks will be cleared.
// If `PL_RENDER_ERR_HOOKS` is set and `num_disabled_hooks` is 0, clear all hooks.
// Otherwise only selected hooks will be cleard based on `disabled_hooks` array.
PL_API void pl_renderer_reset_errors(pl_renderer rr,
const struct pl_render_errors *errors);
enum pl_lut_type {
PL_LUT_UNKNOWN = 0,
PL_LUT_NATIVE, // applied to raw image contents (after fixing bit depth)
PL_LUT_NORMALIZED, // applied to normalized (HDR) RGB values
PL_LUT_CONVERSION, // LUT fully replaces color conversion
// Note: When using a PL_LUT_CONVERSION to replace the YUV->RGB conversion,
// `pl_render_params.color_adjustment` is no longer applied. Similarly,
// when using a PL_LUT_CONVERSION to replace the image->target color space
// conversion, `pl_render_params.color_map_params` are ignored.
//
// Note: For LUTs attached to the output frame, PL_LUT_CONVERSION should
// instead perform the inverse (RGB->native) conversion.
//
// Note: PL_LUT_UNKNOWN tries inferring the meaning of the LUT from the
// LUT's tagged metadata, and otherwise falls back to PL_LUT_NATIVE.
};
enum pl_render_stage {
PL_RENDER_STAGE_FRAME, // full frame redraws, for fresh/uncached frames
PL_RENDER_STAGE_BLEND, // the output blend pass (only for pl_render_image_mix)
PL_RENDER_STAGE_COUNT,
};
struct pl_render_info {
const struct pl_dispatch_info *pass; // information about the shader
enum pl_render_stage stage; // the associated render stage
// This specifies the chronological index of this pass within the frame and
// stage (starting at `index == 0`).
int index;
// For PL_RENDER_STAGE_BLEND, this specifies the number of frames
// being blended (since that results in a different shader).
int count;
};
// Represents the options used for rendering. These affect the quality of
// the result.
struct pl_render_params {
// Configures the algorithms used for upscaling and downscaling,
// respectively. If left as NULL, then libplacebo will only use inexpensive
// sampling (bilinear or nearest neighbour depending on the capabilities
// of the hardware / texture).
//
// Note: Setting `downscaler` to NULL also implies `skip_anti_aliasing`,
// since the built-in GPU sampling algorithms can't anti-alias.
//
// Note: If set to the same address as the built-in `pl_filter_bicubic`,
// `pl_filter_nearest` etc.; libplacebo will also use the more efficient
// direct sampling algorithm where possible without quality loss.
const struct pl_filter_config *upscaler;
const struct pl_filter_config *downscaler;
// If set, this overrides the value of `upscaler`/`downscaling` for
// subsampled (chroma) planes. These scalers are used whenever the size of
// multiple different `pl_plane`s in a single `pl_frame` differ, requiring
// adaptation when converting to/from RGB. Note that a value of NULL simply
// means "no override". To force built-in scaling explicitly, set this to
// `&pl_filter_bilinear`.
const struct pl_filter_config *plane_upscaler;
const struct pl_filter_config *plane_downscaler;
// The anti-ringing strength to apply to filters. See the equivalent option
// in `pl_sample_filter_params` for more information.
float antiringing_strength;
// Configures the algorithm used for frame mixing (when using
// `pl_render_image_mix`). Ignored otherwise. As a special requirement,
// this must be a filter config with `polar` set to false, since it's only
// used for 1D mixing and thus only 1D filters are compatible.
//
// If set to NULL, frame mixing is disabled, in which case
// `pl_render_image_mix` will use nearest-neighbour semantics. (Note that
// this still goes through the redraw cache, unless you also enable
// `skip_caching_single_frame`)
const struct pl_filter_config *frame_mixer;
// Configures the settings used to deband source textures. Leaving this as
// NULL disables debanding.
//
// Note: The `deband_params.grain` setting is automatically adjusted to
// prevent blowing up on HDR sources. The user need not account for this.
const struct pl_deband_params *deband_params;
// Configures the settings used to sigmoidize the image before upscaling.
// This is not always used. If NULL, disables sigmoidization.
const struct pl_sigmoid_params *sigmoid_params;
// Configures the color adjustment parameters used to decode the color.
// This can be used to apply additional artistic settings such as
// desaturation, etc. If NULL, defaults to &pl_color_adjustment_neutral.
const struct pl_color_adjustment *color_adjustment;
// Configures the settings used to detect the peak of the source content,
// for HDR sources. Has no effect on SDR content. If NULL, peak detection
// is disabled.
const struct pl_peak_detect_params *peak_detect_params;
// Configures the settings used to tone map from HDR to SDR, or from higher
// gamut to standard gamut content. If NULL, defaults to
// `&pl_color_map_default_params`.
const struct pl_color_map_params *color_map_params;
// Configures the settings used to dither to the output depth. Leaving this
// as NULL disables dithering.
const struct pl_dither_params *dither_params;
// Configures the error diffusion kernel to use for error diffusion
// dithering. If set, this will be used instead of `dither_params` whenever
// possible. Leaving this as NULL disables error diffusion.
const struct pl_error_diffusion_kernel *error_diffusion;
// Configures the settings used to simulate color blindness, if desired.
// If NULL, this feature is disabled.
const struct pl_cone_params *cone_params;
// Configures output blending. When rendering to the final target, the
// framebuffer contents will be blended using this blend mode. Requires
// that the target format has PL_FMT_CAP_BLENDABLE. NULL disables blending.
const struct pl_blend_params *blend_params;
// Configures the settings used to deinterlace frames (see
// `pl_frame.field`), if required.. If NULL, deinterlacing is "disabled",
// meaning interlaced frames are rendered as weaved frames instead.
//
// Note: As a consequence of how `pl_frame` represents individual fields,
// and especially when using the `pl_queue`, this will still result in
// frames being redundantly rendered twice. As such, it's highly
// recommended to, instead, fully disable deinterlacing by not marking
// source frames as interlaced in the first place.
const struct pl_deinterlace_params *deinterlace_params;
// If set, applies an extra distortion matrix to the image, after
// scaling and before presenting it to the screen. Can be used for e.g.
// fractional rotation.
//
// Note: The distortion canvas will be set to the size of `target->crop`,
// so this cannot effectively draw outside the specified target area,
// nor change the aspect ratio of the image.
const struct pl_distort_params *distort_params;
// List of custom user shaders / hooks.
// See <libplacebo/shaders/custom.h> for more information.
const struct pl_hook * const *hooks;
int num_hooks;
// Color mapping LUT. If present, this will be applied as part of the
// image being rendered, in normalized RGB space.
//
// Note: In this context, PL_LUT_NATIVE means "gamma light" and
// PL_LUT_NORMALIZED means "linear light". For HDR signals, normalized LUTs
// are scaled so 1.0 corresponds to the `pl_color_transfer_nominal_peak`.
//
// Note: A PL_LUT_CONVERSION fully replaces the color adaptation from
// `image` to `target`, including any tone-mapping (if necessary) and ICC
// profiles. It has the same representation as PL_LUT_NATIVE, so in this
// case the input and output are (respectively) non-linear light RGB.
const struct pl_custom_lut *lut;
enum pl_lut_type lut_type;
// If the image being rendered does not span the entire size of the target,
// it will be cleared explicitly using this background color (RGB). To
// disable this logic, set `skip_target_clearing`.
float background_color[3];
float background_transparency; // 0.0 for opaque, 1.0 for fully transparent
bool skip_target_clearing;
// If set to a value above 0.0, the output will be rendered with rounded
// corners, as if an alpha transparency mask had been applied. The value
// indicates the relative fraction of the side length to round - a value
// of 1.0 rounds the corners as much as possible.
float corner_rounding;
// If true, then transparent images will made opaque by painting them
// against a checkerboard pattern consisting of alternating colors. If both
// colors are left as {0}, they default respectively to 93% and 87% gray.
bool blend_against_tiles;
float tile_colors[2][3];
int tile_size;
// --- Performance / quality trade-off options:
// These should generally be left off where quality is desired, as they can
// degrade the result quite noticeably; but may be useful for older or
// slower hardware. Note that libplacebo will automatically disable
// advanced features on hardware where they are unsupported, regardless of
// these settings. So only enable them if you need a performance bump.
// Disables anti-aliasing on downscaling. This will result in moiré
// artifacts and nasty, jagged pixels when downscaling, except for some
// very limited special cases (e.g. bilinear downsampling to exactly 0.5x).
//
// Significantly speeds up downscaling with high downscaling ratios.
bool skip_anti_aliasing;
// Normally, when the size of the `target` used with `pl_render_image_mix`
// changes, or the render parameters are updated, the internal cache of
// mixed frames must be discarded in order to re-render all required
// frames. Setting this option to `true` will skip the cache invalidation
// and instead re-use the existing frames (with bilinear scaling to the new
// size if necessary), which comes at a quality loss shortly after a
// resize, but should make it much more smooth.
bool preserve_mixing_cache;
// --- Performance tuning / debugging options
// These may affect performance or may make debugging problems easier,
// but shouldn't have any effect on the quality.
// Normally, `pl_render_image_mix` will also push single frames through the
// mixer cache, in order to speed up re-draws. Enabling this option
// disables that logic, causing single frames to bypass the cache. (Though
// it will still read from, if they happen to already be cached)
bool skip_caching_single_frame;
// Disables linearization / sigmoidization before scaling. This might be
// useful when tracking down unexpected image artifacts or excessing
// ringing, but it shouldn't normally be necessary.
bool disable_linear_scaling;
// Forces the use of the "general" scaling algorithms even when using the
// special-cased built-in presets like `pl_filter_bicubic`. Basically, this
// disables the more efficient implementations in favor of the slower,
// general-purpose ones.
bool disable_builtin_scalers;
// Forces correction of subpixel offsets (using the configured `upscaler`).
bool correct_subpixel_offsets;
// Forces the use of dithering, even when rendering to 16-bit FBOs. This is
// generally pretty pointless because most 16-bit FBOs have high enough
// depth that rounding errors are below the human perception threshold,
// but this can be used to test the dither code.
bool force_dither;
// Disables the gamma-correct dithering logic which normally applies when
// dithering to low bit depths. No real use, outside of testing.
bool disable_dither_gamma_correction;
// Completely overrides the use of FBOs, as if there were no renderable
// texture format available. This disables most features.
bool disable_fbos;
// Use only low-bit-depth FBOs (8 bits). Note that this also implies
// disabling linear scaling and sigmoidization.
bool force_low_bit_depth_fbos;
// If this is true, all shaders will be generated as "dynamic" shaders,
// with any compile-time constants being replaced by runtime-adjustable
// values. This is generally a performance loss, but has the advantage of
// being able to freely change parameters without triggering shader
// recompilations.
//
// It's a good idea to enable while presenting configurable settings to the
// user, but it should be set to false once those values are "dialed in".
bool dynamic_constants;
// This callback is invoked for every pass successfully executed in the
// process of rendering a frame. Optional.
//
// Note: `info` is only valid until this function returns.
void (*info_callback)(void *priv, const struct pl_render_info *info);
void *info_priv;
// --- Deprecated/removed fields
bool allow_delayed_peak_detect PL_DEPRECATED; // moved to pl_peak_detect_params
const struct pl_icc_params *icc_params PL_DEPRECATED; // use pl_frame.icc
bool ignore_icc_profiles PL_DEPRECATED; // non-functional, just set pl_frame.icc to NULL
int lut_entries PL_DEPRECATED; // hard-coded as 256
float polar_cutoff PL_DEPRECATED; // hard-coded as 1e-3
};
// Bare minimum parameters, with no features enabled. This is the fastest
// possible configuration, and should therefore be fine on any system.
#define PL_RENDER_DEFAULTS \
.color_map_params = &pl_color_map_default_params, \
.color_adjustment = &pl_color_adjustment_neutral, \
.tile_colors = {{0.93, 0.93, 0.93}, \
{0.87, 0.87, 0.87}}, \
.tile_size = 32,
#define pl_render_params(...) (&(struct pl_render_params) { PL_RENDER_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_render_params pl_render_fast_params;
// This contains the default/recommended options for reasonable image quality,
// while also not being too terribly slow. All of the *_params structs are
// defaulted to the corresponding *_default_params, except for deband_params,
// which is disabled by default.
//
// This should be fine on most integrated GPUs, but if it's too slow,
// consider using `pl_render_fast_params` instead.
PL_API extern const struct pl_render_params pl_render_default_params;
// This contains a higher quality preset for better image quality at the cost
// of quite a bit of performance. In addition to the settings implied by
// `pl_render_default_params`, it enables debanding, sets the upscaler to
// `pl_filter_ewa_lanczossharp`, and uses pl_*_high_quality_params structs where
// available. This should only really be used with a discrete GPU and where
// maximum image quality is desired.
PL_API extern const struct pl_render_params pl_render_high_quality_params;
#define PL_MAX_PLANES 4
// High level description of a single slice of an image. This basically
// represents a single 2D plane, with any number of components
struct pl_plane {
// The texture underlying this plane. The texture must be 2D, and must
// have specific parameters set depending on what the plane is being used
// for (see `pl_render_image`).
pl_tex texture;
// The preferred behaviour when sampling outside of this texture. Optional,
// since the default (PL_TEX_ADDRESS_CLAMP) is very reasonable.
enum pl_tex_address_mode address_mode;
// Controls whether or not the `texture` will be considered flipped
// vertically with respect to the overall image dimensions. It's generally
// preferable to flip planes using this setting instead of the crop in
// cases where the flipping is the result of e.g. negative plane strides or
// flipped framebuffers (OpenGL).
//
// Note that any planar padding (due to e.g. size mismatch or misalignment
// of subsampled planes) is always at the physical end of the texture
// (highest y coordinate) - even if this bool is true. However, any
// subsampling shift (`shift_y`) is applied with respect to the flipped
// direction. This ensures the correct interpretation when e.g. vertically
// flipping 4:2:0 sources by flipping all planes.
bool flipped;
// Describes the number and interpretation of the components in this plane.
// This defines the mapping from component index to the canonical component
// order (RGBA, YCbCrA or XYZA). It's worth pointing out that this is
// completely separate from `texture->format.sample_order`. The latter is
// essentially irrelevant/transparent for the API user, since it just
// determines which order the texture data shows up as inside the GLSL
// shader; whereas this field controls the actual meaning of the component.
//
// Example; if the user has a plane with just {Y} and a plane with just
// {Cb Cr}, and a GPU that only supports bgra formats, you would still
// specify the component mapping as {0} and {1 2} respectively, even though
// the GPU is sampling the data in the order BGRA. Use -1 for "ignored"
// components.
int components; // number of relevant components
int component_mapping[4]; // semantic index of each component
// Controls the sample offset, relative to the "reference" dimensions. For
// an example of what to set here, see `pl_chroma_location_offset`. Note
// that this is given in unit of reference pixels. For a graphical example,
// imagine you have a 2x2 image with a 1x1 (subsampled) plane. Without any
// shift (0.0), the situation looks like this:
//
// X-------X X = reference pixel
// | | P = plane pixel
// | P |
// | |
// X-------X
//
// For 4:2:0 subsampling, this corresponds to PL_CHROMA_CENTER. If the
// shift_x was instead set to -0.5, the `P` pixel would be offset to the
// left by half the separation between the reference (`X` pixels), resulting
// in the following:
//
// X-------X X = reference pixel
// | | P = plane pixel
// P |
// | |
// X-------X
//
// For 4:2:0 subsampling, this corresponds to PL_CHROMA_LEFT.
//
// Note: It's recommended to fill this using `pl_chroma_location_offset` on
// the chroma planes.
float shift_x, shift_y;
};
enum pl_overlay_mode {
PL_OVERLAY_NORMAL = 0, // treat the texture as a normal, full-color texture
PL_OVERLAY_MONOCHROME, // treat the texture as a single-component alpha map
PL_OVERLAY_MODE_COUNT,
};
enum pl_overlay_coords {
PL_OVERLAY_COORDS_AUTO = 0, // equal to SRC/DST_FRAME, respectively
PL_OVERLAY_COORDS_SRC_FRAME, // relative to the raw src frame
PL_OVERLAY_COORDS_SRC_CROP, // relative to the src frame crop
PL_OVERLAY_COORDS_DST_FRAME, // relative to the raw dst frame
PL_OVERLAY_COORDS_DST_CROP, // relative to the dst frame crop
PL_OVERLAY_COORDS_COUNT,
// Note on rotations: If there is an end-to-end rotation between `src` and
// `dst`, then any overlays relative to SRC_FRAME or SRC_CROP will be
// rotated alongside the image, while overlays relative to DST_FRAME or
// DST_CROP will not.
};
struct pl_overlay_part {
pl_rect2df src; // source coordinate with respect to `pl_overlay.tex`
pl_rect2df dst; // target coordinates with respect to `pl_overlay.coords`
// If `mode` is PL_OVERLAY_MONOCHROME, then this specifies the color of
// this overlay part. The color is multiplied into the sampled texture's
// first channel.
float color[4];
};
// A struct representing an image overlay (e.g. for subtitles or on-screen
// status messages, controls, ...)
struct pl_overlay {
// The texture containing the backing data for overlay parts. Must have
// `params.sampleable` set.
pl_tex tex;
// This controls the coloring mode of this overlay.
enum pl_overlay_mode mode;
// Controls which coordinates this overlay is addressed relative to.
enum pl_overlay_coords coords;
// This controls the colorspace information for this overlay. The contents
// of the texture / the value of `color` are interpreted according to this.
struct pl_color_repr repr;
struct pl_color_space color;
// The number of parts for this overlay.
const struct pl_overlay_part *parts;
int num_parts;
};
// High-level description of a complete frame, including metadata and planes
struct pl_frame {
// Each frame is split up into some number of planes, each of which may
// carry several components and be of any size / offset.
int num_planes;
struct pl_plane planes[PL_MAX_PLANES];
// For interlaced frames. If set, this `pl_frame` corresponds to a single
// field of the underlying source textures. `first_field` indicates which
// of these fields is ordered first in time. `prev` and `next` should point
// to the previous/next frames in the file, or NULL if there are none.
//
// Note: Setting these fields on the render target has no meaning and will
// be ignored.
enum pl_field field;
enum pl_field first_field;
const struct pl_frame *prev, *next;
// If set, will be called immediately before GPU access to this frame. This
// function *may* be used to, for example, perform synchronization with
// external APIs (e.g. `pl_vulkan_hold/release`). If your mapping requires
// a memcpy of some sort (e.g. pl_tex_transfer), users *should* instead do
// the memcpy up-front and avoid the use of these callbacks - because they
// might be called multiple times on the same frame.
//
// This function *may* arbitrarily mutate the `pl_frame`, but it *should*
// ideally only update `planes` - in particular, color metadata and so
// forth should be provided up-front as best as possible. Note that changes
// here will not be reflected back to the structs provided in the original
// `pl_render_*` call (e.g. via `pl_frame_mix`).
//
// Note: Unless dealing with interlaced frames, only one frame will ever be
// acquired at a time per `pl_render_*` call. So users *can* safely use
// this with, for example, hwdec mappers that can only map a single frame
// at a time. When using this with, for example, `pl_render_image_mix`,
// each frame to be blended is acquired and release in succession, before
// moving on to the next frame. For interlaced frames, the previous and
// next frames must also be acquired simultaneously.
bool (*acquire)(pl_gpu gpu, struct pl_frame *frame);
// If set, will be called after a plane is done being used by the GPU,
// *including* after any errors (e.g. `acquire` returning false).
void (*release)(pl_gpu gpu, struct pl_frame *frame);
// Color representation / encoding / semantics of this frame.
struct pl_color_repr repr;
struct pl_color_space color;
// Optional ICC profile associated with this frame.
pl_icc_object icc;
// Alternative to `icc`, this can be used in cases where allocating and
// tracking an pl_icc_object externally may be inconvenient. The resulting
// profile will be managed internally by the pl_renderer.
struct pl_icc_profile profile;
// Optional LUT associated with this frame.
const struct pl_custom_lut *lut;
enum pl_lut_type lut_type;
// The logical crop / rectangle containing the valid information, relative
// to the reference plane's dimensions (e.g. luma). Pixels outside of this
// rectangle will ostensibly be ignored, but note that this is not a hard
// guarantee. In particular, scaler filters may end up sampling outside of
// this crop. This rect may be flipped, and may be partially or wholly
// outside the bounds of the underlying textures. (Optional)
//
// Note that `pl_render_image` will map the input crop directly to the
// output crop, stretching and scaling as needed. If you wish to preserve
// the aspect ratio, use a dedicated function like pl_rect2df_aspect_copy.
pl_rect2df crop;
// Logical rotation of the image, with respect to the underlying planes.
// For example, if this is PL_ROTATION_90, then the image will be rotated
// to the right by 90° when mapping to `crop`. The actual position on-screen
// is unaffected, so users should ensure that the (rotated) aspect ratio
// matches the source. (Or use a helper like `pl_rect2df_aspect_set_rot`)
//
// Note: For `target` frames, this corresponds to a rotation of the
// display, for `image` frames, this corresponds to a rotation of the
// camera.
//
// So, as an example, target->rotation = PL_ROTATE_90 means the end user
// has rotated the display to the right by 90° (meaning rendering will be
// rotated 90° to the *left* to compensate), and image->rotation =
// PL_ROTATE_90 means the video provider has rotated the camera to the
// right by 90° (so rendering will be rotated 90° to the *right* to
// compensate).
pl_rotation rotation;
// A list of additional overlays associated with this frame. Note that will
// be rendered directly onto intermediate/cache frames, so changing any of
// these overlays may require flushing the renderer cache.
const struct pl_overlay *overlays;
int num_overlays;
// Note on subsampling and plane correspondence: All planes belonging to
// the same frame will only be stretched by an integer multiple (or inverse
// thereof) in order to match the reference dimensions of this image. For
// example, suppose you have an 8x4 image. A valid plane scaling would be
// 4x2 -> 8x4 or 4x4 -> 4x4, but not 6x4 -> 8x4. So if a 6x4 plane is
// given, then it would be treated like a cropped 8x4 plane (since 1.0 is
// the closest scaling ratio to the actual ratio of 1.3).
//
// For an explanation of why this makes sense, consider the relatively
// common example of a subsampled, oddly sized (e.g. jpeg) image. In such
// cases, for example a 35x23 image, the 4:2:0 subsampled chroma plane
// would have to end up as 17.5x11.5, which gets rounded up to 18x12 by
// implementations. So in this example, the 18x12 chroma plane would get
// treated by libplacebo as an oversized chroma plane - i.e. the plane
// would get sampled as if it was 17.5 pixels wide and 11.5 pixels large.
// Associated film grain data (see <libplacebo/shaders/film_grain.h>).
//
// Note: This is ignored for the `target` of `pl_render_image`, since
// un-applying grain makes little sense.
struct pl_film_grain_data film_grain;
// Ignored by libplacebo. May be useful for users.
void *user_data;
};
// Helper function to infer the chroma location offset for each plane in a
// frame. This is equivalent to calling `pl_chroma_location_offset` on all
// subsampled planes' shift_x/shift_y variables.
PL_API void pl_frame_set_chroma_location(struct pl_frame *frame,
enum pl_chroma_location chroma_loc);
// Fills in a `pl_frame` based on a swapchain frame's FBO and metadata.
PL_API void pl_frame_from_swapchain(struct pl_frame *out_frame,
const struct pl_swapchain_frame *frame);
// Helper function to determine if a frame is logically cropped or not. In
// particular, this is useful in determining whether or not an output frame
// needs to be cleared before rendering or not.
PL_API bool pl_frame_is_cropped(const struct pl_frame *frame);
// Helper function to reset a frame to a given RGB color. If the frame's
// color representation is something other than RGB, the clear color will
// be adjusted accordingly. `clear_color` should be non-premultiplied.
PL_API void pl_frame_clear_rgba(pl_gpu gpu, const struct pl_frame *frame,
const float clear_color[4]);
// Like `pl_frame_clear_rgba` but without an alpha channel.
static inline void pl_frame_clear(pl_gpu gpu, const struct pl_frame *frame,
const float clear_color[3])
{
const float clear_color_rgba[4] = { clear_color[0], clear_color[1], clear_color[2], 1.0 };
pl_frame_clear_rgba(gpu, frame, clear_color_rgba);
}
// Helper functions to return the fixed/inferred pl_frame parameters used
// for rendering internally. Mutates `image` and `target` in-place to hold
// the modified values, which are what will actually be used for rendering.
//
// This currently includes:
// - Defaulting all missing pl_color_space/repr parameters
// - Coalescing all rotation to the target
// - Rounding and clamping the target crop to pixel boundaries and adjusting the
// image crop correspondingly
//
// Note: This is idempotent and does not generally alter the effects of a
// subsequent `pl_render_image` on the same pl_frame pair. (But see the
// following warning)
//
// Warning: This does *not* call pl_frame.acquire/release, and so the returned
// metadata *may* be incorrect if the acquire callback mutates the pl_frame in
// nontrivial ways, in particular the crop and color space fields.
PL_API void pl_frames_infer(pl_renderer rr, struct pl_frame *image,
struct pl_frame *target);
// Render a single image to a target using the given parameters. This is
// fully dynamic, i.e. the params can change at any time. libplacebo will
// internally detect and flush whatever caches are invalidated as a result of
// changing colorspace, size etc.
//
// Required plane capabilities:
// - Planes in `image` must be `sampleable`
// - Planes in `target` must be `renderable`
//
// Recommended plane capabilities: (Optional, but good for performance)
// - Planes in `image` should have `sample_mode` PL_TEX_SAMPLE_LINEAR
// - Planes in `target` should be `storable`
// - Planes in `target` should have `blit_dst`
//
// Note on lifetime: Once this call returns, the passed structures may be
// freely overwritten or discarded by the caller, even the referenced
// `pl_tex` objects may be freely reused.
//
// Note: `image` may be NULL, in which case `target.overlays` will still be
// rendered, but nothing else.
PL_API bool pl_render_image(pl_renderer rr, const struct pl_frame *image,
const struct pl_frame *target,
const struct pl_render_params *params);
// Flushes the internal state of this renderer. This is normally not needed,
// even if the image parameters, colorspace or target configuration change,
// since libplacebo will internally detect such circumstances and recreate
// outdated resources automatically. Doing this explicitly *may* be useful to
// purge some state related to things like HDR peak detection or frame mixing,
// so calling it is a good idea if the content source is expected to change
// dramatically (e.g. when switching to a different file).
PL_API void pl_renderer_flush_cache(pl_renderer rr);
// Mirrors `pl_get_detected_hdr_metadata`, giving you the current internal peak
// detection HDR metadata (when peak detection is active). Returns false if no
// information is available (e.g. not HDR source, peak detection disabled).
PL_API bool pl_renderer_get_hdr_metadata(pl_renderer rr,
struct pl_hdr_metadata *metadata);
// Represents a mixture of input frames, distributed temporally.
//
// NOTE: Frames must be sorted by timestamp, i.e. `timestamps` must be
// monotonically increasing.
struct pl_frame_mix {
// The number of frames in this mixture. The number of frames should be
// sufficient to meet the needs of the configured frame mixer. See the
// section below for more information.
//
// If the number of frames is 0, this call will be equivalent to
// `pl_render_image` with `image == NULL`.
int num_frames;
// A list of the frames themselves. The frames can have different
// colorspaces, configurations of planes, or even sizes.
//
// Note: This is a list of pointers, to avoid users having to copy
// around `pl_frame` structs when re-organizing this array.
const struct pl_frame **frames;
// A list of unique signatures, one for each frame. These are used to
// identify frames across calls to this function, so it's crucial that they
// be both unique per-frame but also stable across invocations of
// `pl_render_frame_mix`.
const uint64_t *signatures;
// A list of relative timestamps for each frame. These are relative to the
// time of the vsync being drawn, i.e. this function will render the frame
// that will be made visible at timestamp 0.0. The values are expected to
// be normalized such that a separation of 1.0 corresponds to roughly one
// nominal source frame duration. So a constant framerate video file will
// always have timestamps like e.g. {-2.3, -1.3, -0.3, 0.7, 1.7, 2.7},
// using an example radius of 3.
//
// In cases where the framerate is variable (e.g. VFR video), the choice of
// what to scale to use can be difficult to answer. A typical choice would
// be either to use the canonical (container-tagged) framerate, or the
// highest momentary framerate, as a reference. If all else fails, you
// could also use the display's framerate.
//
// Note: This function assumes zero-order-hold semantics, i.e. the frame at
// timestamp 0.7 is intended to remain visible until timestamp 1.7, when
// the next frame replaces it.
const float *timestamps;
// The duration for which the vsync being drawn will be held, using the
// same scale as `timestamps`. If the display has an unknown or variable
// frame-rate (e.g. Adaptive Sync), then you're probably better off not
// using this function and instead just painting the frames directly using
// `pl_render_frame` at the correct PTS.
//
// As an example, if `vsync_duration` is 0.4, then it's assumed that the
// vsync being painted is visible for the period [0.0, 0.4].
float vsync_duration;
// Explanation of the frame mixing radius: The algorithm chosen in
// `pl_render_params.frame_mixer` has a canonical radius equal to
// `pl_filter_config.kernel->radius`. This means that the frame mixing
// algorithm will (only) need to consult all of the frames that have a
// distance within the interval [-radius, radius]. As such, the user should
// include all such frames in `frames`, but may prune or omit frames that
// lie outside it.
//
// The built-in frame mixing (`pl_render_params.frame_mixer == NULL`) has
// no concept of radius, it just always needs access to the "current" and
// "next" frames.
};
// Helper function to calculate the base frame mixing radius.
//
// Note: When the source FPS exceeds the display FPS, this radius must be
// increased by the corresponding ratio.
static inline float pl_frame_mix_radius(const struct pl_render_params *params)
{
// For backwards compatibility, allow !frame_mixer->kernel
if (!params->frame_mixer || !params->frame_mixer->kernel)
return 0.0;
return params->frame_mixer->kernel->radius;
}
// Find closest frame to current PTS by zero-order hold semantics, or NULL.
PL_API const struct pl_frame *pl_frame_mix_current(const struct pl_frame_mix *mix);
// Find closest frame to current PTS by nearest neighbour semantics, or NULL.
PL_API const struct pl_frame *pl_frame_mix_nearest(const struct pl_frame_mix *mix);
// Render a mixture of images to the target using the given parameters. This
// functions much like a generalization of `pl_render_image`, for when the API
// user has more control over the frame queue / vsync loop, and can provide a
// few frames from the past and future + timestamp information.
//
// This allows libplacebo to perform rudimentary frame mixing / interpolation,
// in order to eliminate judder artifacts typically associated with
// source/display frame rate mismatch.
PL_API bool pl_render_image_mix(pl_renderer rr, const struct pl_frame_mix *images,
const struct pl_frame *target,
const struct pl_render_params *params);
// Analog of `pl_frame_infer` corresponding to `pl_render_image_mix`. This
// function will *not* mutate the frames contained in `mix`, and instead
// return an adjusted copy of the "reference" frame for that image mix in
// `out_refimage`, or {0} if the mix is empty.
PL_API void pl_frames_infer_mix(pl_renderer rr, const struct pl_frame_mix *mix,
struct pl_frame *target, struct pl_frame *out_ref);
// Backwards compatibility with old filters API, may be deprecated.
// Redundant with pl_filter_configs and masking `allowed` for
// PL_FILTER_SCALING and PL_FILTER_FRAME_MIXING respectively.
// A list of recommended frame mixer presets, terminated by {0}
PL_API extern const struct pl_filter_preset pl_frame_mixers[];
PL_API extern const int pl_num_frame_mixers; // excluding trailing {0}
// A list of recommended scaler presets, terminated by {0}. This is almost
// equivalent to `pl_filter_presets` with the exception of including extra
// built-in filters that don't map to the `pl_filter` architecture.
PL_API extern const struct pl_filter_preset pl_scale_filters[];
PL_API extern const int pl_num_scale_filters; // excluding trailing {0}
// Deprecated in favor of `pl_cache_save/pl_cache_load` on the `pl_cache`
// associated with the `pl_gpu` this renderer is using.
PL_DEPRECATED PL_API size_t pl_renderer_save(pl_renderer rr, uint8_t *out_cache);
PL_DEPRECATED PL_API void pl_renderer_load(pl_renderer rr, const uint8_t *cache);
PL_API_END
#endif // LIBPLACEBO_RENDERER_H_

View File

@ -0,0 +1,273 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_H_
#define LIBPLACEBO_SHADERS_H_
// This function defines the "direct" interface to libplacebo's GLSL shaders,
// suitable for use in contexts where the user controls GLSL shader compilation
// but wishes to include functions generated by libplacebo as part of their
// own rendering process. This API is normally not used for operation with
// libplacebo's higher-level constructs such as `pl_dispatch` or `pl_renderer`.
#include <libplacebo/gpu.h>
PL_API_BEGIN
// Thread-safety: Unsafe
typedef struct pl_shader_t *pl_shader;
struct pl_shader_params {
// The `id` represents an abstract identifier for the shader, to avoid
// collisions with other shaders being used as part of the same larger,
// overarching shader. This is relevant for users which want to combine
// multiple `pl_shader` objects together, in which case all `pl_shader`
// objects should have a unique `id`.
uint8_t id;
// If `gpu` is non-NULL, then this `gpu` will be used to create objects
// such as textures and buffers, or check for required capabilities, for
// operations which depend on either of those. This is fully optional, i.e.
// these GLSL primitives are designed to be used without a dependency on
// `gpu` wherever possible - however, some features may not work, and will
// be disabled even if requested.
pl_gpu gpu;
// The `index` represents an abstract frame index, which shaders may use
// internally to do things like temporal dithering or seeding PRNGs. If the
// user does not care about temporal dithering/debanding, or wants
// deterministic rendering, this may safely be left as 0. Otherwise, it
// should be incremented by 1 on successive frames.
uint8_t index;
// If `glsl.version` is nonzero, then this structure will be used to
// determine the effective GLSL mode and capabilities. If `gpu` is also
// set, then this overrides `gpu->glsl`.
struct pl_glsl_version glsl;
// If this is true, all constants in the shader will be replaced by
// dynamic variables. This is mainly useful to avoid recompilation for
// shaders which expect to have their values change constantly.
bool dynamic_constants;
};
#define pl_shader_params(...) (&(struct pl_shader_params) { __VA_ARGS__ })
// Creates a new, blank, mutable pl_shader object.
//
// Note: Rather than allocating and destroying many shaders, users are
// encouraged to reuse them (using `pl_shader_reset`) for efficiency.
PL_API pl_shader pl_shader_alloc(pl_log log, const struct pl_shader_params *params);
// Frees a pl_shader and all resources associated with it.
PL_API void pl_shader_free(pl_shader *sh);
// Resets a pl_shader to a blank slate, without releasing internal memory.
// If you're going to be re-generating shaders often, this function will let
// you skip the re-allocation overhead.
PL_API void pl_shader_reset(pl_shader sh, const struct pl_shader_params *params);
// Returns whether or not a shader is in a "failed" state. Trying to modify a
// shader in illegal ways (e.g. signature mismatch) will result in the shader
// being marked as "failed". Since most pl_shader_ operations have a void
// return type, the user can use this function to figure out whether a specific
// shader operation has failed or not. This function is somewhat redundant
// since `pl_shader_finalize` will also return NULL in this case.
PL_API bool pl_shader_is_failed(const pl_shader sh);
// Returns whether or not a pl_shader needs to be run as a compute shader. This
// will never be the case unless the `pl_glsl_version` this `pl_shader` was
// created using has `compute` support enabled.
PL_API bool pl_shader_is_compute(const pl_shader sh);
// Returns whether or not the shader has any particular output size
// requirements. Some shaders, in particular those that sample from other
// textures, have specific output size requirements which need to be respected
// by the caller. If this is false, then the shader is compatible with every
// output size. If true, the size requirements are stored into *w and *h.
PL_API bool pl_shader_output_size(const pl_shader sh, int *w, int *h);
// Indicates the type of signature that is associated with a shader result.
// Every shader result defines a function that may be called by the user, and
// this enum indicates the type of value that this function takes and/or
// returns.
//
// Which signature a shader ends up with depends on the type of operation being
// performed by a shader fragment, as determined by the user's calls. See below
// for more information.
enum pl_shader_sig {
PL_SHADER_SIG_NONE = 0, // no input / void output
PL_SHADER_SIG_COLOR, // vec4 color (normalized so that 1.0 is the ref white)
// The following are only valid as input signatures:
PL_SHADER_SIG_SAMPLER, // (gsampler* src_tex, vecN tex_coord) pair,
// specifics depend on how the shader was generated
};
// Structure encapsulating information about a shader. This is internally
// refcounted, to allow moving it around without having to create deep copies.
typedef const struct pl_shader_info_t {
// A copy of the parameters used to create the shader.
struct pl_shader_params params;
// A list of friendly names for the semantic operations being performed by
// this shader, e.g. "color decoding" or "debanding".
const char **steps;
int num_steps;
// As a convenience, this contains a pretty-printed version of the
// above list, with entries tallied and separated by commas
const char *description;
} *pl_shader_info;
PL_API pl_shader_info pl_shader_info_ref(pl_shader_info info);
PL_API void pl_shader_info_deref(pl_shader_info *info);
// Represents a finalized shader fragment. This is not a complete shader, but a
// collection of raw shader text together with description of the input
// attributes, variables and vertices it expects to be available.
struct pl_shader_res {
// Descriptive information about the shader. Note that this reference is
// attached to the shader itself - the user does not need to manually ref
// or deref `info` unless they wish to move it elsewhere.
pl_shader_info info;
// The shader text, as literal GLSL. This will always be a function
// definition, such that the the function with the indicated name and
// signature may be called by the user.
const char *glsl;
const char *name;
enum pl_shader_sig input; // what the function expects
enum pl_shader_sig output; // what the function returns
// For compute shaders (pl_shader_is_compute), this indicates the requested
// work group size. Otherwise, both fields are 0. The interpretation of
// these work groups is that they're tiled across the output image.
int compute_group_size[2];
// If this pass is a compute shader, this field indicates the shared memory
// size requirements for this shader pass.
size_t compute_shmem;
// A set of input vertex attributes needed by this shader fragment.
const struct pl_shader_va *vertex_attribs;
int num_vertex_attribs;
// A set of input variables needed by this shader fragment.
const struct pl_shader_var *variables;
int num_variables;
// A list of input descriptors needed by this shader fragment,
const struct pl_shader_desc *descriptors;
int num_descriptors;
// A list of compile-time constants used by this shader fragment.
const struct pl_shader_const *constants;
int num_constants;
// --- Deprecated fields (see `info`)
struct pl_shader_params params PL_DEPRECATED;
const char **steps PL_DEPRECATED;
int num_steps PL_DEPRECATED;
const char *description PL_DEPRECATED;
};
// Represents a vertex attribute. The four values will be bound to the four
// corner vertices respectively, in row-wise order starting from the top left:
// data[0] data[1]
// data[2] data[3]
struct pl_shader_va {
struct pl_vertex_attrib attr; // VA type, excluding `offset` and `location`
const void *data[4];
};
// Represents a bound shared variable / descriptor
struct pl_shader_var {
struct pl_var var; // the underlying variable description
const void *data; // the raw data (as per `pl_var_host_layout`)
bool dynamic; // if true, the value is expected to change frequently
};
struct pl_buffer_var {
struct pl_var var;
struct pl_var_layout layout;
};
typedef uint16_t pl_memory_qualifiers;
enum {
PL_MEMORY_COHERENT = 1 << 0, // supports synchronization across shader invocations
PL_MEMORY_VOLATILE = 1 << 1, // all writes are synchronized automatically
// Note: All descriptors are also implicitly assumed to have the 'restrict'
// memory qualifier. There is currently no way to override this behavior.
};
struct pl_shader_desc {
struct pl_desc desc; // descriptor type, excluding `int binding`
struct pl_desc_binding binding; // contents of the descriptor binding
// For PL_DESC_BUF_UNIFORM/STORAGE, this specifies the layout of the
// variables contained by a buffer. Ignored for the other descriptor types
struct pl_buffer_var *buffer_vars;
int num_buffer_vars;
// For storage images and buffers, this specifies additional memory
// qualifiers on the descriptor. It's highly recommended to always use
// at least PL_MEMORY_RESTRICT. Ignored for other descriptor types.
pl_memory_qualifiers memory;
};
// Represents a compile-time constant. This can be lowered to a specialization
// constant to support cheaper recompilations.
struct pl_shader_const {
enum pl_var_type type;
const char *name;
const void *data;
// If true, this constant *must* be a compile-time constant, which
// basically just overrides `pl_shader_params.dynamic_constants`. Useful
// for constants which will serve as inputs to e.g. array sizes.
bool compile_time;
};
// Finalize a pl_shader. It is no longer mutable at this point, and any further
// attempts to modify it result in an error. (Functions which take a `const
// pl_shader` argument do not modify the shader and may be freely
// called on an already-finalized shader)
//
// The returned pl_shader_res is bound to the lifetime of the pl_shader - and
// will only remain valid until the pl_shader is freed or reset. This function
// may be called multiple times, and will produce the same result each time.
//
// This function will return NULL if the shader is considered to be in a
// "failed" state (see pl_shader_is_failed).
PL_API const struct pl_shader_res *pl_shader_finalize(pl_shader sh);
// Shader objects represent abstract resources that shaders need to manage in
// order to ensure their operation. This could include shader storage buffers,
// generated lookup textures, or other sorts of configured state. The body
// of a shader object is fully opaque; but the user is in charge of cleaning up
// after them and passing them to the right shader passes.
//
// Note: pl_shader_obj objects must be initialized to NULL by the caller.
typedef struct pl_shader_obj_t *pl_shader_obj;
PL_API void pl_shader_obj_destroy(pl_shader_obj *obj);
PL_API_END
#endif // LIBPLACEBO_SHADERS_H_

View File

@ -0,0 +1,381 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_COLORSPACE_H_
#define LIBPLACEBO_SHADERS_COLORSPACE_H_
// Color space transformation shaders. These all input and output a color
// value (PL_SHADER_SIG_COLOR).
#include <libplacebo/colorspace.h>
#include <libplacebo/gamut_mapping.h>
#include <libplacebo/tone_mapping.h>
#include <libplacebo/shaders.h>
// For backwards compatibility
#include <libplacebo/shaders/dithering.h>
PL_API_BEGIN
// Transform the input color, in its given representation, to ensure
// compatibility with the indicated alpha mode. Mutates `repr` to reflect the
// change. Note that this is a no-op if the input is PL_ALPHA_UNKNOWN.
PL_API void pl_shader_set_alpha(pl_shader sh, struct pl_color_repr *repr,
enum pl_alpha_mode mode);
// Colorspace reshaping for PL_COLOR_SYSTEM_DOLBYVISION. Note that this is done
// automatically by `pl_shader_decode_color` for PL_COLOR_SYSTEM_DOLBYVISION.
PL_API void pl_shader_dovi_reshape(pl_shader sh, const struct pl_dovi_metadata *data);
// Decode the color into normalized RGB, given a specified color_repr. This
// also takes care of additional pre- and post-conversions requires for the
// "special" color systems (XYZ, BT.2020-C, etc.). If `params` is left as NULL,
// it defaults to &pl_color_adjustment_neutral.
//
// Note: This function always returns PC-range RGB with independent alpha.
// It mutates the pl_color_repr to reflect the change.
//
// Note: For DCDM XYZ decoding output is linear
PL_API void pl_shader_decode_color(pl_shader sh, struct pl_color_repr *repr,
const struct pl_color_adjustment *params);
// Encodes a color from normalized, PC-range, independent alpha RGB into a
// given representation. That is, this performs the inverse operation of
// `pl_shader_decode_color` (sans color adjustments).
//
// Note: For DCDM XYZ encoding input is expected to be linear
PL_API void pl_shader_encode_color(pl_shader sh, const struct pl_color_repr *repr);
// Linearize (expand) `vec4 color`, given a specified color space. In essence,
// this corresponds to the ITU-R EOTF.
//
// Note: Unlike the ITU-R EOTF, it never includes the OOTF - even for systems
// where the EOTF includes the OOTF (such as HLG).
PL_API void pl_shader_linearize(pl_shader sh, const struct pl_color_space *csp);
// Delinearize (compress), given a color space as output. This loosely
// corresponds to the inverse EOTF (not the OETF) in ITU-R terminology, again
// assuming a reference monitor.
PL_API void pl_shader_delinearize(pl_shader sh, const struct pl_color_space *csp);
struct pl_sigmoid_params {
// The center (bias) of the sigmoid curve. Must be between 0.0 and 1.0.
// If left as NULL, defaults to 0.75
float center;
// The slope (steepness) of the sigmoid curve. Must be between 1.0 and 20.0.
// If left as NULL, defaults to 6.5.
float slope;
};
#define PL_SIGMOID_DEFAULTS \
.center = 0.75, \
.slope = 6.50,
#define pl_sigmoid_params(...) (&(struct pl_sigmoid_params) { PL_SIGMOID_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_sigmoid_params pl_sigmoid_default_params;
// Applies a sigmoidal color transform to all channels. This helps avoid
// ringing artifacts during upscaling by bringing the color information closer
// to neutral and away from the extremes. If `params` is NULL, it defaults to
// &pl_sigmoid_default_params.
//
// Warning: This function clamps the input to the interval [0,1]; and as such
// it should *NOT* be used on already-decoded high-dynamic range content.
PL_API void pl_shader_sigmoidize(pl_shader sh, const struct pl_sigmoid_params *params);
// This performs the inverse operation to `pl_shader_sigmoidize`.
PL_API void pl_shader_unsigmoidize(pl_shader sh, const struct pl_sigmoid_params *params);
struct pl_peak_detect_params {
// Smoothing coefficient for the detected values. This controls the time
// parameter (tau) of an IIR low pass filter. In other words, it represent
// the cutoff period (= 1 / cutoff frequency) in frames. Frequencies below
// this length will be suppressed. This helps block out annoying
// "sparkling" or "flickering" due to small variations in frame-to-frame
// brightness. If left as 0.0, this smoothing is completely disabled.
float smoothing_period;
// In order to avoid reacting sluggishly on scene changes as a result of
// the low-pass filter, we disable it when the difference between the
// current frame brightness and the average frame brightness exceeds a
// given threshold difference. But rather than a single hard cutoff, which
// would lead to weird discontinuities on fades, we gradually disable it
// over a small window of brightness ranges. These parameters control the
// lower and upper bounds of this window, in units of 1% PQ.
//
// Setting either one of these to 0.0 disables this logic.
float scene_threshold_low;
float scene_threshold_high;
// Which percentile of the input image brightness histogram to consider as
// the true peak of the scene. If this is set to 100 (or 0), the brightest
// pixel is measured. Otherwise, the top of the frequency distribution is
// progressively cut off. Setting this too low will cause clipping of very
// bright details, but can improve the dynamic brightness range of scenes
// with very bright isolated highlights.
//
// A recommended value is 99.995%, which is very conservative and should
// cause no major issues in typical content.
float percentile;
// Allows the peak detection result to be delayed by up to a single frame,
// which can sometimes improve thoughput, at the cost of introducing the
// possibility of 1-frame flickers on transitions. Disabled by default.
bool allow_delayed;
// --- Deprecated / removed fields
float overshoot_margin PL_DEPRECATED;
float minimum_peak PL_DEPRECATED;
};
#define PL_PEAK_DETECT_DEFAULTS \
.smoothing_period = 20.0f, \
.scene_threshold_low = 1.0f, \
.scene_threshold_high = 3.0f, \
.percentile = 100.0f,
#define PL_PEAK_DETECT_HQ_DEFAULTS \
PL_PEAK_DETECT_DEFAULTS \
.percentile = 99.995f,
#define pl_peak_detect_params(...) (&(struct pl_peak_detect_params) { PL_PEAK_DETECT_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_peak_detect_params pl_peak_detect_default_params;
PL_API extern const struct pl_peak_detect_params pl_peak_detect_high_quality_params;
// This function can be used to measure the CLL and FALL of a video
// source automatically, using a compute shader. The measured values are
// smoothed automatically (depending on the parameters), so to keep track of
// the measured results over time, a tone mapping shader state object is used
// to hold the state. Returns false on failure initializing the tone mapping
// object, or if compute shaders are not supported.
//
// It's important that the same shader object is used for successive frames
// belonging to the same source. If the source changes (e.g. due to a file
// change or seek), the user should reset it with `pl_reset_detected_peak` (or
// destroy it and use a new state object).
//
// The parameter `csp` holds the representation of the color values that are
// the input to this function. (They must already be in decoded RGB form, i.e.
// alternate color representations are not supported)
PL_API bool pl_shader_detect_peak(pl_shader sh, struct pl_color_space csp,
pl_shader_obj *state,
const struct pl_peak_detect_params *params);
// After dispatching the above shader, this function can be used to retrieve
// the detected dynamic HDR10+ metadata parameters. The other fields of
// `metadata` are not written to. Returns whether or not any values were
// written. If not, the values are left untouched, so this can be used to
// safely update `pl_hdr_metadata` values in-place. This function may or may
// not block, depending on the previous setting of `allow_delayed`.
PL_API bool pl_get_detected_hdr_metadata(const pl_shader_obj state,
struct pl_hdr_metadata *metadata);
// After dispatching the above shader, this function *may* be used to read out
// the detected CLL and FALL directly (in PL_HDR_NORM units). If the shader
// has never been dispatched yet, i.e. no information is available, this will
// return false.
//
// Deprecated in favor of `pl_get_detected_hdr_metadata`
PL_DEPRECATED PL_API bool pl_get_detected_peak(const pl_shader_obj state,
float *out_cll, float *out_fall);
// Resets the peak detection state in a given tone mapping state object. This
// is not equal to `pl_shader_obj_destroy`, because it does not destroy any
// state used by `pl_shader_tone_map`.
PL_API void pl_reset_detected_peak(pl_shader_obj state);
// Feature map extraction (for pl_color_map_args.feature_map). The result
// of this shader should be downscaled / low-passed to the indicated kernel
// size before use. (This does not happen automatically)
PL_API void pl_shader_extract_features(pl_shader sh, struct pl_color_space csp);
// Deprecated and unused. Libplacebo now always performs a variant of the old
// hybrid tone-mapping, mixing together the intensity (I) and per-channel (LMS)
// results.
enum pl_tone_map_mode {
PL_TONE_MAP_AUTO PL_DEPRECATED_ENUMERATOR,
PL_TONE_MAP_RGB PL_DEPRECATED_ENUMERATOR,
PL_TONE_MAP_MAX PL_DEPRECATED_ENUMERATOR,
PL_TONE_MAP_HYBRID PL_DEPRECATED_ENUMERATOR,
PL_TONE_MAP_LUMA PL_DEPRECATED_ENUMERATOR,
PL_TONE_MAP_MODE_COUNT,
};
// Deprecated by <libplacebo/gamut_mapping.h>
enum pl_gamut_mode {
PL_GAMUT_CLIP PL_DEPRECATED_ENUMERATOR, // pl_gamut_map_clip
PL_GAMUT_WARN PL_DEPRECATED_ENUMERATOR, // pl_gamut_map_highlight
PL_GAMUT_DARKEN PL_DEPRECATED_ENUMERATOR, // pl_gamut_map_darken
PL_GAMUT_DESATURATE PL_DEPRECATED_ENUMERATOR, // pl_gamut_map_desaturate
PL_GAMUT_MODE_COUNT,
};
struct pl_color_map_params {
// --- Gamut mapping options
// Gamut mapping function to use to handle out-of-gamut colors, including
// colors which are out-of-gamut as a consequence of tone mapping.
const struct pl_gamut_map_function *gamut_mapping;
// Gamut mapping constants, for expert tuning. Leave as default otherwise.
struct pl_gamut_map_constants gamut_constants;
// Gamut mapping 3DLUT size, for channels ICh. Defaults to {48, 32, 256}
int lut3d_size[3];
// Use higher quality, but slower, tricubic interpolation for gamut mapping
// 3DLUTs. May substantially improve the 3DLUT gamut mapping accuracy, in
// particular at smaller 3DLUT sizes. Shouldn't have much effect at the
// default size.
bool lut3d_tricubic;
// If true, allows the gamut mapping function to expand the gamut, in
// cases where the target gamut exceeds that of the source. If false,
// the source gamut will never be enlarged, even when using a gamut
// mapping function capable of bidirectional mapping.
bool gamut_expansion;
// --- Tone mapping options
// Tone mapping function to use to handle out-of-range colors.
const struct pl_tone_map_function *tone_mapping_function;
// Tone mapping constants, for expert tuning. Leave as default otherwise.
struct pl_tone_map_constants tone_constants;
// If true, and supported by the given tone mapping function, libplacebo
// will perform inverse tone mapping to expand the dynamic range of a
// signal. libplacebo is not liable for any HDR-induced eye damage.
bool inverse_tone_mapping;
// Data source to use when tone-mapping. Setting this to a specific
// value allows overriding the default metadata preference logic.
enum pl_hdr_metadata_type metadata;
// Tone mapping LUT size. Defaults to 256.
int lut_size;
// HDR contrast recovery strength. If set to a value above 0.0, the source
// image will be divided into high-frequency and low-frequency components,
// and a portion of the high-frequency image is added back onto the
// tone-mapped output. May cause excessive ringing artifacts for some HDR
// sources, but can improve the subjective sharpness and detail left over
// in the image after tone-mapping.
float contrast_recovery;
// Contrast recovery lowpass kernel size. Defaults to 3.5. Increasing
// or decreasing this will affect the visual appearance substantially.
float contrast_smoothness;
// --- Debugging options
// Force the use of a full tone-mapping LUT even for functions that have
// faster pure GLSL replacements (e.g. clip, linear, saturation).
bool force_tone_mapping_lut;
// Visualize the tone-mapping LUT and gamut mapping 3DLUT, in IPT space.
bool visualize_lut;
// Controls where to draw the visualization, relative to the rendered
// video (dimensions 0-1). Optional, defaults to the full picture.
pl_rect2df visualize_rect;
// Controls the rotation of the 3DLUT visualization.
float visualize_hue; // useful range [-pi, pi]
float visualize_theta; // useful range [0, pi/2]
// Graphically highlight hard-clipped pixels during tone-mapping (i.e.
// pixels that exceed the claimed source luminance range).
bool show_clipping;
// --- Deprecated fields
enum pl_tone_map_mode tone_mapping_mode PL_DEPRECATED; // removed
float tone_mapping_param PL_DEPRECATED; // see `tone_constants`
float tone_mapping_crosstalk PL_DEPRECATED; // now hard-coded as 0.04
enum pl_rendering_intent intent PL_DEPRECATED; // see `gamut_mapping`
enum pl_gamut_mode gamut_mode PL_DEPRECATED; // see `gamut_mapping`
float hybrid_mix PL_DEPRECATED; // removed
};
#define PL_COLOR_MAP_DEFAULTS \
.gamut_mapping = &pl_gamut_map_perceptual, \
.tone_mapping_function = &pl_tone_map_spline, \
.gamut_constants = { PL_GAMUT_MAP_CONSTANTS }, \
.tone_constants = { PL_TONE_MAP_CONSTANTS }, \
.metadata = PL_HDR_METADATA_ANY, \
.lut3d_size = {48, 32, 256}, \
.lut_size = 256, \
.visualize_rect = {0, 0, 1, 1}, \
.contrast_smoothness = 3.5f,
#define PL_COLOR_MAP_HQ_DEFAULTS \
PL_COLOR_MAP_DEFAULTS \
.contrast_recovery = 0.30f,
#define pl_color_map_params(...) (&(struct pl_color_map_params) { PL_COLOR_MAP_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_color_map_params pl_color_map_default_params;
PL_API extern const struct pl_color_map_params pl_color_map_high_quality_params;
// Execution arguments for the `pl_shader_color_map_ex` call. Distinct from
// `pl_color_map_params` because it is filled by internally-provided execution
// metadata, instead of user-tunable aesthetic parameters.
struct pl_color_map_args {
// Input/output color space for the mapping.
struct pl_color_space src;
struct pl_color_space dst;
// If true, the logic will assume the input has already been linearized by
// the caller (e.g. as part of a previous linear light scaling operation).
bool prelinearized;
// Object to be used to store generated LUTs. Note that this is the same
// state object used by `pl_shader_detect_peak`, and if that function has
// been called on `state` prior to `pl_shader_color_map`, the detected
// values will be used to guide the tone mapping algorithm. If this is not
// provided, tone/gamut mapping are disabled.
pl_shader_obj *state;
// Low-resolution intensity feature map, as generated by
// `pl_shader_extract_features`. Optional. No effect if
// `params->contrast_recovery` is disabled.
pl_tex feature_map;
};
#define pl_color_map_args(...) (&(struct pl_color_map_args) { __VA_ARGS__ })
// Maps `vec4 color` from one color space to another color space according
// to the parameters (described in greater depth above). If `params` is left
// as NULL, it defaults to `&pl_color_map_default_params`
PL_API void pl_shader_color_map_ex(pl_shader sh,
const struct pl_color_map_params *params,
const struct pl_color_map_args *args);
// Backwards compatibility wrapper around `pl_shader_color_map_ex`
PL_API void pl_shader_color_map(pl_shader sh, const struct pl_color_map_params *params,
struct pl_color_space src, struct pl_color_space dst,
pl_shader_obj *state, bool prelinearized);
// Applies a set of cone distortion parameters to `vec4 color` in a given color
// space. This can be used to simulate color blindness. See `pl_cone_params`
// for more information.
PL_API void pl_shader_cone_distort(pl_shader sh, struct pl_color_space csp,
const struct pl_cone_params *params);
PL_API_END
#endif // LIBPLACEBO_SHADERS_COLORSPACE_H_

View File

@ -0,0 +1,341 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_CUSTOM_H_
#define LIBPLACEBO_SHADERS_CUSTOM_H_
#include <stdlib.h>
// Functions for writing custom shaders and hooking them into the `pl_renderer`
// pipeline, as well as compatibility functions for parsing shaders in mpv
// format.
#include <libplacebo/shaders.h>
#include <libplacebo/dispatch.h>
#include <libplacebo/colorspace.h>
PL_API_BEGIN
// Parameters describing custom shader text to be embedded into a `pl_shader`
// object. All of the strings are optional and can be left as NULL, but without
// a `body` in particular, the shader will do nothing useful on its own.
struct pl_custom_shader {
// The prelude contains text such as extra #defines, #extension pragmas,
// or other parts of the shader that must be placed at the very
// beginning (before input layout declarations etc.)
//
// Note: #extension pragmas do not need to be emitted to enable support for
// resource types already attached to the shader (e.g. SSBOs), compute
// shaders, or GPU capabilities known to libplacebo (e.g. subgroups).
const char *prelude;
// The header contains text such as helper function definitions, extra
// uniforms, shared memory variables or buffer descriptions.
const char *header;
// A friendly name for the shader. (Optional)
const char *description;
// The "primary" GLSL code. This will be effectively appended to the "main"
// function. It lives in an environment given by the `input` signature, and
// is expected to return results in a way given by the `output` signature.
//
// Note: In the case of PL_SHADER_SIG_COLOR, the output `vec4 color` is
// allocated by `pl_shader_custom`, the user merely needs to assign to it.
//
// Note: For ease of development it can be useful to have the main logic
// live inside a helper function defined as part of `header`, and specify
// the `body` as a single line that simply calls the helper function.
const char *body;
enum pl_shader_sig input;
enum pl_shader_sig output;
// Extra descriptors, variables and vertex attributes to attach to the
// resulting `pl_shader_res`.
//
// Note: The names inside these will possibly be replaced by fresh
// identifiers internally, so users should avoid looking for exact string
// matches for the given names inside the `pl_shader_res`.
const struct pl_shader_desc *descriptors;
int num_descriptors;
const struct pl_shader_var *variables;
int num_variables;
const struct pl_shader_va *vertex_attribs;
int num_vertex_attribs;
const struct pl_shader_const *constants;
int num_constants;
// If true, this shader must be a compute shader. The desired workgroup
// size and shared memory usage can be optionally specified, or 0 if no
// specific work group size or shared memory size restrictions apply.
//
// See also: `pl_shader_res.compute_group_size`
bool compute;
size_t compute_shmem;
int compute_group_size[2];
// Fixes the output size requirements of the shader to exact dimensions.
// Optional, if left as 0, means the shader can be dispatched at any size.
int output_w;
int output_h;
};
// Append custom shader code, including extra descriptors and variables, to an
// existing `pl_shader` object. Returns whether successful. This function may
// fail in the event that e.g. the custom shader requires compute shaders on
// an unsupported GPU, or exceeds the GPU's shared memory capabilities.
PL_API bool pl_shader_custom(pl_shader sh, const struct pl_custom_shader *params);
// Which "rendering stages" are available for user shader hooking purposes.
// Except where otherwise noted, all stages are "non-resizable", i.e. the
// shaders already have specific output size requirements.
enum pl_hook_stage {
// Hook stages for the untouched planes, as made available by the source.
// These are all resizable, i.e. there are no specific output stage
// requirements.
PL_HOOK_RGB_INPUT = 1 << 0,
PL_HOOK_LUMA_INPUT = 1 << 1,
PL_HOOK_CHROMA_INPUT = 1 << 2,
PL_HOOK_ALPHA_INPUT = 1 << 3,
PL_HOOK_XYZ_INPUT = 1 << 4,
// Hook stages for the scaled/aligned planes
PL_HOOK_CHROMA_SCALED = 1 << 5,
PL_HOOK_ALPHA_SCALED = 1 << 6,
PL_HOOK_NATIVE = 1 << 7, // Combined image in its native color space
PL_HOOK_RGB = 1 << 8, // After conversion to RGB (resizable)
PL_HOOK_LINEAR = 1 << 9, // After linearization but before scaling
PL_HOOK_SIGMOID = 1 << 10, // After sigmoidization
PL_HOOK_PRE_KERNEL = 1 << 11, // Immediately before the main scaler kernel
PL_HOOK_POST_KERNEL = 1 << 12, // Immediately after the main scaler kernel
PL_HOOK_SCALED = 1 << 13, // After scaling, before color management
PL_HOOK_PRE_OUTPUT = 1 << 14, // After color management, before blending/rotation
PL_HOOK_OUTPUT = 1 << 15, // After blending/rotation, before dithering
};
// Returns true if a given hook stage is resizable
static inline bool pl_hook_stage_resizable(enum pl_hook_stage stage) {
switch (stage) {
case PL_HOOK_RGB_INPUT:
case PL_HOOK_LUMA_INPUT:
case PL_HOOK_CHROMA_INPUT:
case PL_HOOK_ALPHA_INPUT:
case PL_HOOK_XYZ_INPUT:
case PL_HOOK_NATIVE:
case PL_HOOK_RGB:
return true;
case PL_HOOK_CHROMA_SCALED:
case PL_HOOK_ALPHA_SCALED:
case PL_HOOK_LINEAR:
case PL_HOOK_SIGMOID:
case PL_HOOK_PRE_KERNEL:
case PL_HOOK_POST_KERNEL:
case PL_HOOK_SCALED:
case PL_HOOK_PRE_OUTPUT:
case PL_HOOK_OUTPUT:
return false;
}
abort();
}
// The different forms of communicating image data between the renderer and
// the hooks
enum pl_hook_sig {
PL_HOOK_SIG_NONE, // No data is passed, no data is received/returned
PL_HOOK_SIG_COLOR, // `vec4 color` already pre-sampled in a `pl_shader`
PL_HOOK_SIG_TEX, // `pl_tex` containing the image data
PL_HOOK_SIG_COUNT,
};
struct pl_hook_params {
// GPU objects associated with the `pl_renderer`, which the user may
// use for their own purposes.
pl_gpu gpu;
pl_dispatch dispatch;
// Helper function to fetch a new temporary texture, using renderer-backed
// storage. This is guaranteed to have sane image usage requirements and a
// 16-bit or floating point format. The user does not need to free/destroy
// this texture in any way. May return NULL.
pl_tex (*get_tex)(void *priv, int width, int height);
void *priv;
// Which stage triggered the hook to run.
enum pl_hook_stage stage;
// For `PL_HOOK_SIG_COLOR`, this contains the existing shader object with
// the color already pre-sampled into `vec4 color`. The user may modify
// this as much as they want, as long as they don't dispatch/finalize/reset
// it.
//
// Note that this shader might have specific output size requirements,
// depending on the exact shader stage hooked by the user, and may already
// be a compute shader.
pl_shader sh;
// For `PL_HOOK_SIG_TEX`, this contains the texture that the user should
// sample from.
//
// Note: This texture object is owned by the renderer, and users must not
// modify its contents. It will not be touched for the duration of a frame,
// but the contents are lost in between frames.
pl_tex tex;
// The effective current rectangle of the image we're rendering in this
// shader, i.e. the effective rect of the content we're interested in,
// as a crop of either `sh` or `tex` (depending on the signature).
//
// Note: This is still set even for `PL_HOOK_SIG_NONE`!
pl_rect2df rect;
// The current effective colorspace and representation, of either the
// pre-sampled color (in `sh`), or the contents of `tex`, respectively.
//
// Note: This is still set even for `PL_HOOK_SIG_NONE`!
struct pl_color_repr repr;
struct pl_color_space color;
int components;
// The representation and colorspace of the original image, for reference.
const struct pl_color_repr *orig_repr;
const struct pl_color_space *orig_color;
// The (cropped) source and destination rectangles of the overall
// rendering. These are functionallty equivalent to `image.crop` and
// `target.crop`, respectively, but `src_rect` in particular may change as
// a result of previous hooks being executed. (e.g. prescalers)
pl_rect2df src_rect;
pl_rect2d dst_rect;
};
struct pl_hook_res {
// If true, the hook is assumed to have "failed" or errored in some way,
// and all other fields are ignored.
bool failed;
// What type of output this hook is returning.
// Note: If this is `PL_HOOK_SIG_NONE`, all other fields are ignored.
enum pl_hook_sig output;
// For `PL_HOOK_SIG_COLOR`, this *must* be set to a valid `pl_shader`
// object containing the sampled color value (i.e. with an output signature
// of `PL_SHADER_SIG_COLOR`), and *should* be allocated from the given
// `pl_dispatch` object. Ignored otherwise.
pl_shader sh;
// For `PL_HOOK_SIG_TEX`, this *must* contain the texture object containing
// the result of rendering the hook. This *should* be a texture allocated
// using the given `get_tex` callback, to ensure the format and texture
// usage flags are compatible with what the renderer expects.
pl_tex tex;
// For shaders that return some sort of output, this contains the
// new/altered versions of the existing "current texture" metadata.
struct pl_color_repr repr;
struct pl_color_space color;
int components;
// This contains the new effective rect of the contents. This may be
// different from the original `rect` for resizable passes. Ignored for
// non-resizable passes.
pl_rect2df rect;
};
enum pl_hook_par_mode {
PL_HOOK_PAR_VARIABLE, // normal shader variable
PL_HOOK_PAR_DYNAMIC, // dynamic shader variable, e.g. per-frame changing
PL_HOOK_PAR_CONSTANT, // fixed at compile time (e.g. for array sizes),
// must be scalar (non-vector/matrix)
PL_HOOK_PAR_DEFINE, // defined in the preprocessor, must be `int`
PL_HOOK_PAR_MODE_COUNT,
};
typedef union pl_var_data {
int i;
unsigned u;
float f;
} pl_var_data;
struct pl_hook_par {
// Name as used in the shader.
const char *name;
// Type of this shader parameter, and how it's manifested in the shader.
enum pl_var_type type;
enum pl_hook_par_mode mode;
// Human-readable explanation of this parameter. (Optional)
const char *description;
// Mutable data pointer to current value of variable.
pl_var_data *data;
// Default/initial value, and lower/upper bounds.
pl_var_data initial;
pl_var_data minimum;
pl_var_data maximum;
// Human-readable names for the variants of an integer option. This array
// can be indexed directly by integer values, ranging from `minimum.i` to
// `maximum.i`. May be NULL, in which case options are unnamed.
const char * const *names;
};
// Struct describing a hook.
//
// Note: Users may freely create their own instances of this struct, there is
// nothing particularly special about `pl_mpv_user_shader_parse`.
struct pl_hook {
enum pl_hook_stage stages; // Which stages to hook on
enum pl_hook_sig input; // Which input signature this hook expects
void *priv; // Arbitrary user context
// Custom tunable shader parameters exported by this hook. These may be
// updated at any time by the user, to influence the behavior of the hook.
// Contents are arbitrary and subject to the method of hook construction.
const struct pl_hook_par *parameters;
int num_parameters;
// Called at the beginning of passes, to reset/initialize the hook. (Optional)
void (*reset)(void *priv);
// The hook function itself. Called by the renderer at any of the indicated
// hook stages. See `pl_hook_res` for more info on the return values.
struct pl_hook_res (*hook)(void *priv, const struct pl_hook_params *params);
// Unique signature identifying this hook, used to disable misbehaving hooks.
// All hooks with the same signature will be disabled, should they fail to
// execute during run-time.
uint64_t signature;
};
// Compatibility layer with `mpv` user shaders. See the mpv man page for more
// information on the format. Will return `NULL` if the shader fails parsing.
//
// The resulting `pl_hook` objects should be destroyed with the corresponding
// destructor when no longer needed.
PL_API const struct pl_hook *
pl_mpv_user_shader_parse(pl_gpu gpu, const char *shader_text, size_t shader_len);
PL_API void pl_mpv_user_shader_destroy(const struct pl_hook **hook);
PL_API_END
#endif // LIBPLACEBO_SHADERS_CUSTOM_H_

View File

@ -0,0 +1,137 @@
/*
* This file is part of libplacebo, which is normally licensed under the terms
* of the LGPL v2.1+. However, this file (film_grain.h) is also available under
* the terms of the more permissive MIT license:
*
* Copyright (c) 2018-2019 Niklas Haas
*
* 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 LIBPLACEBO_SHADERS_DEINTERLACING_H_
#define LIBPLACEBO_SHADERS_DEINTERLACING_H_
#include <libplacebo/shaders.h>
PL_API_BEGIN
enum pl_field {
PL_FIELD_NONE = 0, // no deinterlacing
PL_FIELD_EVEN, // "top" fields, with even y coordinates
PL_FIELD_ODD, // "bottom" fields, with odd y coordinates
// Convenience aliases
PL_FIELD_TOP = PL_FIELD_EVEN,
PL_FIELD_BOTTOM = PL_FIELD_ODD,
};
static inline enum pl_field pl_field_other(enum pl_field field)
{
switch (field) {
case PL_FIELD_EVEN: return PL_FIELD_ODD;
case PL_FIELD_ODD: return PL_FIELD_EVEN;
default: return field;
}
}
struct pl_field_pair {
// Top texture. If only this is specified, it's assumed to contain both
// fields in an interleaved fashion (MBAFF).
//
// Note: Support for separate fields (PAFF), is currently pending, so this
// is the only way to provide interlaced frames at the moment.
pl_tex top;
};
#define pl_field_pair(...) ((struct pl_field_pair) { __VA_ARGS__ })
struct pl_deinterlace_source {
// Previous, current and next source (interlaced) frames. `prev` and `next`
// may be NULL, but `cur` is required. If present, they must all have the
// exact same texture dimensions.
//
// Note: `prev` and `next` are only required for PL_DEINTERLACE_YADIF.
struct pl_field_pair prev, cur, next;
// The parity of the current field to output. This field will be unmodified
// from `cur`, with the corresponding other field interpolated.
//
// If this is `PL_FIELD_NONE`, no deinterlacing is performed, and the
// texture is merely sampled as-is.
enum pl_field field;
// The parity of the first frame in a stream. Set this the field that is
// (conceptually) ordered first in time.
//
// If this is `PL_FIELD_NONE`, it will instead default to `PL_FIELD_TOP`.
enum pl_field first_field;
// Components to deinterlace. Components not specified will be ignored.
// Optional, if left as 0, all components will be deinterlaced.
uint8_t component_mask;
};
#define pl_deinterlace_source(...) (&(struct pl_deinterlace_source) { __VA_ARGS__ })
enum pl_deinterlace_algorithm {
// No-op deinterlacing, just sample the weaved frame un-touched.
PL_DEINTERLACE_WEAVE = 0,
// Naive bob deinterlacing. Doubles the field lines vertically.
PL_DEINTERLACE_BOB,
// "Yet another deinterlacing filter". Deinterlacer with temporal and
// spatial information. Based on FFmpeg's Yadif filter algorithm, but
// adapted slightly for the GPU.
PL_DEINTERLACE_YADIF,
PL_DEINTERLACE_ALGORITHM_COUNT,
};
// Returns whether or not an algorithm requires `prev`/`next` refs to be set.
static inline bool pl_deinterlace_needs_refs(enum pl_deinterlace_algorithm algo)
{
return algo == PL_DEINTERLACE_YADIF;
}
struct pl_deinterlace_params {
// Algorithm to use. The recommended default is PL_DEINTERLACE_YADIF, which
// provides a good trade-off of quality and speed.
enum pl_deinterlace_algorithm algo;
// Skip the spatial interlacing check. (PL_DEINTERLACE_YADIF only)
bool skip_spatial_check;
};
#define PL_DEINTERLACE_DEFAULTS \
.algo = PL_DEINTERLACE_YADIF,
#define pl_deinterlace_params(...) (&(struct pl_deinterlace_params) { PL_DEINTERLACE_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_deinterlace_params pl_deinterlace_default_params;
// Deinterlaces a set of interleaved source frames and outputs the result into
// `vec4 color`. If `params` is left as NULL, it defaults to
// `&pl_deinterlace_default_params`.
PL_API void pl_shader_deinterlace(pl_shader sh, const struct pl_deinterlace_source *src,
const struct pl_deinterlace_params *params);
PL_API_END
#endif // LIBPLACEBO_SHADERS_DEINTERLACING_H_

View File

@ -0,0 +1,140 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_DITHERING_H_
#define LIBPLACEBO_SHADERS_DITHERING_H_
// Dithering shaders
#include <libplacebo/colorspace.h>
#include <libplacebo/dither.h>
#include <libplacebo/shaders.h>
PL_API_BEGIN
enum pl_dither_method {
// Dither with blue noise. Very high quality, but requires the use of a
// LUT. Warning: Computing a blue noise texture with a large size can be
// very slow, however this only needs to be performed once. Even so, using
// this with a `lut_size` greater than 6 is generally ill-advised. This is
// the preferred/default dither method.
PL_DITHER_BLUE_NOISE,
// Dither with an ordered (bayer) dither matrix, using a LUT. Low quality,
// and since this also uses a LUT, there's generally no advantage to picking
// this instead of `PL_DITHER_BLUE_NOISE`. It's mainly there for testing.
PL_DITHER_ORDERED_LUT,
// The same as `PL_DITHER_ORDERED_LUT`, but uses fixed function math instead
// of a LUT. This is faster, but only supports a fixed dither matrix size
// of 16x16 (equal to a `lut_size` of 4).
PL_DITHER_ORDERED_FIXED,
// Dither with white noise. This does not require a LUT and is fairly cheap
// to compute. Unlike the other modes it doesn't show any repeating
// patterns either spatially or temporally, but the downside is that this
// is visually fairly jarring due to the presence of low frequencies in the
// noise spectrum.
PL_DITHER_WHITE_NOISE,
PL_DITHER_METHOD_COUNT,
};
struct pl_dither_params {
// The source of the dither noise to use.
enum pl_dither_method method;
// For the dither methods which require the use of a LUT, this controls
// the size of the LUT (base 2). If left as NULL, this defaults to 6, which
// is equivalent to a 64x64 dither matrix. Must not be larger than 8.
int lut_size;
// Enables temporal dithering. This reduces the persistence of dithering
// artifacts by perturbing the dithering matrix per frame.
// Warning: This can cause nasty aliasing artifacts on some LCD screens.
bool temporal;
// Gamma function to use for dither gamma correction. This will only have
// an effect when dithering to low bit depths (<= 4).
enum pl_color_transfer transfer;
};
#define PL_DITHER_DEFAULTS \
.method = PL_DITHER_BLUE_NOISE, \
.lut_size = 6, \
/* temporal dithering commonly flickers on LCDs */ \
.temporal = false,
#define pl_dither_params(...) (&(struct pl_dither_params) { PL_DITHER_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_dither_params pl_dither_default_params;
// Dither the colors to a lower depth, given in bits. This can be used on input
// colors of any precision. Basically, this rounds the colors to only linear
// multiples of the stated bit depth. The average intensity of the result
// will not change (i.e., the dither noise is balanced in both directions).
// If `params` is NULL, it defaults to &pl_dither_default_params.
//
// For the dither methods which require the use of a LUT, `dither_state` must
// be set to a valid pointer. To avoid thrashing the resource, users should
// avoid trying to re-use the same LUT for different dither configurations. If
// passed as NULL, libplacebo will automatically fall back to dither algorithms
// that don't require the use of a LUT.
//
// Warning: This dithering algorithm is not gamma-invariant; so using it for
// very low bit depths (below 4 or so) will noticeably increase the brightness
// of the resulting image. When doing low bit depth dithering for aesthetic
// purposes, it's recommended that the user explicitly (de)linearize the colors
// before and after this algorithm.
PL_API void pl_shader_dither(pl_shader sh, int new_depth,
pl_shader_obj *dither_state,
const struct pl_dither_params *params);
struct pl_error_diffusion_params {
// Both the input and output texture must be provided up-front, with the
// same size. The output texture must be storable, and the input texture
// must be sampleable.
pl_tex input_tex;
pl_tex output_tex;
// Depth to dither to. Required.
int new_depth;
// Error diffusion kernel to use. Optional. If unspecified, defaults to
// `&pl_error_diffusion_sierra_lite`.
const struct pl_error_diffusion_kernel *kernel;
};
#define pl_error_diffusion_params(...) (&(struct pl_error_diffusion_params) { __VA_ARGS__ })
// Computes the shared memory requirements for a given error diffusion kernel.
// This can be used to test up-front whether or not error diffusion would be
// supported or not, before having to initialize textures.
PL_API size_t pl_error_diffusion_shmem_req(const struct pl_error_diffusion_kernel *kernel,
int height);
// Apply an error diffusion dithering kernel. This is a much more expensive and
// heavy dithering method, and is not generally recommended for realtime usage
// where performance is critical.
//
// Requires compute shader support. Returns false if dithering fail e.g. as a
// result of shader memory limits being exceeded. The resulting shader must be
// dispatched with a work group count of exactly 1.
PL_API bool pl_shader_error_diffusion(pl_shader sh, const struct pl_error_diffusion_params *params);
PL_API_END
#endif // LIBPLACEBO_SHADERS_DITHERING_H_

View File

@ -0,0 +1,137 @@
/*
* This file is part of libplacebo, which is normally licensed under the terms
* of the LGPL v2.1+. However, this file (film_grain.h) is also available under
* the terms of the more permissive MIT license:
*
* Copyright (c) 2018-2019 Niklas Haas
*
* 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 LIBPLACEBO_SHADERS_FILM_GRAIN_H_
#define LIBPLACEBO_SHADERS_FILM_GRAIN_H_
// Film grain synthesis shaders for AV1 / H.274.
#include <stdint.h>
#include <stdbool.h>
#include <libplacebo/colorspace.h>
#include <libplacebo/shaders.h>
PL_API_BEGIN
enum pl_film_grain_type {
PL_FILM_GRAIN_NONE = 0,
PL_FILM_GRAIN_AV1,
PL_FILM_GRAIN_H274,
PL_FILM_GRAIN_COUNT,
};
// AV1 film grain parameters. For the exact meaning of these, see the AV1
// specification (section 6.8.20).
struct pl_av1_grain_data {
int num_points_y;
uint8_t points_y[14][2]; // [n][0] = value, [n][1] = scaling
bool chroma_scaling_from_luma;
int num_points_uv[2]; // should be {0} for grayscale images
uint8_t points_uv[2][10][2]; // like points_y for points_uv[0, 1] = u, v
int scaling_shift;
int ar_coeff_lag;
int8_t ar_coeffs_y[24];
int8_t ar_coeffs_uv[2][25];
int ar_coeff_shift;
int grain_scale_shift;
int8_t uv_mult[2];
int8_t uv_mult_luma[2];
int16_t uv_offset[2]; // 9-bit value, range [-256, 255]
bool overlap;
};
// H.274 film grain parameters. For the exact meaning of these, see the H.274
// specification (section 8.5).
struct pl_h274_grain_data {
int model_id;
int blending_mode_id;
int log2_scale_factor;
bool component_model_present[3];
uint16_t num_intensity_intervals[3];
uint8_t num_model_values[3];
const uint8_t *intensity_interval_lower_bound[3];
const uint8_t *intensity_interval_upper_bound[3];
const int16_t (*comp_model_value[3])[6];
};
// Tagged union for film grain data
struct pl_film_grain_data {
enum pl_film_grain_type type; // film grain type
uint64_t seed; // shared seed value
union {
// Warning: These values are not sanity-checked at all, Invalid grain
// data results in undefined behavior!
struct pl_av1_grain_data av1;
struct pl_h274_grain_data h274;
} params;
};
// Options for the `pl_shader_film_grain` call.
struct pl_film_grain_params {
// Required for all film grain types:
struct pl_film_grain_data data; // film grain data
pl_tex tex; // texture to sample from
struct pl_color_repr *repr; // underlying color representation (see notes)
int components;
int component_mapping[4]; // same as `struct pl_plane`
// Notes for `repr`:
// - repr->bits affects the rounding for grain generation
// - repr->levels affects whether or not we clip to full range or not
// - repr->sys affects the interpretation of channels
// - *repr gets normalized by this shader, which is why it's a pointer
// Required for PL_FILM_GRAIN_AV1 only:
pl_tex luma_tex; // "luma" texture (see notes)
int luma_comp; // index of luma in `luma_tex`
// Notes for `luma_tex`:
// - `luma_tex` must be specified if the `tex` does not itself contain the
// "luma-like" component. For XYZ systems, the Y channel is the luma
// component. For RGB systems, the G channel is.
};
#define pl_film_grain_params(...) (&(struct pl_film_grain_params) { __VA_ARGS__ })
// Test if film grain needs to be applied. This is a helper function that users
// can use to decide whether or not `pl_shader_film_grain` needs to be called,
// based on the given grain metadata.
PL_API bool pl_needs_film_grain(const struct pl_film_grain_params *params);
// Sample from a texture while applying film grain at the same time.
// `grain_state` must be unique for every plane configuration, as it may
// contain plane-dependent state.
//
// Returns false on any error, or if film grain generation is not supported
// due to GLSL limitations.
PL_API bool pl_shader_film_grain(pl_shader sh, pl_shader_obj *grain_state,
const struct pl_film_grain_params *params);
PL_API_END
#endif // LIBPLACEBO_SHADERS_FILM_GRAIN_H_

View File

@ -0,0 +1,135 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_ICC_H_
#define LIBPLACEBO_SHADERS_ICC_H_
// Functions for generating and applying ICC-derived (3D)LUTs
#include <libplacebo/colorspace.h>
#include <libplacebo/shaders.h>
PL_API_BEGIN
struct pl_icc_params {
// The rendering intent to use, for profiles with multiple intents. A
// recommended value is PL_INTENT_RELATIVE_COLORIMETRIC for color-accurate
// video reproduction, or PL_INTENT_PERCEPTUAL for profiles containing
// meaningful perceptual mapping tables for some more suitable color space
// like BT.709.
//
// If this is set to the special value PL_INTENT_AUTO, will use the
// preferred intent provided by the profile header.
enum pl_rendering_intent intent;
// The size of the 3DLUT to generate. If left as NULL, these individually
// default to values appropriate for the profile. (Based on internal
// precision heuristics)
//
// Note: Setting this manually is strongly discouraged, as it can result
// in excessively high 3DLUT sizes where a much smaller LUT would have
// sufficed.
int size_r, size_g, size_b;
// This field can be used to override the detected brightness level of the
// ICC profile. If you set this to the special value 0 (or a negative
// number), libplacebo will attempt reading the brightness value from the
// ICC profile's tagging (if available), falling back to PL_COLOR_SDR_WHITE
// if unavailable.
float max_luma;
// Force black point compensation. May help avoid crushed or raised black
// points on "improper" profiles containing e.g. colorimetric tables that
// do not round-trip. Should not be required on well-behaved profiles,
// or when using PL_INTENT_PERCEPTUAL, but YMMV.
bool force_bpc;
// If provided, this pl_cache instance will be used, instead of the
// GPU-internal cache, to cache the generated 3DLUTs. Note that these can
// get large, especially for large values of size_{r,g,b}, so the user may
// wish to split this cache off from the main shader cache. (Optional)
pl_cache cache;
// Deprecated legacy caching API. Replaced by `cache`.
PL_DEPRECATED void *cache_priv;
PL_DEPRECATED void (*cache_save)(void *priv, uint64_t sig, const uint8_t *cache, size_t size);
PL_DEPRECATED bool (*cache_load)(void *priv, uint64_t sig, uint8_t *cache, size_t size);
};
#define PL_ICC_DEFAULTS \
.intent = PL_INTENT_RELATIVE_COLORIMETRIC, \
.max_luma = PL_COLOR_SDR_WHITE,
#define pl_icc_params(...) (&(struct pl_icc_params) { PL_ICC_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_icc_params pl_icc_default_params;
// This object represents a "parsed" ICC profile.
typedef const struct pl_icc_object_t {
// Provided params, with the `intent` and `size` fields set (as described)
struct pl_icc_params params;
// Signature of the corresponding ICC profile.
uint64_t signature;
// Detected color space (or UNKNOWN for profiles which don't contain an
// exact match), with HDR metedata set to the detected gamut and
// white/black value ranges.
struct pl_color_space csp;
// Best estimate of profile gamma. This only serves as a rough guideline.
float gamma;
// Smallest containing primary set, always set.
enum pl_color_primaries containing_primaries;
} *pl_icc_object;
// Attempts opening/parsing the contents of an ICC profile. The resulting
// object is memory managed and may outlive the original profile - access
// to the underlying profile is no longer needed once this returns.
PL_API pl_icc_object pl_icc_open(pl_log log, const struct pl_icc_profile *profile,
const struct pl_icc_params *params);
PL_API void pl_icc_close(pl_icc_object *icc);
// Update an existing pl_icc_object, which may be NULL, replacing it by the
// new profile and parameters (if incompatible).
//
// Returns success. `obj` is set to the created profile, or NULL on error.
//
// Note: If `profile->signature` matches `(*obj)->signature`, or if `profile` is
// NULL, then the existing profile is directly reused, with only the effective
// parameters changing. In this case, `profile->data` is also *not* read from,
// and may safely be NULL.
PL_API bool pl_icc_update(pl_log log, pl_icc_object *obj,
const struct pl_icc_profile *profile,
const struct pl_icc_params *params);
// Decode the input from the colorspace determined by the attached ICC profile
// to linear light RGB (in the profile's containing primary set). `lut` must be
// set to a shader object that will store the GPU resources associated with the
// generated LUT. The resulting color space will be written to `out_csp`.
PL_API void pl_icc_decode(pl_shader sh, pl_icc_object profile, pl_shader_obj *lut,
struct pl_color_space *out_csp);
// Encode the input from linear light RGB (in the profile's containing primary
// set) into the colorspace determined by the attached ICC profile. `lut` must
// be set to a shader object that will store the GPU resources associated with
// the generated LUT.
PL_API void pl_icc_encode(pl_shader sh, pl_icc_object profile, pl_shader_obj *lut);
PL_API_END
#endif // LIBPLACEBO_SHADERS_ICC_H_

View File

@ -0,0 +1,78 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_LUT_H_
#define LIBPLACEBO_SHADERS_LUT_H_
// Shaders for loading and applying arbitrary custom 1D/3DLUTs
#include <libplacebo/colorspace.h>
#include <libplacebo/shaders.h>
PL_API_BEGIN
// Struct defining custom LUTs
//
// Note: Users may freely create their own instances of this struct, there is
// nothing particularly special about `pl_lut_parse_cube`.
struct pl_custom_lut {
// Some unique signature identifying this LUT, needed to detect state
// changes (for cache invalidation). This should ideally be a hash of the
// file contents. (Which is what `pl_lut_parse_*` will set it to.)
uint64_t signature;
// Size of each dimension, in the order R, G, B. For 1D LUTs, only the R
// dimension should be specified (the others left as 0).
int size[3];
// Raw LUT data itself, in properly scaled floating point format. For 3D
// LUTs, the innermost dimension is the first dimension (R), and the
// outermost dimension is the last dimension (B). Individual color samples
// are in the order R, G, B.
const float *data;
// Extra input/output shaper matrices. Ignored if equal to {0}. This is
// mostly useful for 1D LUTs, since 3D LUTs can bake the shaper matrix into
// the LUT itself - but it can still help optimize LUT precision.
pl_matrix3x3 shaper_in, shaper_out;
// Nominal metadata for the input/output of a LUT. Left as {0} if unknown.
// Note: This is purely informative, `pl_shader_custom_lut` ignores it.
struct pl_color_repr repr_in, repr_out;
struct pl_color_space color_in, color_out;
};
// Parse a 3DLUT in .cube format. Returns NULL if the file fails parsing.
PL_API struct pl_custom_lut *pl_lut_parse_cube(pl_log log, const char *str, size_t str_len);
// Frees a LUT created by `pl_lut_parse_*`.
PL_API void pl_lut_free(struct pl_custom_lut **lut);
// Apply a `pl_custom_lut`. The user is responsible for ensuring colors going
// into the LUT are in the expected format as informed by the LUT metadata.
//
// `lut_state` must be a pointer to a NULL-initialized shader state object that
// will be used to encapsulate any required GPU state.
//
// Note: `lut` does not have to be allocated by `pl_lut_parse_*`. It can be a
// struct filled out by the user.
PL_API void pl_shader_custom_lut(pl_shader sh, const struct pl_custom_lut *lut,
pl_shader_obj *lut_state);
PL_API_END
#endif // LIBPLACEBO_SHADERS_LUT_H_

View File

@ -0,0 +1,257 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SHADERS_SAMPLING_H_
#define LIBPLACEBO_SHADERS_SAMPLING_H_
// Sampling operations. These shaders perform some form of sampling operation
// from a given pl_tex. In order to use these, the pl_shader *must* have been
// created using the same `gpu` as the originating `pl_tex`. Otherwise, this
// is undefined behavior. They require nothing (PL_SHADER_SIG_NONE) and return
// a color (PL_SHADER_SIG_COLOR).
#include <libplacebo/colorspace.h>
#include <libplacebo/filters.h>
#include <libplacebo/shaders.h>
PL_API_BEGIN
// Common parameters for sampling operations
struct pl_sample_src {
// There are two mutually exclusive ways of providing the source to sample
// from:
//
// 1. Provide the texture and sampled region directly. This generates
// a shader with input signature `PL_SHADER_SIG_NONE`, which binds the
// texture as a descriptor (and the coordinates as a vertex attribute)
pl_tex tex; // texture to sample
pl_rect2df rect; // sub-rect to sample from (optional)
enum pl_tex_address_mode address_mode; // preferred texture address mode
// 2. Have the shader take it as an argument. Doing this requires
// specifying the missing metadata of the texture backing the sampler, so
// that the shader generation can generate the correct code.
int tex_w, tex_h; // dimensions of the actual texture
enum pl_fmt_type format; // format of the sampler being accepted
enum pl_sampler_type sampler; // type of the sampler being accepted
enum pl_tex_sample_mode mode; // sample mode of the sampler being accepted
float sampled_w, sampled_h; // dimensions of the sampled region (optional)
// Common metadata for both sampler input types:
int components; // number of components to sample (optional)
uint8_t component_mask; // bitmask of components to sample (optional)
int new_w, new_h; // dimensions of the resulting output (optional)
float scale; // factor to multiply into sampled signal (optional)
// Note: `component_mask` and `components` are mutually exclusive, the
// former is preferred if both are specified.
};
#define pl_sample_src(...) (&(struct pl_sample_src) { __VA_ARGS__ })
struct pl_deband_params {
// The number of debanding steps to perform per sample. Each step reduces a
// bit more banding, but takes time to compute. Note that the strength of
// each step falls off very quickly, so high numbers (>4) are practically
// useless. Defaults to 1.
int iterations;
// The debanding filter's cut-off threshold. Higher numbers increase the
// debanding strength dramatically, but progressively diminish image
// details. Defaults to 3.0.
float threshold;
// The debanding filter's initial radius. The radius increases linearly
// for each iteration. A higher radius will find more gradients, but a
// lower radius will smooth more aggressively. Defaults to 16.0.
float radius;
// Add some extra noise to the image. This significantly helps cover up
// remaining quantization artifacts. Higher numbers add more noise.
// Note: When debanding HDR sources, even a small amount of grain can
// result in a very big change to the brightness level. It's recommended to
// either scale this value down or disable it entirely for HDR.
//
// Defaults to 4.0, which is very mild.
float grain;
// 'Neutral' grain value for each channel being debanded (sorted in order
// from low to high index). Grain application will be modulated to avoid
// disturbing colors close to this value. Set this to a value corresponding
// to black in the relevant colorspace.
float grain_neutral[3];
};
#define PL_DEBAND_DEFAULTS \
.iterations = 1, \
.threshold = 3.0, \
.radius = 16.0, \
.grain = 4.0,
#define pl_deband_params(...) (&(struct pl_deband_params) {PL_DEBAND_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_deband_params pl_deband_default_params;
// Debands a given texture and returns the sampled color in `vec4 color`. If
// `params` is left as NULL, it defaults to &pl_deband_default_params. Note
// that `tex->params.format` must have PL_FMT_CAP_LINEAR. When the given
// `pl_sample_src` implies scaling, this effectively performs bilinear
// sampling on the input (but not the output).
//
// Note: This can also be used as a pure grain function, by setting the number
// of iterations to 0.
PL_API void pl_shader_deband(pl_shader sh, const struct pl_sample_src *src,
const struct pl_deband_params *params);
// Performs direct / native texture sampling, using whatever texture filter is
// available (linear for linearly sampleable sources, nearest otherwise).
//
// Note: This is generally very low quality and should be avoided if possible,
// for both upscaling and downscaling.
PL_API bool pl_shader_sample_direct(pl_shader sh, const struct pl_sample_src *src);
// Performs hardware-accelerated nearest neighbour sampling. This is similar to
// `pl_shader_sample_direct`, but forces nearest neighbour interpolation.
PL_API bool pl_shader_sample_nearest(pl_shader sh, const struct pl_sample_src *src);
// Performs hardware-accelerated bilinear sampling. This is similar to
// `pl_shader_sample_direct`, but forces bilinear interpolation.
PL_API bool pl_shader_sample_bilinear(pl_shader sh, const struct pl_sample_src *src);
// Optimized versions of specific, strictly positive scaler kernels that take
// adantage of linear texture sampling to reduce the number of fetches needed
// by a factor of four. This family of functions performs radius-2 scaling
// with only four texture fetches, which is far more efficient than using
// the generalized 1D scaling method. Only works well for upscaling.
PL_API bool pl_shader_sample_bicubic(pl_shader sh, const struct pl_sample_src *src);
PL_API bool pl_shader_sample_hermite(pl_shader sh, const struct pl_sample_src *src);
PL_API bool pl_shader_sample_gaussian(pl_shader sh, const struct pl_sample_src *src);
// A sampler that is similar to nearest neighbour sampling, but tries to
// preserve pixel aspect ratios. This is mathematically equivalent to taking an
// idealized image with square pixels, sampling it at an infinite resolution,
// and then downscaling that to the desired resolution. (Hence it being called
// "oversample"). Good for pixel art.
//
// The threshold provides a cutoff threshold below which the contribution of
// pixels should be ignored, trading some amount of aspect ratio distortion for
// a slightly crisper image. A value of `threshold == 0.5` makes this filter
// equivalent to regular nearest neighbour sampling.
PL_API bool pl_shader_sample_oversample(pl_shader sh, const struct pl_sample_src *src,
float threshold);
struct pl_sample_filter_params {
// The filter to use for sampling.
struct pl_filter_config filter;
// Antiringing strength. A value of 0.0 disables antiringing, and a value
// of 1.0 enables full-strength antiringing. Defaults to 0.0 if
// unspecified.
//
// Note: Ignored if `filter.antiring` is already set to something nonzero.
float antiring;
// Disable the use of compute shaders (e.g. if rendering to non-storable tex)
bool no_compute;
// Disable the use of filter widening / anti-aliasing (for downscaling)
bool no_widening;
// This shader object is used to store the LUT, and will be recreated
// if necessary. To avoid thrashing the resource, users should avoid trying
// to re-use the same LUT for different filter configurations or scaling
// ratios. Must be set to a valid pointer, and the target NULL-initialized.
pl_shader_obj *lut;
// Deprecated / removed fields
int lut_entries PL_DEPRECATED; // hard-coded as 256
float cutoff PL_DEPRECATED; // hard-coded as 1e-3
};
#define pl_sample_filter_params(...) (&(struct pl_sample_filter_params) { __VA_ARGS__ })
// Performs polar sampling. This internally chooses between an optimized compute
// shader, and various fragment shaders, depending on the supported GLSL version
// and GPU features. Returns whether or not it was successful.
//
// Note: `params->filter.polar` must be true to use this function.
PL_API bool pl_shader_sample_polar(pl_shader sh, const struct pl_sample_src *src,
const struct pl_sample_filter_params *params);
// Performs orthogonal (1D) sampling. Using this twice in a row (once vertical
// and once horizontal) effectively performs a 2D upscale. This is lower
// quality than polar sampling, but significantly faster, and therefore the
// recommended default. Returns whether or not it was successful.
//
// `src` must represent a scaling operation that only scales in one direction,
// i.e. either only X or only Y. The other direction must be left unscaled.
//
// Note: Due to internal limitations, this may currently only be used on 2D
// textures - even though the basic principle would work for 1D and 3D textures
// as well.
PL_API bool pl_shader_sample_ortho2(pl_shader sh, const struct pl_sample_src *src,
const struct pl_sample_filter_params *params);
struct pl_distort_params {
// An arbitrary 2x2 affine transformation to apply to the input image.
// For simplicity, the input image is explicitly centered and scaled such
// that the longer dimension is in [-1,1], before applying this.
pl_transform2x2 transform;
// If true, the texture is placed inside the center of the canvas without
// scaling. If false, it is effectively stretched to the canvas size.
bool unscaled;
// If true, the transformation is automatically scaled down and shifted to
// ensure that the resulting image fits inside the output canvas.
bool constrain;
// If true, use bicubic interpolation rather than faster bilinear
// interpolation. Higher quality but slower.
bool bicubic;
// Specifies the texture address mode to use when sampling out of bounds.
enum pl_tex_address_mode address_mode;
// If set, all out-of-bounds accesses will instead be treated as
// transparent, according to the given alpha mode. (Which should match the
// alpha mode of the texture)
//
// Note: `address_mode` has no effect when this is specified.
enum pl_alpha_mode alpha_mode;
};
#define PL_DISTORT_DEFAULTS \
.transform.mat.m = {{ 1, 0 }, {0, 1}},
#define pl_distort_params(...) (&(struct pl_distort_params) {PL_DISTORT_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_distort_params pl_distort_default_params;
// Distorts the input image using a given set of transformation parameters.
// `out_w` and `out_h` determine the size of the effective canvas inside which
// the distorted result may be rendered. Areas outside of this canvas will
// be implicitly cut off.
PL_API void pl_shader_distort(pl_shader sh, pl_tex tex, int out_w, int out_h,
const struct pl_distort_params *params);
enum PL_DEPRECATED { // for `int pass`
PL_SEP_VERT = 0,
PL_SEP_HORIZ,
PL_SEP_PASSES
};
PL_API_END
#endif // LIBPLACEBO_SHADERS_SAMPLING_H_

View File

@ -0,0 +1,171 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_SWAPCHAIN_H_
#define LIBPLACEBO_SWAPCHAIN_H_
#include <libplacebo/common.h>
#include <libplacebo/colorspace.h>
#include <libplacebo/gpu.h>
PL_API_BEGIN
// This abstraction represents a low-level interface to visible surfaces
// exposed by a graphics API (and accompanying GPU instance), allowing users to
// directly present frames to the screen (or window, typically). This is a
// sister API to gpu.h and follows the same convention w.r.t undefined behavior.
//
// Thread-safety: Safe
typedef const struct pl_swapchain_t {
pl_log log;
pl_gpu gpu;
} *pl_swapchain;
// Destroys this swapchain. May be used at any time, and may block until the
// completion of all outstanding rendering commands. The swapchain and any
// resources retrieved from it must not be used afterwards.
PL_API void pl_swapchain_destroy(pl_swapchain *sw);
// Returns the approximate current swapchain latency in vsyncs, or 0 if
// unknown. A latency of 1 means that `submit_frame` followed by `swap_buffers`
// will block until the just-submitted frame has finished rendering. Typical
// values are 2 or 3, which enable better pipelining by allowing the GPU to be
// processing one or two frames at the same time as the user is preparing the
// next for submission.
PL_API int pl_swapchain_latency(pl_swapchain sw);
// Update/query the swapchain size. This function performs both roles: it tries
// setting the swapchain size to the values requested by the user, and returns
// in the same variables what width/height the swapchain was actually set to -
// which may be (substantially) different from the values requested by the
// user. A value of 0 means "unknown/none" (in which case, libplacebo won't try
// updating the size - it will simply return the current state of the
// swapchain). It's also possible for libplacebo to return values of 0, such as
// in the case that the swapchain doesn't exist yet.
//
// Returns false on significant errors (e.g. dead surface). This function can
// effectively be used to probe if creating a swapchain works.
PL_API bool pl_swapchain_resize(pl_swapchain sw, int *width, int *height);
// Backwards compatibility
#define pl_swapchain_colors pl_color_space
// Inform the swapchain about the input color space. This API deliberately
// provides no feedback, because the swapchain can internally decide what to do
// with this information, including ignoring it entirely, or applying it
// asynchronously. Users must still base their rendering on the value of
// `pl_swapchain_frame.color_space`.
//
// Note: Calling this function a second time completely overrides any
// previously specified hint. So calling this on {0} or NULL resets the
// swapchain back to its initial/preferred colorspace.
//
// Note: If `csp->transfer` is a HDR transfer curve but HDR metadata is left
// unspecified, the HDR metadata defaults to `pl_hdr_metadata_hdr10`.
// Conversely, if the HDR metadata is non-empty but `csp->transfer` is left as
// PL_COLOR_TRC_UNKNOWN, then it instead defaults to PL_COLOR_TRC_PQ.
PL_API void pl_swapchain_colorspace_hint(pl_swapchain sw, const struct pl_color_space *csp);
// The struct used to hold the results of `pl_swapchain_start_frame`
struct pl_swapchain_frame {
// A texture representing the framebuffer users should use for rendering.
// It's guaranteed that `fbo->params.renderable` and `fbo->params.blit_dst`
// will be true, but no other guarantees are made - not even that
// `fbo->params.format` is a real format.
pl_tex fbo;
// If true, the user should assume that this framebuffer will be flipped
// as a result of presenting it on-screen. If false, nothing special needs
// to be done - but if true, users should flip the coordinate system of
// the `pl_pass` that is rendering to this framebuffer.
//
// Note: Normally, libplacebo follows the convention that (0,0) represents
// the top left of the image/screen. So when flipped is true, this means
// (0,0) on this framebuffer gets displayed as the bottom left of the image.
bool flipped;
// Indicates the color representation this framebuffer will be interpreted
// as by the host system / compositor / display, including the bit depth
// and alpha handling (where available).
struct pl_color_repr color_repr;
struct pl_color_space color_space;
};
// Retrieve a new frame from the swapchain. Returns whether successful. It's
// worth noting that this function can fail sporadically for benign reasons,
// for example the window being invisible or inaccessible. This function may
// block until an image is available, which may be the case if the GPU is
// rendering frames significantly faster than the display can output them. It
// may also be non-blocking, so users shouldn't rely on this call alone in
// order to meter rendering speed. (Specifics depend on the underlying graphics
// API)
PL_API bool pl_swapchain_start_frame(pl_swapchain sw, struct pl_swapchain_frame *out_frame);
// Submits the previously started frame. Non-blocking. This must be issued in
// lockstep with pl_swapchain_start_frame - there is no way to start multiple
// frames and submit them out-of-order. The frames submitted this way will
// generally be made visible in a first-in first-out fashion, although
// specifics depend on the mechanism used to create the pl_swapchain. (See the
// platform-specific APIs for more info).
//
// Returns whether successful. This should normally never fail, unless the
// GPU/surface has been lost or some other critical error has occurred. The
// "started" frame is consumed even in the event of failure.
//
// Note that `start_frame` and `submit_frame` form a lock pair, i.e. trying to
// call e.g. `pl_swapchain_resize` from another thread will block until
// `pl_swapchain_submit_frame` is finished.
PL_API bool pl_swapchain_submit_frame(pl_swapchain sw);
// Performs a "buffer swap", or some generalization of the concept. In layman's
// terms, this blocks until the execution of the Nth previously submitted frame
// has been "made complete" in some sense. (The N derives from the swapchain's
// built-in latency. See `pl_swapchain_latency` for more information).
//
// Users should include this call in their rendering loops in order to make
// sure they aren't submitting rendering commands faster than the GPU can
// process them, which would potentially lead to a queue overrun or exhaust
// memory.
//
// An example loop might look like this:
//
// while (rendering) {
// struct pl_swapchain_frame frame;
// bool ok = pl_swapchain_start_frame(swapchain, &frame);
// if (!ok) {
// /* wait some time, or decide to stop rendering */
// continue;
// }
//
// /* do some rendering with frame.fbo */
//
// ok = pl_swapchain_submit_frame(swapchain);
// if (!ok)
// break;
//
// pl_swapchain_swap_buffers(swapchain);
// }
//
// The duration this function blocks for, if at all, may be very inconsistent
// and should not be used as an authoritative source of vsync timing
// information without sufficient smoothing/filtering (and if so, the time that
// `start_frame` blocked for should also be included).
PL_API void pl_swapchain_swap_buffers(pl_swapchain sw);
PL_API_END
#endif // LIBPLACEBO_SWAPCHAIN_H_

View File

@ -0,0 +1,268 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_TONE_MAPPING_H_
#define LIBPLACEBO_TONE_MAPPING_H_
#include <stddef.h>
#include <stdbool.h>
#include <libplacebo/common.h>
#include <libplacebo/colorspace.h>
PL_API_BEGIN
struct pl_tone_map_params;
struct pl_tone_map_function {
const char *name; // Identifier
const char *description; // Friendly / longer name
// This controls the type of values input/output to/from `map`
enum pl_hdr_scaling scaling;
// The tone-mapping function itself. Iterates over all values in `lut`, and
// adapts them as needed.
//
// Note that the `params` struct fed into this function is guaranteed to
// satisfy `params->input_scaling == params->output_scaling == scaling`,
// and also obeys `params->input_max >= params->output_max`.
void (*map)(float *lut, const struct pl_tone_map_params *params);
// Inverse tone mapping function. Optional. If absent, this tone mapping
// curve only works in the forwards direction.
//
// For this function, `params->input_max <= params->output_max`.
void (*map_inverse)(float *lut, const struct pl_tone_map_params *params);
// Private data. Unused by libplacebo, but may be accessed by `map`.
void *priv;
// --- Deprecated fields
const char *param_desc PL_DEPRECATED;
float param_min PL_DEPRECATED;
float param_def PL_DEPRECATED;
float param_max PL_DEPRECATED;
};
struct pl_tone_map_constants {
// Configures the knee point, as a ratio between the source average and
// target average (in PQ space). An adaptation of 1.0 always adapts the
// source scene average brightness to the (scaled) target average,
// while a value of 0.0 never modifies scene brightness. [0,1]
//
// Affects all methods that use the ST2094 knee point determination
// (currently ST2094-40, ST2094-10 and spline)
float knee_adaptation;
// Configures the knee point minimum and maximum, respectively, as
// a percentage of the PQ luminance range. Provides a hard limit on the
// knee point chosen by `knee_adaptation`.
float knee_minimum; // (0, 0.5)
float knee_maximum; // (0.5, 1.0)
// Default knee point to use in the absence of source scene average
// metadata. Normally, this is ignored in favor of picking the knee
// point as the (relative) source scene average brightness level.
float knee_default; // [knee_minimum, knee_maximum]
// Knee point offset (for BT.2390 only). Note that a value of 0.5 is
// the spec-defined default behavior, which differs from the libplacebo
// default of 1.0. [0.5, 2]
float knee_offset;
// For the single-pivot polynomial (spline) function, this controls the
// coefficients used to tune the slope of the curve. This tuning is designed
// to make the slope closer to 1.0 when the difference in peaks is low,
// and closer to linear when the difference between peaks is high.
float slope_tuning; // [0,10]
float slope_offset; // [0,1]
// Contrast setting for the spline function. Higher values make the curve
// steeper (closer to `clip`), preserving midtones at the cost of losing
// shadow/highlight details, while lower values make the curve shallowed
// (closer to `linear`), preserving highlights at the cost of losing midtone
// contrast. Values above 1.0 are possible, resulting in an output with more
// contrast than the input.
float spline_contrast; // [0,1.5]
// For the reinhard function, this specifies the local contrast coefficient
// at the display peak. Essentially, a value of 0.5 implies that the
// reference white will be about half as bright as when clipping. (0,1)
float reinhard_contrast;
// For legacy functions (mobius, gamma) which operate on linear light, this
// directly sets the corresponding knee point. (0,1)
float linear_knee;
// For linear methods (linear, linearlight), this controls the linear
// exposure/gain applied to the image. (0,10]
float exposure;
};
#define PL_TONE_MAP_CONSTANTS \
.knee_adaptation = 0.4f, \
.knee_minimum = 0.1f, \
.knee_maximum = 0.8f, \
.knee_default = 0.4f, \
.knee_offset = 1.0f, \
.slope_tuning = 1.5f, \
.slope_offset = 0.2f, \
.spline_contrast = 0.5f, \
.reinhard_contrast = 0.5f, \
.linear_knee = 0.3f, \
.exposure = 1.0f,
struct pl_tone_map_params {
// If `function` is NULL, defaults to `pl_tone_map_clip`.
const struct pl_tone_map_function *function;
// Common constants, should be initialized to PL_TONE_MAP_CONSTANTS if
// not intending to override them further.
struct pl_tone_map_constants constants;
// The desired input/output scaling of the tone map. If this differs from
// `function->scaling`, any required conversion will be performed.
//
// Note that to maximize LUT efficiency, it's *highly* recommended to use
// either PL_HDR_PQ or PL_HDR_SQRT as the input scaling, except when
// using `pl_tone_map_sample`.
enum pl_hdr_scaling input_scaling;
enum pl_hdr_scaling output_scaling;
// The size of the resulting LUT. (For `pl_tone_map_generate` only)
size_t lut_size;
// The characteristics of the input, in `input_scaling` units.
float input_min;
float input_max;
float input_avg; // or 0 if unknown
// The desired characteristics of the output, in `output_scaling` units.
float output_min;
float output_max;
// The input HDR metadata. Only used by a select few tone-mapping
// functions, currently only SMPTE ST2094. (Optional)
struct pl_hdr_metadata hdr;
// --- Deprecated fields
float param PL_DEPRECATED; // see `constants`
};
#define pl_tone_map_params(...) (&(struct pl_tone_map_params) { __VA_ARGS__ });
// Note: Only does pointer equality testing on `function`
PL_API bool pl_tone_map_params_equal(const struct pl_tone_map_params *a,
const struct pl_tone_map_params *b);
// Clamps/defaults the parameters, including input/output maximum.
PL_API void pl_tone_map_params_infer(struct pl_tone_map_params *params);
// Returns true if the given tone mapping configuration effectively represents
// a no-op configuration. Tone mapping can be skipped in this case (although
// strictly speaking, the LUT would still clip illegal input values)
PL_API bool pl_tone_map_params_noop(const struct pl_tone_map_params *params);
// Generate a tone-mapping LUT for a given configuration. This will always
// span the entire input range, as given by `input_min` and `input_max`.
PL_API void pl_tone_map_generate(float *out, const struct pl_tone_map_params *params);
// Samples a tone mapping function at a single position. Note that this is less
// efficient than `pl_tone_map_generate` for generating multiple values.
//
// Ignores `params->lut_size`.
PL_API float pl_tone_map_sample(float x, const struct pl_tone_map_params *params);
// Performs no tone-mapping, just clips out-of-range colors. Retains perfect
// color accuracy for in-range colors but completely destroys out-of-range
// information. Does not perform any black point adaptation.
PL_API extern const struct pl_tone_map_function pl_tone_map_clip;
// EETF from SMPTE ST 2094-40 Annex B, which uses the provided OOTF based on
// Bezier curves to perform tone-mapping. The OOTF used is adjusted based on
// the ratio between the targeted and actual display peak luminances. In the
// absence of HDR10+ metadata, falls back to a simple constant bezier curve.
PL_API extern const struct pl_tone_map_function pl_tone_map_st2094_40;
// EETF from SMPTE ST 2094-10 Annex B.2, which takes into account the input
// signal average luminance in addition to the maximum/minimum.
//
// Note: This does *not* currently include the subjective gain/offset/gamma
// controls defined in Annex B.3. (Open an issue with a valid sample file if
// you want such parameters to be respected.)
PL_API extern const struct pl_tone_map_function pl_tone_map_st2094_10;
// EETF from the ITU-R Report BT.2390, a hermite spline roll-off with linear
// segment.
PL_API extern const struct pl_tone_map_function pl_tone_map_bt2390;
// EETF from ITU-R Report BT.2446, method A. Can be used for both forward
// and inverse tone mapping.
PL_API extern const struct pl_tone_map_function pl_tone_map_bt2446a;
// Simple spline consisting of two polynomials, joined by a single pivot point,
// which is tuned based on the source scene average brightness (taking into
// account dynamic metadata if available). This function can be used
// for both forward and inverse tone mapping.
PL_API extern const struct pl_tone_map_function pl_tone_map_spline;
// Very simple non-linear curve. Named after Erik Reinhard.
PL_API extern const struct pl_tone_map_function pl_tone_map_reinhard;
// Generalization of the reinhard tone mapping algorithm to support an
// additional linear slope near black. The name is derived from its function
// shape (ax+b)/(cx+d), which is known as a Möbius transformation.
PL_API extern const struct pl_tone_map_function pl_tone_map_mobius;
// Piece-wise, filmic tone-mapping algorithm developed by John Hable for use in
// Uncharted 2, inspired by a similar tone-mapping algorithm used by Kodak.
// Popularized by its use in video games with HDR rendering. Preserves both
// dark and bright details very well, but comes with the drawback of changing
// the average brightness quite significantly. This is sort of similar to
// pl_tone_map_reinhard with `reinhard_contrast=0.24`.
PL_API extern const struct pl_tone_map_function pl_tone_map_hable;
// Fits a gamma (power) function to transfer between the source and target
// color spaces, effectively resulting in a perceptual hard-knee joining two
// roughly linear sections. This preserves details at all scales, but can result
// in an image with a muted or dull appearance.
PL_API extern const struct pl_tone_map_function pl_tone_map_gamma;
// Linearly stretches the input range to the output range, in PQ space. This
// will preserve all details accurately, but results in a significantly
// different average brightness. Can be used for inverse tone-mapping in
// addition to regular tone-mapping.
PL_API extern const struct pl_tone_map_function pl_tone_map_linear;
// Like `pl_tone_map_linear`, but in linear light (instead of PQ). Works well
// for small range adjustments but may cause severe darkening when
// downconverting from e.g. 10k nits to SDR.
PL_API extern const struct pl_tone_map_function pl_tone_map_linear_light;
// A list of built-in tone mapping functions, terminated by NULL
PL_API extern const struct pl_tone_map_function * const pl_tone_map_functions[];
PL_API extern const int pl_num_tone_map_functions; // excluding trailing NULL
// Find the tone mapping function with the given name, or NULL on failure.
PL_API const struct pl_tone_map_function *pl_find_tone_map_function(const char *name);
// Deprecated alias, do not use
#define pl_tone_map_auto pl_tone_map_spline
PL_API_END
#endif // LIBPLACEBO_TONE_MAPPING_H_

View File

@ -0,0 +1,129 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_DAV1D_H_
#define LIBPLACEBO_DAV1D_H_
#include <libplacebo/gpu.h>
#include <libplacebo/utils/upload.h>
#include <dav1d/dav1d.h>
#if defined(__cplusplus) && !defined(PL_DAV1D_IMPLEMENTATION)
# define PL_DAV1D_API
# define PL_DAV1D_IMPLEMENTATION 0
# warning Remember to include this file with a PL_DAV1D_IMPLEMENTATION set to 1 in \
C translation unit to provide implementation. Suppress this warning by \
defining PL_DAV1D_IMPLEMENTATION to 0 in C++ files.
#elif !defined(PL_DAV1D_IMPLEMENTATION)
# define PL_DAV1D_API static inline
# define PL_DAV1D_IMPLEMENTATION 1
#else
# define PL_DAV1D_API
#endif
PL_API_BEGIN
// Fill in the details of a `pl_frame` from a Dav1dPicture. This function will
// explicitly clear `out_frame`, setting all extra fields to 0. After this
// function returns, the only missing data is information related to the plane
// texture itself (`planes[N].texture`).
//
// Note: This will include all possible metadata, including HDR metadata and
// AV1 film grain data. Users should explicitly clear this out if undesired.
PL_DAV1D_API void pl_frame_from_dav1dpicture(struct pl_frame *out_frame,
const Dav1dPicture *picture);
// Helper function to generate a `pl_color_space` struct from a Dav1dPicture.
// Useful to update the swapchain colorspace mode dynamically (e.g. for HDR).
PL_DAV1D_API void pl_swapchain_colors_from_dav1dpicture(struct pl_color_space *out_colors,
const Dav1dPicture *picture);
struct pl_dav1d_upload_params {
// The picture to upload. Not modified unless `asynchronous` is true.
Dav1dPicture *picture;
// If true, film grain present in `picture` will be exported to the
// `pl_frame` as well. This should be set to false unless the user has
// disabled `Dav1dSettings.apply_grain`.
bool film_grain;
// If true, libplacebo will probe for the allocation metadata set by
// `pl_allocate_dav1dpicture`, and directly import the attached buffers
// (saving a memcpy in some cases). Has no effect if the Dav1dPicture was
// not allocated using `pl_allocate_dav1dpicture`.
//
// Note: When this is the case, `asynchronous` has no further effect -
// uploads from attached buffers are already asynchronous.
bool gpu_allocated;
// If true, `picture` will be asynchronously uploaded and unref'd
// internally by libplacebo, and the struct passed by the user cleared to
// {0}. This is needed to avoid `memcpy` in some cases, so setting it to
// true is highly recommended wherever possible.
//
// Note: If `pl_upload_dav1dpicture` returns false, `picture` does not get
// unref'd.
bool asynchronous;
};
#define pl_dav1d_upload_params(...) (&(struct pl_dav1d_upload_params) { __VA_ARGS__ })
// Very high level helper function to take a `Dav1dPicture` and upload it to
// the GPU. Similar in spirit to `pl_upload_plane`, and the same notes apply.
// `tex` must be an array of 3 pointers of type `pl_tex`, each
// either pointing to a valid texture, or NULL. Returns whether successful.
PL_DAV1D_API bool pl_upload_dav1dpicture(pl_gpu gpu,
struct pl_frame *out_frame, pl_tex tex[3],
const struct pl_dav1d_upload_params *params);
// Allocate a Dav1dPicture from persistently mapped buffers. This can be more
// efficient than regular Dav1dPictures, especially when using the synchronous
// `pl_upload_dav1dpicture`, or on platforms that don't support importing
// PL_HANDLE_HOST_PTR as buffers. Returns 0 or a negative DAV1D_ERR value.
//
// Note: These may only be used directly as a Dav1dPicAllocator if the `gpu`
// passed as the value of `cookie` is `pl_gpu.limits.thread_safe`. Otherwise,
// the user must manually synchronize this to ensure it runs on the correct
// thread.
PL_DAV1D_API int pl_allocate_dav1dpicture(Dav1dPicture *picture, void *gpu);
PL_DAV1D_API void pl_release_dav1dpicture(Dav1dPicture *picture, void *gpu);
// Mapping functions for the various Dav1dColor* enums. Note that these are not
// quite 1:1, and even for values that exist in both, the semantics sometimes
// differ. Some special cases (e.g. ICtCp, or XYZ) are handled differently in
// libplacebo and libdav1d, respectively.
PL_DAV1D_API enum pl_color_system pl_system_from_dav1d(enum Dav1dMatrixCoefficients mc);
PL_DAV1D_API enum Dav1dMatrixCoefficients pl_system_to_dav1d(enum pl_color_system sys);
PL_DAV1D_API enum pl_color_levels pl_levels_from_dav1d(int color_range);
PL_DAV1D_API int pl_levels_to_dav1d(enum pl_color_levels levels);
PL_DAV1D_API enum pl_color_primaries pl_primaries_from_dav1d(enum Dav1dColorPrimaries prim);
PL_DAV1D_API enum Dav1dColorPrimaries pl_primaries_to_dav1d(enum pl_color_primaries prim);
PL_DAV1D_API enum pl_color_transfer pl_transfer_from_dav1d(enum Dav1dTransferCharacteristics trc);
PL_DAV1D_API enum Dav1dTransferCharacteristics pl_transfer_to_dav1d(enum pl_color_transfer trc);
PL_DAV1D_API enum pl_chroma_location pl_chroma_from_dav1d(enum Dav1dChromaSamplePosition loc);
PL_DAV1D_API enum Dav1dChromaSamplePosition pl_chroma_to_dav1d(enum pl_chroma_location loc);
// Actual implementation, included as part of this header to avoid having
// a compile-time dependency on libdav1d.
#if PL_DAV1D_IMPLEMENTATION
# include <libplacebo/utils/dav1d_internal.h>
#endif
PL_API_END
#endif // LIBPLACEBO_DAV1D_H_

View File

@ -0,0 +1,613 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_DAV1D_H_
#error This header should be included as part of <libplacebo/utils/dav1d.h>
#elif defined(__cplusplus)
#error This header cannot be included from C++ define PL_DAV1D_IMPLEMENTATION appropriately
#else
#include <assert.h>
#include <stdlib.h>
#include <string.h>
PL_DAV1D_API enum pl_color_system pl_system_from_dav1d(enum Dav1dMatrixCoefficients mc)
{
switch (mc) {
case DAV1D_MC_IDENTITY: return PL_COLOR_SYSTEM_RGB; // or XYZ (unlikely)
case DAV1D_MC_BT709: return PL_COLOR_SYSTEM_BT_709;
case DAV1D_MC_UNKNOWN: return PL_COLOR_SYSTEM_UNKNOWN;
case DAV1D_MC_FCC: return PL_COLOR_SYSTEM_UNKNOWN; // missing
case DAV1D_MC_BT470BG: return PL_COLOR_SYSTEM_BT_601;
case DAV1D_MC_BT601: return PL_COLOR_SYSTEM_BT_601;
case DAV1D_MC_SMPTE240: return PL_COLOR_SYSTEM_SMPTE_240M;
case DAV1D_MC_SMPTE_YCGCO: return PL_COLOR_SYSTEM_YCGCO;
case DAV1D_MC_BT2020_NCL: return PL_COLOR_SYSTEM_BT_2020_NC;
case DAV1D_MC_BT2020_CL: return PL_COLOR_SYSTEM_BT_2020_C;
case DAV1D_MC_SMPTE2085: return PL_COLOR_SYSTEM_UNKNOWN; // missing
case DAV1D_MC_CHROMAT_NCL: return PL_COLOR_SYSTEM_UNKNOWN; // missing
case DAV1D_MC_CHROMAT_CL: return PL_COLOR_SYSTEM_UNKNOWN; // missing
// Note: this colorspace is confused between PQ and HLG, which dav1d
// requires inferring from other sources, but libplacebo makes
// explicit. Default to PQ as it's the more common scenario.
case DAV1D_MC_ICTCP: return PL_COLOR_SYSTEM_BT_2100_PQ;
case DAV1D_MC_RESERVED: abort();
}
return PL_COLOR_SYSTEM_UNKNOWN;
}
PL_DAV1D_API enum Dav1dMatrixCoefficients pl_system_to_dav1d(enum pl_color_system sys)
{
switch (sys) {
case PL_COLOR_SYSTEM_UNKNOWN: return DAV1D_MC_UNKNOWN;
case PL_COLOR_SYSTEM_BT_601: return DAV1D_MC_BT601;
case PL_COLOR_SYSTEM_BT_709: return DAV1D_MC_BT709;
case PL_COLOR_SYSTEM_SMPTE_240M: return DAV1D_MC_SMPTE240;
case PL_COLOR_SYSTEM_BT_2020_NC: return DAV1D_MC_BT2020_NCL;
case PL_COLOR_SYSTEM_BT_2020_C: return DAV1D_MC_BT2020_CL;
case PL_COLOR_SYSTEM_BT_2100_PQ: return DAV1D_MC_ICTCP;
case PL_COLOR_SYSTEM_BT_2100_HLG: return DAV1D_MC_ICTCP;
case PL_COLOR_SYSTEM_DOLBYVISION: return DAV1D_MC_UNKNOWN; // missing
case PL_COLOR_SYSTEM_YCGCO: return DAV1D_MC_SMPTE_YCGCO;
case PL_COLOR_SYSTEM_RGB: return DAV1D_MC_IDENTITY;
case PL_COLOR_SYSTEM_XYZ: return DAV1D_MC_IDENTITY;
case PL_COLOR_SYSTEM_COUNT: abort();
}
return DAV1D_MC_UNKNOWN;
}
PL_DAV1D_API enum pl_color_levels pl_levels_from_dav1d(int color_range)
{
return color_range ? PL_COLOR_LEVELS_FULL : PL_COLOR_LEVELS_LIMITED;
}
PL_DAV1D_API int pl_levels_to_dav1d(enum pl_color_levels levels)
{
return levels == PL_COLOR_LEVELS_FULL;
}
PL_DAV1D_API enum pl_color_primaries pl_primaries_from_dav1d(enum Dav1dColorPrimaries prim)
{
switch (prim) {
case DAV1D_COLOR_PRI_BT709: return PL_COLOR_PRIM_BT_709;
case DAV1D_COLOR_PRI_UNKNOWN: return PL_COLOR_PRIM_UNKNOWN;
case DAV1D_COLOR_PRI_RESERVED: return PL_COLOR_PRIM_UNKNOWN;
case DAV1D_COLOR_PRI_BT470M: return PL_COLOR_PRIM_BT_470M;
case DAV1D_COLOR_PRI_BT470BG: return PL_COLOR_PRIM_BT_601_625;
case DAV1D_COLOR_PRI_BT601: return PL_COLOR_PRIM_BT_601_525;
case DAV1D_COLOR_PRI_SMPTE240: return PL_COLOR_PRIM_BT_601_525;
case DAV1D_COLOR_PRI_FILM: return PL_COLOR_PRIM_FILM_C;
case DAV1D_COLOR_PRI_BT2020: return PL_COLOR_PRIM_BT_2020;
case DAV1D_COLOR_PRI_XYZ: return PL_COLOR_PRIM_UNKNOWN;
case DAV1D_COLOR_PRI_SMPTE431: return PL_COLOR_PRIM_DCI_P3;
case DAV1D_COLOR_PRI_SMPTE432: return PL_COLOR_PRIM_DISPLAY_P3;
case DAV1D_COLOR_PRI_EBU3213: return PL_COLOR_PRIM_EBU_3213;
}
return PL_COLOR_PRIM_UNKNOWN;
}
PL_DAV1D_API enum Dav1dColorPrimaries pl_primaries_to_dav1d(enum pl_color_primaries prim)
{
switch (prim) {
case PL_COLOR_PRIM_UNKNOWN: return DAV1D_COLOR_PRI_UNKNOWN;
case PL_COLOR_PRIM_BT_601_525: return DAV1D_COLOR_PRI_BT601;
case PL_COLOR_PRIM_BT_601_625: return DAV1D_COLOR_PRI_BT470BG;
case PL_COLOR_PRIM_BT_709: return DAV1D_COLOR_PRI_BT709;
case PL_COLOR_PRIM_BT_470M: return DAV1D_COLOR_PRI_BT470M;
case PL_COLOR_PRIM_EBU_3213: return DAV1D_COLOR_PRI_EBU3213;
case PL_COLOR_PRIM_BT_2020: return DAV1D_COLOR_PRI_BT2020;
case PL_COLOR_PRIM_APPLE: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_ADOBE: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_PRO_PHOTO: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_CIE_1931: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_DCI_P3: return DAV1D_COLOR_PRI_SMPTE431;
case PL_COLOR_PRIM_DISPLAY_P3: return DAV1D_COLOR_PRI_SMPTE432;
case PL_COLOR_PRIM_V_GAMUT: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_S_GAMUT: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_FILM_C: return DAV1D_COLOR_PRI_FILM;
case PL_COLOR_PRIM_ACES_AP0: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_ACES_AP1: return DAV1D_COLOR_PRI_UNKNOWN; // missing
case PL_COLOR_PRIM_COUNT: abort();
}
return DAV1D_COLOR_PRI_UNKNOWN;
}
PL_DAV1D_API enum pl_color_transfer pl_transfer_from_dav1d(enum Dav1dTransferCharacteristics trc)
{
switch (trc) {
case DAV1D_TRC_BT709: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
case DAV1D_TRC_UNKNOWN: return PL_COLOR_TRC_UNKNOWN;
case DAV1D_TRC_BT470M: return PL_COLOR_TRC_GAMMA22;
case DAV1D_TRC_BT470BG: return PL_COLOR_TRC_GAMMA28;
case DAV1D_TRC_BT601: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
case DAV1D_TRC_SMPTE240: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
case DAV1D_TRC_LINEAR: return PL_COLOR_TRC_LINEAR;
case DAV1D_TRC_LOG100: return PL_COLOR_TRC_UNKNOWN; // missing
case DAV1D_TRC_LOG100_SQRT10: return PL_COLOR_TRC_UNKNOWN; // missing
case DAV1D_TRC_IEC61966: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
case DAV1D_TRC_BT1361: return PL_COLOR_TRC_BT_1886; // ETOF != OETF
case DAV1D_TRC_SRGB: return PL_COLOR_TRC_SRGB;
case DAV1D_TRC_BT2020_10BIT: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
case DAV1D_TRC_BT2020_12BIT: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
case DAV1D_TRC_SMPTE2084: return PL_COLOR_TRC_PQ;
case DAV1D_TRC_SMPTE428: return PL_COLOR_TRC_ST428;
case DAV1D_TRC_HLG: return PL_COLOR_TRC_HLG;
case DAV1D_TRC_RESERVED: abort();
}
return PL_COLOR_TRC_UNKNOWN;
}
PL_DAV1D_API enum Dav1dTransferCharacteristics pl_transfer_to_dav1d(enum pl_color_transfer trc)
{
switch (trc) {
case PL_COLOR_TRC_UNKNOWN: return DAV1D_TRC_UNKNOWN;
case PL_COLOR_TRC_BT_1886: return DAV1D_TRC_BT709; // EOTF != OETF
case PL_COLOR_TRC_SRGB: return DAV1D_TRC_SRGB;
case PL_COLOR_TRC_LINEAR: return DAV1D_TRC_LINEAR;
case PL_COLOR_TRC_GAMMA18: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_GAMMA20: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_GAMMA22: return DAV1D_TRC_BT470M;
case PL_COLOR_TRC_GAMMA24: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_GAMMA26: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_GAMMA28: return DAV1D_TRC_BT470BG;
case PL_COLOR_TRC_ST428: return DAV1D_TRC_SMPTE428;
case PL_COLOR_TRC_PRO_PHOTO: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_PQ: return DAV1D_TRC_SMPTE2084;
case PL_COLOR_TRC_HLG: return DAV1D_TRC_HLG;
case PL_COLOR_TRC_V_LOG: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_S_LOG1: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_S_LOG2: return DAV1D_TRC_UNKNOWN; // missing
case PL_COLOR_TRC_COUNT: abort();
}
return DAV1D_TRC_UNKNOWN;
}
PL_DAV1D_API enum pl_chroma_location pl_chroma_from_dav1d(enum Dav1dChromaSamplePosition loc)
{
switch (loc) {
case DAV1D_CHR_UNKNOWN: return PL_CHROMA_UNKNOWN;
case DAV1D_CHR_VERTICAL: return PL_CHROMA_LEFT;
case DAV1D_CHR_COLOCATED: return PL_CHROMA_TOP_LEFT;
}
return PL_CHROMA_UNKNOWN;
}
PL_DAV1D_API enum Dav1dChromaSamplePosition pl_chroma_to_dav1d(enum pl_chroma_location loc)
{
switch (loc) {
case PL_CHROMA_UNKNOWN: return DAV1D_CHR_UNKNOWN;
case PL_CHROMA_LEFT: return DAV1D_CHR_VERTICAL;
case PL_CHROMA_CENTER: return DAV1D_CHR_UNKNOWN; // missing
case PL_CHROMA_TOP_LEFT: return DAV1D_CHR_COLOCATED;
case PL_CHROMA_TOP_CENTER: return DAV1D_CHR_UNKNOWN; // missing
case PL_CHROMA_BOTTOM_LEFT: return DAV1D_CHR_UNKNOWN; // missing
case PL_CHROMA_BOTTOM_CENTER: return DAV1D_CHR_UNKNOWN; // missing
case PL_CHROMA_COUNT: abort();
}
return DAV1D_CHR_UNKNOWN;
}
static inline float pl_fixed24_8(uint32_t n)
{
return (float) n / (1 << 8);
}
static inline float pl_fixed18_14(uint32_t n)
{
return (float) n / (1 << 14);
}
static inline float pl_fixed0_16(uint16_t n)
{
return (float) n / (1 << 16);
}
// Align to a power of 2
#define PL_ALIGN2(x, align) (((x) + (align) - 1) & ~((align) - 1))
PL_DAV1D_API void pl_frame_from_dav1dpicture(struct pl_frame *out,
const Dav1dPicture *picture)
{
const Dav1dSequenceHeader *seq_hdr = picture->seq_hdr;
int num_planes;
switch (picture->p.layout) {
case DAV1D_PIXEL_LAYOUT_I400:
num_planes = 1;
break;
case DAV1D_PIXEL_LAYOUT_I420:
case DAV1D_PIXEL_LAYOUT_I422:
case DAV1D_PIXEL_LAYOUT_I444:
num_planes = 3;
break;
default: abort();
}
*out = (struct pl_frame) {
.num_planes = num_planes,
.planes = {
// Components are always in order, which makes things easy
{
.components = 1,
.component_mapping = {0},
}, {
.components = 1,
.component_mapping = {1},
}, {
.components = 1,
.component_mapping = {2},
},
},
.crop = {
0, 0, picture->p.w, picture->p.h,
},
.color = {
.primaries = pl_primaries_from_dav1d(seq_hdr->pri),
.transfer = pl_transfer_from_dav1d(seq_hdr->trc),
},
.repr = {
.sys = pl_system_from_dav1d(seq_hdr->mtrx),
.levels = pl_levels_from_dav1d(seq_hdr->color_range),
.bits = {
.sample_depth = PL_ALIGN2(picture->p.bpc, 8),
.color_depth = picture->p.bpc,
},
},
};
if (seq_hdr->mtrx == DAV1D_MC_ICTCP && seq_hdr->trc == DAV1D_TRC_HLG) {
// dav1d makes no distinction between PQ and HLG ICtCp, so we need
// to manually fix it in the case that we have HLG ICtCp data.
out->repr.sys = PL_COLOR_SYSTEM_BT_2100_HLG;
} else if (seq_hdr->mtrx == DAV1D_MC_IDENTITY &&
seq_hdr->pri == DAV1D_COLOR_PRI_XYZ)
{
// dav1d handles this as a special case, but doesn't provide an
// explicit flag for it either, so we have to resort to this ugly hack,
// even though CIE 1931 RGB *is* a valid thing in principle!
out->repr.sys= PL_COLOR_SYSTEM_XYZ;
} else if (!out->repr.sys) {
// PL_COLOR_SYSTEM_UNKNOWN maps to RGB, so hard-code this one
out->repr.sys = pl_color_system_guess_ycbcr(picture->p.w, picture->p.h);
}
const Dav1dContentLightLevel *cll = picture->content_light;
if (cll) {
out->color.hdr.max_cll = cll->max_content_light_level;
out->color.hdr.max_fall = cll->max_frame_average_light_level;
}
// This overrides the CLL values above, if both are present
const Dav1dMasteringDisplay *md = picture->mastering_display;
if (md) {
out->color.hdr.max_luma = pl_fixed24_8(md->max_luminance);
out->color.hdr.min_luma = pl_fixed18_14(md->min_luminance);
out->color.hdr.prim = (struct pl_raw_primaries) {
.red.x = pl_fixed0_16(md->primaries[0][0]),
.red.y = pl_fixed0_16(md->primaries[0][1]),
.green.x = pl_fixed0_16(md->primaries[1][0]),
.green.y = pl_fixed0_16(md->primaries[1][1]),
.blue.x = pl_fixed0_16(md->primaries[2][0]),
.blue.y = pl_fixed0_16(md->primaries[2][1]),
.white.x = pl_fixed0_16(md->white_point[0]),
.white.y = pl_fixed0_16(md->white_point[1]),
};
}
if (picture->frame_hdr->film_grain.present) {
const Dav1dFilmGrainData *fg = &picture->frame_hdr->film_grain.data;
out->film_grain = (struct pl_film_grain_data) {
.type = PL_FILM_GRAIN_AV1,
.seed = fg->seed,
.params.av1 = {
.num_points_y = fg->num_y_points,
.chroma_scaling_from_luma = fg->chroma_scaling_from_luma,
.num_points_uv = { fg->num_uv_points[0], fg->num_uv_points[1] },
.scaling_shift = fg->scaling_shift,
.ar_coeff_lag = fg->ar_coeff_lag,
.ar_coeff_shift = (int) fg->ar_coeff_shift,
.grain_scale_shift = fg->grain_scale_shift,
.uv_mult = { fg->uv_mult[0], fg->uv_mult[1] },
.uv_mult_luma = { fg->uv_luma_mult[0], fg->uv_luma_mult[1] },
.uv_offset = { fg->uv_offset[0], fg->uv_offset[1] },
.overlap = fg->overlap_flag,
},
};
struct pl_av1_grain_data *av1 = &out->film_grain.params.av1;
memcpy(av1->points_y, fg->y_points, sizeof(av1->points_y));
memcpy(av1->points_uv, fg->uv_points, sizeof(av1->points_uv));
memcpy(av1->ar_coeffs_y, fg->ar_coeffs_y, sizeof(av1->ar_coeffs_y));
memcpy(av1->ar_coeffs_uv[0], fg->ar_coeffs_uv[0], sizeof(av1->ar_coeffs_uv[0]));
memcpy(av1->ar_coeffs_uv[1], fg->ar_coeffs_uv[1], sizeof(av1->ar_coeffs_uv[1]));
}
switch (picture->p.layout) {
case DAV1D_PIXEL_LAYOUT_I400:
case DAV1D_PIXEL_LAYOUT_I444:
break;
case DAV1D_PIXEL_LAYOUT_I420:
case DAV1D_PIXEL_LAYOUT_I422:
// Only set the chroma location for definitely subsampled images
pl_frame_set_chroma_location(out, pl_chroma_from_dav1d(seq_hdr->chr));
break;
}
}
PL_DAV1D_API void pl_swapchain_colors_from_dav1dpicture(struct pl_swapchain_colors *out_colors,
const Dav1dPicture *picture)
{
struct pl_frame frame;
pl_frame_from_dav1dpicture(&frame, picture);
*out_colors = (struct pl_swapchain_colors) {
.primaries = frame.color.primaries,
.transfer = frame.color.transfer,
};
const Dav1dContentLightLevel *cll = picture->content_light;
if (cll) {
out_colors->hdr.max_cll = cll->max_content_light_level;
out_colors->hdr.max_fall = cll->max_frame_average_light_level;
}
const Dav1dMasteringDisplay *md = picture->mastering_display;
if (md) {
out_colors->hdr.min_luma = pl_fixed18_14(md->min_luminance);
out_colors->hdr.max_luma = pl_fixed24_8(md->max_luminance);
out_colors->hdr.prim.red.x = pl_fixed0_16(md->primaries[0][0]);
out_colors->hdr.prim.red.y = pl_fixed0_16(md->primaries[0][1]);
out_colors->hdr.prim.green.x = pl_fixed0_16(md->primaries[1][0]);
out_colors->hdr.prim.green.y = pl_fixed0_16(md->primaries[1][1]);
out_colors->hdr.prim.blue.x = pl_fixed0_16(md->primaries[2][0]);
out_colors->hdr.prim.blue.y = pl_fixed0_16(md->primaries[2][1]);
out_colors->hdr.prim.white.x = pl_fixed0_16(md->white_point[0]);
out_colors->hdr.prim.white.y = pl_fixed0_16(md->white_point[1]);
}
}
#define PL_MAGIC0 0x2c2a1269
#define PL_MAGIC1 0xc6d02577
struct pl_dav1dalloc {
uint32_t magic[2];
pl_gpu gpu;
pl_buf buf;
};
struct pl_dav1dref {
Dav1dPicture pic;
uint8_t count;
};
static void pl_dav1dpicture_unref(void *priv)
{
struct pl_dav1dref *ref = priv;
if (--ref->count == 0) {
dav1d_picture_unref(&ref->pic);
free(ref);
}
}
PL_DAV1D_API bool pl_upload_dav1dpicture(pl_gpu gpu,
struct pl_frame *out,
pl_tex tex[3],
const struct pl_dav1d_upload_params *params)
{
Dav1dPicture *pic = params->picture;
pl_frame_from_dav1dpicture(out, pic);
if (!params->film_grain)
out->film_grain.type = PL_FILM_GRAIN_NONE;
const int bytes = (pic->p.bpc + 7) / 8; // rounded up
int sub_x = 0, sub_y = 0;
switch (pic->p.layout) {
case DAV1D_PIXEL_LAYOUT_I400:
case DAV1D_PIXEL_LAYOUT_I444:
break;
case DAV1D_PIXEL_LAYOUT_I420:
sub_x = sub_y = 1;
break;
case DAV1D_PIXEL_LAYOUT_I422:
sub_x = 1;
break;
}
struct pl_plane_data data[3] = {
{
// Y plane
.type = PL_FMT_UNORM,
.width = pic->p.w,
.height = pic->p.h,
.pixel_stride = bytes,
.component_size = {bytes * 8},
.component_map = {0},
}, {
// U plane
.type = PL_FMT_UNORM,
.width = pic->p.w >> sub_x,
.height = pic->p.h >> sub_y,
.pixel_stride = bytes,
.component_size = {bytes * 8},
.component_map = {1},
}, {
// V plane
.type = PL_FMT_UNORM,
.width = pic->p.w >> sub_x,
.height = pic->p.h >> sub_y,
.pixel_stride = bytes,
.component_size = {bytes * 8},
.component_map = {2},
},
};
pl_buf buf = NULL;
struct pl_dav1dalloc *alloc = params->gpu_allocated ? pic->allocator_data : NULL;
struct pl_dav1dref *ref = NULL;
if (alloc && alloc->magic[0] == PL_MAGIC0 && alloc->magic[1] == PL_MAGIC1) {
// Re-use pre-allocated buffers directly
assert(alloc->gpu == gpu);
buf = alloc->buf;
} else if (params->asynchronous && gpu->limits.callbacks) {
ref = malloc(sizeof(*ref));
if (!ref)
return false;
memcpy(&ref->pic, pic, sizeof(Dav1dPicture));
ref->count = out->num_planes;
}
for (int p = 0; p < out->num_planes; p++) {
ptrdiff_t stride = p > 0 ? pic->stride[1] : pic->stride[0];
if (stride < 0) {
data[p].pixels = (uint8_t *) pic->data[p] + stride * (data[p].height - 1);
data[p].row_stride = -stride;
out->planes[p].flipped = true;
} else {
data[p].pixels = pic->data[p];
data[p].row_stride = stride;
}
if (buf) {
data[p].buf = buf;
data[p].buf_offset = (uintptr_t) data[p].pixels - (uintptr_t) buf->data;
data[p].pixels = NULL;
} else if (ref) {
data[p].priv = ref;
data[p].callback = pl_dav1dpicture_unref;
}
if (!pl_upload_plane(gpu, &out->planes[p], &tex[p], &data[p])) {
free(ref);
return false;
}
}
if (params->asynchronous) {
if (ref) {
*pic = (Dav1dPicture) {0};
} else {
dav1d_picture_unref(pic);
}
}
return true;
}
PL_DAV1D_API int pl_allocate_dav1dpicture(Dav1dPicture *p, void *cookie)
{
pl_gpu gpu = cookie;
if (!gpu->limits.max_mapped_size || !gpu->limits.host_cached ||
!gpu->limits.buf_transfer)
{
return DAV1D_ERR(ENOTSUP);
}
// Copied from dav1d_default_picture_alloc
const int hbd = p->p.bpc > 8;
const int aligned_w = PL_ALIGN2(p->p.w, 128);
const int aligned_h = PL_ALIGN2(p->p.h, 128);
const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
p->stride[0] = aligned_w << hbd;
p->stride[1] = has_chroma ? (aligned_w >> ss_hor) << hbd : 0;
// Align strides up to multiples of the GPU performance hints
p->stride[0] = PL_ALIGN2(p->stride[0], gpu->limits.align_tex_xfer_pitch);
p->stride[1] = PL_ALIGN2(p->stride[1], gpu->limits.align_tex_xfer_pitch);
// Aligning offsets to 4 also implicitly aligns to the texel alignment (1 or 2)
size_t off_align = PL_ALIGN2(gpu->limits.align_tex_xfer_offset, 4);
const size_t y_sz = PL_ALIGN2(p->stride[0] * aligned_h, off_align);
const size_t uv_sz = PL_ALIGN2(p->stride[1] * (aligned_h >> ss_ver), off_align);
// The extra DAV1D_PICTURE_ALIGNMENTs are to brute force plane alignment,
// even in the case that the driver gives us insane alignments
const size_t pic_size = y_sz + 2 * uv_sz;
const size_t total_size = pic_size + DAV1D_PICTURE_ALIGNMENT * 4;
// Validate size limitations
if (total_size > gpu->limits.max_mapped_size)
return DAV1D_ERR(ENOMEM);
pl_buf buf = pl_buf_create(gpu, pl_buf_params(
.size = total_size,
.host_mapped = true,
.memory_type = PL_BUF_MEM_HOST,
));
if (!buf)
return DAV1D_ERR(ENOMEM);
struct pl_dav1dalloc *alloc = malloc(sizeof(struct pl_dav1dalloc));
if (!alloc) {
pl_buf_destroy(gpu, &buf);
return DAV1D_ERR(ENOMEM);
}
*alloc = (struct pl_dav1dalloc) {
.magic = { PL_MAGIC0, PL_MAGIC1 },
.gpu = gpu,
.buf = buf,
};
assert(buf->data);
uintptr_t base = (uintptr_t) buf->data, data[3];
data[0] = PL_ALIGN2(base, DAV1D_PICTURE_ALIGNMENT);
data[1] = PL_ALIGN2(data[0] + y_sz, DAV1D_PICTURE_ALIGNMENT);
data[2] = PL_ALIGN2(data[1] + uv_sz, DAV1D_PICTURE_ALIGNMENT);
p->allocator_data = alloc;
p->data[0] = (void *) data[0];
p->data[1] = (void *) data[1];
p->data[2] = (void *) data[2];
return 0;
}
PL_DAV1D_API void pl_release_dav1dpicture(Dav1dPicture *p, void *cookie)
{
struct pl_dav1dalloc *alloc = p->allocator_data;
if (!alloc)
return;
assert(alloc->magic[0] == PL_MAGIC0);
assert(alloc->magic[1] == PL_MAGIC1);
assert(alloc->gpu == cookie);
pl_buf_destroy(alloc->gpu, &alloc->buf);
free(alloc);
p->data[0] = p->data[1] = p->data[2] = p->allocator_data = NULL;
}
#undef PL_ALIGN2
#undef PL_MAGIC0
#undef PL_MAGIC1
#endif // LIBPLACEBO_DAV1D_H_

View File

@ -0,0 +1,34 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_DOLBYVISION_H_
#define LIBPLACEBO_DOLBYVISION_H_
#include <libplacebo/colorspace.h>
PL_API_BEGIN
// Parses the Dolby Vision RPU, and sets the `pl_hdr_metadata` dynamic
// brightness metadata fields accordingly.
//
// Note: requires `PL_HAVE_LIBDOVI` to be defined, no-op otherwise.
PL_API void pl_hdr_metadata_from_dovi_rpu(struct pl_hdr_metadata *out,
const uint8_t *buf, size_t size);
PL_API_END
#endif // LIBPLACEBO_DOLBYVISION_H_

View File

@ -0,0 +1,230 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_FRAME_QUEUE_H
#define LIBPLACEBO_FRAME_QUEUE_H
#include <libplacebo/renderer.h>
#include <libplacebo/shaders/deinterlacing.h>
PL_API_BEGIN
// An abstraction layer for automatically turning a conceptual stream of
// (frame, pts) pairs, as emitted by a decoder or filter graph, into a
// `pl_frame_mix` suitable for `pl_render_image_mix`.
//
// This API ensures that minimal work is performed (e.g. only mapping frames
// that are actually required), while also satisfying the requirements
// of any configured frame mixer.
//
// Thread-safety: Safe
typedef struct pl_queue_t *pl_queue;
enum pl_queue_status {
PL_QUEUE_OK, // success
PL_QUEUE_EOF, // no more frames are available
PL_QUEUE_MORE, // more frames needed, but not (yet) available
PL_QUEUE_ERR = -1, // some unknown error occurred while retrieving frames
};
struct pl_source_frame {
// The frame's presentation timestamp, in seconds relative to the first
// frame. These must be monotonically increasing for subsequent frames.
// To implement a discontinuous jump, users must explicitly reset the
// frame queue with `pl_queue_reset` and restart from PTS 0.0.
double pts;
// The frame's duration. This is not needed in normal scenarios, as the
// FPS can be inferred from the `pts` values themselves. Providing it
// only helps initialize the value for initial frames, which can smooth
// out the interpolation weights. Its use is also highly recommended
// when displaying interlaced frames. (Optional)
float duration;
// If set to something other than PL_FIELD_NONE, this source frame is
// marked as interlaced. It will be split up into two separate frames
// internally, and exported to the resulting `pl_frame_mix` as a pair of
// fields, referencing the corresponding previous and next frames. The
// first field will have the same PTS as `pts`, and the second field will
// be inserted at the timestamp `pts + duration/2`.
//
// Note: As a result of FPS estimates being unreliable around streams with
// mixed FPS (or when mixing interlaced and progressive frames), it's
// highly recommended to always specify a valid `duration` for interlaced
// frames.
enum pl_field first_field;
// Abstract frame data itself. To allow mapping frames only when they're
// actually needed, frames use a lazy representation. The provided
// callbacks will be invoked to interface with it.
void *frame_data;
// This will be called to map the frame to the GPU, only if needed.
//
// `tex` is a pointer to an array of 4 texture objects (or NULL), which
// *may* serve as backing storage for the texture being mapped. These are
// intended to be recreated by `map`, e.g. using `pl_tex_recreate` or
// `pl_upload_plane` as appropriate. They will be managed internally by
// `pl_queue` and destroyed at some unspecified future point in time.
//
// Note: If `map` fails, it will not be retried, nor will `discard` be run.
// The user should clean up state in this case.
bool (*map)(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src,
struct pl_frame *out_frame);
// If present, this will be called on frames that are done being used by
// `pl_queue`. This may be useful to e.g. unmap textures backed by external
// APIs such as hardware decoders. (Optional)
void (*unmap)(pl_gpu gpu, struct pl_frame *frame, const struct pl_source_frame *src);
// This function will be called for frames that are deemed unnecessary
// (e.g. never became visible) and should instead be cleanly freed.
// (Optional)
void (*discard)(const struct pl_source_frame *src);
};
// Create a new, empty frame queue.
//
// It's highly recommended to fully render a single frame with `pts == 0.0`,
// and flush the GPU pipeline with `pl_gpu_finish`, prior to starting the timed
// playback loop.
PL_API pl_queue pl_queue_create(pl_gpu gpu);
PL_API void pl_queue_destroy(pl_queue *queue);
// Explicitly clear the queue. This is essentially equivalent to destroying
// and recreating the queue, but preserves any internal memory allocations.
//
// Note: Calling `pl_queue_reset` may block, if another thread is currently
// blocked on a different `pl_queue_*` call.
PL_API void pl_queue_reset(pl_queue queue);
// Explicitly push a frame. This is an alternative way to feed the frame queue
// with incoming frames, the other method being the asynchronous callback
// specified as `pl_queue_params.get_frame`. Both methods may be used
// simultaneously, although providing `get_frame` is recommended since it
// avoids the risk of the queue underrunning.
//
// When no more frames are available, call this function with `frame == NULL`
// to indicate EOF and begin draining the frame queue.
PL_API void pl_queue_push(pl_queue queue, const struct pl_source_frame *frame);
// Variant of `pl_queue_push` that blocks while the queue is judged
// (internally) to be "too full". This is useful for asynchronous decoder loops
// in order to prevent the queue from exhausting available RAM if frames are
// decoded significantly faster than they're displayed.
//
// The given `timeout` parameter specifies how long to wait before giving up,
// in nanoseconds. Returns false if this timeout was reached.
PL_API bool pl_queue_push_block(pl_queue queue, uint64_t timeout,
const struct pl_source_frame *frame);
struct pl_queue_params {
// The PTS of the frame that will be rendered. This should be set to the
// timestamp (in seconds) of the next vsync, relative to the initial frame.
//
// These must be monotonically increasing. To implement a discontinuous
// jump, users must explicitly reset the frame queue with `pl_queue_reset`
// and restart from PTS 0.0.
double pts;
// The radius of the configured mixer. This should be set to the value
// as returned by `pl_frame_mix_radius`.
float radius;
// The estimated duration of a vsync, in seconds. This will only be used as
// a hint, the true value will be estimated by comparing `pts` timestamps
// between calls to `pl_queue_update`. (Optional)
float vsync_duration;
// If the difference between the (estimated) vsync duration and the
// (measured) frame duration is smaller than this threshold, silently
// disable interpolation and switch to ZOH semantics instead.
//
// For example, a value of 0.01 allows the FPS to differ by up to 1%
// without being interpolated. Note that this will result in a continuous
// phase drift unless also compensated for by the user, which will
// eventually resulted in a dropped or duplicated frame. (Though this can
// be preferable to seeing that same phase drift result in a temporally
// smeared image)
float interpolation_threshold;
// Specifies how long `pl_queue_update` will wait for frames to become
// available, in nanoseconds, before giving up and returning with
// QUEUE_MORE.
//
// If `get_frame` is provided, this value is ignored by `pl_queue` and
// should instead be interpreted by the provided callback.
uint64_t timeout;
// This callback will be used to pull new frames from the decoder. It may
// block if needed. The user is responsible for setting appropriate time
// limits and/or returning and interpreting QUEUE_MORE as sensible.
//
// Providing this callback is entirely optional. Users can instead choose
// to manually feed the frame queue with new frames using `pl_queue_push`.
enum pl_queue_status (*get_frame)(struct pl_source_frame *out_frame,
const struct pl_queue_params *params);
void *priv;
};
#define pl_queue_params(...) (&(struct pl_queue_params) { __VA_ARGS__ })
// Advance the frame queue's internal state to the target timestamp. Any frames
// which are no longer needed (i.e. too far in the past) are automatically
// unmapped and evicted. Any future frames which are needed to fill the queue
// must either have been pushed in advance, or will be requested using the
// provided `get_frame` callback. If you call this on `out_mix == NULL`, the
// queue state will advance, but no frames will be mapped.
//
// This function may return with PL_QUEUE_MORE, in which case the user may wish
// to ensure more frames are available and then re-run this function with the
// same parameters. In this case, `out_mix` is still written to, but it may be
// incomplete (or even contain no frames at all). Additionally, when the source
// contains interlaced frames (see `pl_source_frame.first_field`), this
// function may return with PL_QUEUE_MORE if a frame is missing references to
// a future frame.
//
// The resulting mix of frames in `out_mix` will represent the neighbourhood of
// the target timestamp, and can be passed to `pl_render_image_mix` as-is.
//
// Note: `out_mix` will only remain valid until the next call to
// `pl_queue_update` or `pl_queue_reset`.
PL_API enum pl_queue_status pl_queue_update(pl_queue queue, struct pl_frame_mix *out_mix,
const struct pl_queue_params *params);
// Returns a pl_queue's internal estimates for FPS and VPS (vsyncs per second).
// Returns 0.0 if no estimate is available.
PL_API float pl_queue_estimate_fps(pl_queue queue);
PL_API float pl_queue_estimate_vps(pl_queue queue);
// Returns the number of frames currently contained in a pl_queue.
PL_API int pl_queue_num_frames(pl_queue queue);
// Inspect the contents of the Nth queued frame. Returns false if `idx` is
// out of range.
//
// Warning: No guarantee is made to ensure validity of `out->frame_data`
// after this call. In particular, pl_queue_* calls made from another thread
// may call `discard()` on the frame in question. The user bears responsibility
// to avoid accessing `out->frame_data` in a multi-threaded scenario unless
// an external guarantee can be made that the frame won't be dequeued until
// it is done being used by the user.
PL_API bool pl_queue_peek(pl_queue queue, int idx, struct pl_source_frame *out);
PL_API_END
#endif // LIBPLACEBO_FRAME_QUEUE_H

View File

@ -0,0 +1,284 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_LIBAV_H_
#define LIBPLACEBO_LIBAV_H_
#include <libplacebo/config.h>
#include <libplacebo/gpu.h>
#include <libplacebo/shaders/deinterlacing.h>
#include <libplacebo/utils/upload.h>
#if defined(__cplusplus) && !defined(PL_LIBAV_IMPLEMENTATION)
# define PL_LIBAV_API
# define PL_LIBAV_IMPLEMENTATION 0
# warning Remember to include this file with a PL_LIBAV_IMPLEMENTATION set to 1 in \
C translation unit to provide implementation. Suppress this warning by \
defining PL_LIBAV_IMPLEMENTATION to 0 in C++ files.
#elif !defined(PL_LIBAV_IMPLEMENTATION)
# define PL_LIBAV_API static inline
# define PL_LIBAV_IMPLEMENTATION 1
#else
# define PL_LIBAV_API
#endif
PL_API_BEGIN
#include <libavformat/avformat.h>
#include <libavutil/frame.h>
#include <libavutil/version.h>
#include <libavcodec/avcodec.h>
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 16, 100) && defined(PL_HAVE_DOVI)
# define PL_HAVE_LAV_DOLBY_VISION
# include <libavutil/dovi_meta.h>
#endif
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 61, 100)
# define PL_HAVE_LAV_FILM_GRAIN
# include <libavutil/film_grain_params.h>
#endif
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 25, 100)
# define PL_HAVE_LAV_HDR
# include <libavutil/hdr_dynamic_metadata.h>
# include <libavutil/mastering_display_metadata.h>
#endif
//------------------------------------------------------------------------
// Important note: For support for AVVkFrame, which depends on <vulkan.h>,
// users *SHOULD* include <vulkan/vulkan.h> manually before this header.
//------------------------------------------------------------------------
// Fill in the details of a `pl_frame` from an AVFrame. This function will
// explicitly clear `out_frame`, setting all extra fields to 0. After this
// function returns, the only missing data is information related to the plane
// texture itself (`planes[N].texture`), as well as any overlays (e.g.
// subtitles).
//
// Note: If the AVFrame contains an embedded ICC profile or H.274 film grain
// metadata, the resulting `out_image->profile` will reference this pointer,
// meaning that in general, the `pl_frame` is only guaranteed to be valid as
// long as the AVFrame is not freed.
//
// Note: This will ignore Dolby Vision metadata by default (to avoid leaking
// memory), either switch to pl_map_avframe_ex or do it manually using
// pl_map_dovi_metadata.
PL_LIBAV_API void pl_frame_from_avframe(struct pl_frame *out_frame, const AVFrame *frame);
// Deprecated aliases for backwards compatibility
#define pl_image_from_avframe pl_frame_from_avframe
#define pl_target_from_avframe pl_frame_from_avframe
// Copy extra metadata from an AVStream to a pl_frame. This should be called
// after `pl_frame_from_avframe` or `pl_map_avframe` (respectively), and sets
// metadata associated with stream-level side data. This is needed because
// FFmpeg rather annoyingly does not propagate stream-level metadata to frames.
PL_LIBAV_API void pl_frame_copy_stream_props(struct pl_frame *out_frame,
const AVStream *stream);
#ifdef PL_HAVE_LAV_HDR
struct pl_av_hdr_metadata {
// All fields are optional and may be passed as `NULL`.
const AVMasteringDisplayMetadata *mdm;
const AVContentLightMetadata *clm;
const AVDynamicHDRPlus *dhp;
};
// Helper function to update a `pl_hdr_metadata` struct from HDR10/HDR10+
// metadata in the FFmpeg format. Unspecified/invalid elements will be left
// uninitialized in `out`.
PL_LIBAV_API void pl_map_hdr_metadata(struct pl_hdr_metadata *out,
const struct pl_av_hdr_metadata *metadata);
#endif
#ifdef PL_HAVE_LAV_DOLBY_VISION
// Helper function to map Dolby Vision metadata from the FFmpeg format.
PL_LIBAV_API void pl_map_dovi_metadata(struct pl_dovi_metadata *out,
const AVDOVIMetadata *metadata);
// Helper function to map Dolby Vision metadata from the FFmpeg format
// to `pl_dovi_metadata`, and adds it to the `pl_frame`.
// The `pl_frame` colorspace fields and HDR struct are also updated with
// values from the `AVDOVIMetadata`.
//
// Note: The `pl_dovi_metadata` must be allocated externally.
// Also, currently the metadata is only used if the `AVDOVIRpuDataHeader`
// `disable_residual_flag` field is not zero and can be checked before allocating.
PL_LIBAV_API void pl_frame_map_avdovi_metadata(struct pl_frame *out_frame,
struct pl_dovi_metadata *dovi,
const AVDOVIMetadata *metadata);
#endif
// Helper function to test if a pixfmt would be supported by the GPU.
// Essentially, this can be used to check if `pl_map_avframe` would work for a
// given AVPixelFormat, without actually uploading or allocating anything.
PL_LIBAV_API bool pl_test_pixfmt(pl_gpu gpu, enum AVPixelFormat pixfmt);
// Variant of `pl_test_pixfmt` that also tests for the given capabilities
// being present. Note that in the presence of hardware accelerated frames,
// this cannot be tested without frame-specific information (i.e. swformat),
// but in practice this should be a non-issue as GPU-native hwformats will
// probably be fully supported.
PL_LIBAV_API bool pl_test_pixfmt_caps(pl_gpu gpu, enum AVPixelFormat pixfmt,
enum pl_fmt_caps caps);
// Like `pl_frame_from_avframe`, but the texture pointers are also initialized
// to ensure they have the correct size and format to match the AVframe.
// Similar in spirit to `pl_recreate_plane`, and the same notes apply. `tex`
// must be an array of 4 pointers of type `pl_tex`, each either
// pointing to a valid texture, or NULL. Returns whether successful.
PL_LIBAV_API bool pl_frame_recreate_from_avframe(pl_gpu gpu, struct pl_frame *out_frame,
pl_tex tex[4], const AVFrame *frame);
struct pl_avframe_params {
// The AVFrame to map. Required.
const AVFrame *frame;
// Backing textures for frame data. Required for all non-hwdec formats.
// This must point to an array of four valid textures (or NULL entries).
//
// Note: Not cleaned up by `pl_unmap_avframe`. The intent is for users to
// re-use this texture array for subsequent frames, to avoid texture
// creation/destruction overhead.
pl_tex *tex;
// Also map Dolby Vision metadata (if supported). Note that this also
// overrides the colorimetry metadata (forces BT.2020+PQ).
bool map_dovi;
};
#define PL_AVFRAME_DEFAULTS \
.map_dovi = true,
#define pl_avframe_params(...) (&(struct pl_avframe_params) { PL_AVFRAME_DEFAULTS __VA_ARGS__ })
// Very high level helper function to take an `AVFrame` and map it to the GPU.
// The resulting `pl_frame` remains valid until `pl_unmap_avframe` is called,
// which must be called at some point to clean up state. The `AVFrame` is
// automatically ref'd and unref'd if needed. Returns whether successful.
//
// Note: `out_frame->user_data` points to a privately managed opaque struct
// and must not be touched by the user.
PL_LIBAV_API bool pl_map_avframe_ex(pl_gpu gpu, struct pl_frame *out_frame,
const struct pl_avframe_params *params);
PL_LIBAV_API void pl_unmap_avframe(pl_gpu gpu, struct pl_frame *frame);
// Backwards compatibility with previous versions of this API.
PL_LIBAV_API bool pl_map_avframe(pl_gpu gpu, struct pl_frame *out_frame,
pl_tex tex[4], const AVFrame *avframe);
// Return the AVFrame* that a pl_frame was mapped from (via pl_map_avframe_ex)
// Note: This reference is attached to the `pl_frame` and will get freed by
// pl_unmap_avframe.
PL_LIBAV_API AVFrame *pl_get_mapped_avframe(const struct pl_frame *frame);
// Download the texture contents of a `pl_frame` back to a corresponding
// AVFrame. Blocks until completion.
//
// Note: This function performs minimal verification, so incorrect usage will
// likely result in broken frames. Use `pl_frame_recreate_from_avframe` to
// ensure matching formats.
PL_LIBAV_API bool pl_download_avframe(pl_gpu gpu,
const struct pl_frame *frame,
AVFrame *out_frame);
// Helper functions to update the colorimetry data in an AVFrame based on
// the values specified in the given color space / color repr / profile.
//
// Note: These functions can and will allocate AVFrame side data if needed,
// in particular to encode HDR metadata in `space.hdr`.
PL_LIBAV_API void pl_avframe_set_color(AVFrame *frame, struct pl_color_space space);
PL_LIBAV_API void pl_avframe_set_repr(AVFrame *frame, struct pl_color_repr repr);
PL_LIBAV_API void pl_avframe_set_profile(AVFrame *frame, struct pl_icc_profile profile);
// Map an AVPixelFormat to an array of pl_plane_data structs. The array must
// have at least `av_pix_fmt_count_planes(fmt)` elements, but never more than
// 4. This function leaves `width`, `height` and `row_stride`, as well as the
// data pointers, uninitialized.
//
// If `bits` is non-NULL, this function will attempt aligning the resulting
// `pl_plane_data` struct for optimal compatibility, placing the resulting
// `pl_bit_depth` metadata into `bits`.
//
// Returns the number of plane structs written to, or 0 on error.
//
// Note: This function is usually clumsier to use than the higher-level
// functions above, but it might have some fringe use cases, for example if
// the user wants to replace the data buffers by `pl_buf` references in the
// `pl_plane_data` before uploading it to the GPU.
PL_LIBAV_API int pl_plane_data_from_pixfmt(struct pl_plane_data data[4],
struct pl_bit_encoding *bits,
enum AVPixelFormat pix_fmt);
// Callback for AVCodecContext.get_buffer2 that allocates memory from
// persistently mapped buffers. This can be more efficient than regular
// system memory, especially on platforms that don't support importing
// PL_HANDLE_HOST_PTR as buffers.
//
// Note: `avctx->opaque` must be a pointer that *points* to the GPU instance.
// That is, it should have type `pl_gpu *`.
PL_LIBAV_API int pl_get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags);
// Mapping functions for the various libavutil enums. Note that these are not
// quite 1:1, and even for values that exist in both, the semantics sometimes
// differ. Some special cases (e.g. ICtCp, or XYZ) are handled differently in
// libplacebo and libavutil, respectively.
//
// Because of this, it's generally recommended to avoid these and instead use
// helpers like `pl_frame_from_avframe`, which contain extra logic to patch
// through all of the special cases.
PL_LIBAV_API enum pl_color_system pl_system_from_av(enum AVColorSpace spc);
PL_LIBAV_API enum AVColorSpace pl_system_to_av(enum pl_color_system sys);
PL_LIBAV_API enum pl_color_levels pl_levels_from_av(enum AVColorRange range);
PL_LIBAV_API enum AVColorRange pl_levels_to_av(enum pl_color_levels levels);
PL_LIBAV_API enum pl_color_primaries pl_primaries_from_av(enum AVColorPrimaries prim);
PL_LIBAV_API enum AVColorPrimaries pl_primaries_to_av(enum pl_color_primaries prim);
PL_LIBAV_API enum pl_color_transfer pl_transfer_from_av(enum AVColorTransferCharacteristic trc);
PL_LIBAV_API enum AVColorTransferCharacteristic pl_transfer_to_av(enum pl_color_transfer trc);
PL_LIBAV_API enum pl_chroma_location pl_chroma_from_av(enum AVChromaLocation loc);
PL_LIBAV_API enum AVChromaLocation pl_chroma_to_av(enum pl_chroma_location loc);
// Helper function to generate a `pl_color_space` struct from an AVFrame.
PL_LIBAV_API void pl_color_space_from_avframe(struct pl_color_space *out_csp,
const AVFrame *frame);
// Helper function to pick the right `pl_field` value for an AVFrame.
PL_LIBAV_API enum pl_field pl_field_from_avframe(const AVFrame *frame);
#ifdef PL_HAVE_LAV_FILM_GRAIN
// Fill in film grain parameters from an AVFilmGrainParams.
//
// Note: The resulting struct will only remain valid as long as the
// `AVFilmGrainParams` remains valid.
PL_LIBAV_API void pl_film_grain_from_av(struct pl_film_grain_data *out_data,
const AVFilmGrainParams *fgp);
#endif
// Deprecated alias for backwards compatibility
#define pl_swapchain_colors_from_avframe pl_color_space_from_avframe
// Actual implementation, included as part of this header to avoid having
// a compile-time dependency on libavutil.
#if PL_LIBAV_IMPLEMENTATION
# include <libplacebo/utils/libav_internal.h>
#endif
PL_API_END
#endif // LIBPLACEBO_LIBAV_H_

View File

@ -0,0 +1,153 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_UPLOAD_H_
#define LIBPLACEBO_UPLOAD_H_
#include <stdint.h>
#include <libplacebo/gpu.h>
#include <libplacebo/renderer.h>
PL_API_BEGIN
// This file contains a utility function to assist in uploading data from host
// memory to a texture. In particular, the texture will be suitable for use as
// a `pl_plane`.
// Description of the host representation of an image plane
struct pl_plane_data {
enum pl_fmt_type type; // meaning of the data (must not be UINT or SINT)
int width, height; // dimensions of the plane
int component_size[4]; // size in bits of each coordinate
int component_pad[4]; // ignored bits preceding each component
int component_map[4]; // semantic meaning of each component (pixel order)
size_t pixel_stride; // offset in bytes between pixels (required)
size_t row_stride; // offset in bytes between rows (optional)
bool swapped; // pixel data is endian-swapped (non-native)
// Similar to `pl_tex_transfer_params`, you can either upload from a raw
// pointer address, or a buffer + offset. Again, the use of these two
// mechanisms is mutually exclusive.
//
// 1. Uploading from host memory
const void *pixels; // the actual data underlying this plane
// 2. Uploading from a buffer (requires `pl_gpu_limits.buf_transfer`)
pl_buf buf; // the buffer to use
size_t buf_offset; // offset of data within buffer, must be a
// multiple of `pixel_stride` as well as of 4
// Similar to `pl_tex_transfer_params.callback`, this allows turning the
// upload of a plane into an asynchronous upload. The same notes apply.
void (*callback)(void *priv);
void *priv;
// Note: When using this together with `pl_frame`, there is some amount of
// overlap between `component_pad` and `pl_color_repr.bits`. Some key
// differences between the two:
//
// - the bits from `component_pad` are ignored; whereas the superfluous bits
// in a `pl_color_repr` must be 0.
// - the `component_pad` exists to align the component size and placement
// with the capabilities of GPUs; the `pl_color_repr` exists to control
// the semantics of the color samples on a finer granularity.
// - the `pl_color_repr` applies to the color sample as a whole, and
// therefore applies to all planes; the `component_pad` can be different
// for each plane.
// - `component_pad` interacts with float textures by moving the actual
// float in memory. `pl_color_repr` interacts with float data as if
// the float was converted from an integer under full range semantics.
//
// To help establish the motivating difference, a typical example of a use
// case would be yuv420p10. Since 10-bit GPU texture support is limited,
// and working with non-byte-aligned pixels is awkward in general, the
// convention is to represent yuv420p10 as 16-bit samples with either the
// high or low bits set to 0. In this scenario, the `component_size` of the
// `pl_plane_data` and `pl_bit_encoding.sample_depth` would be 16, while
// the `pl_bit_encoding.color_depth` would be 10 (and additionally, the
// `pl_bit_encoding.bit_shift` would be either 0 or 6, depending on
// whether the low or the high bits are used).
//
// On the contrary, something like a packed, 8-bit XBGR format (where the
// X bits are ignored and may contain garbage) would set `component_pad[0]`
// to 8, and the component_size[0:2] (respectively) to 8 as well.
//
// As a general rule of thumb, for maximum compatibility, you should try
// and align component_size/component_pad to multiples of 8 and explicitly
// clear any remaining superfluous bits (+ use `pl_color_repr.bits` to
// ensure they're decoded correctly). You should also try to align the
// `pixel_stride` to a power of two.
};
// Fills in the `component_size`, `component_pad` and `component_map` fields
// based on the supplied mask for each component (in semantic order, i.e.
// RGBA). Each element of `mask` must have a contiguous range of set bits.
PL_API void pl_plane_data_from_mask(struct pl_plane_data *data, uint64_t mask[4]);
// Fills in the `component_size`, `component_pad` and `component_map` fields
// based on the supplied sizes (in bits) and shift of each component (in
// semantic order).
//
// Similar to `pl_plane_data_from_mask` but not limited to 64-bit pixels.
PL_API void pl_plane_data_from_comps(struct pl_plane_data *data, int size[4],
int shift[4]);
// Helper function to take a `pl_plane_data` struct and try and improve its
// alignment to make it more likely to correspond to a real `pl_fmt`. It does
// this by attempting to round each component up to the nearest byte boundary.
// This relies on the assumption (true in practice) that superfluous bits of
// byte-misaligned formats are explicitly set to 0.
//
// The resulting shift must be consistent across all components, in which case
// it's returned in `out_bits`. If no alignment was possible, `out_bits` is set
// to {0}, and this function returns false.
PL_API bool pl_plane_data_align(struct pl_plane_data *data, struct pl_bit_encoding *out_bits);
// Helper function to find a suitable `pl_fmt` based on a pl_plane_data's
// requirements. This is called internally by `pl_upload_plane`, but it's
// exposed to users both as a convenience and so they may pre-emptively check
// if a format would be supported without actually having to attempt the upload.
PL_API pl_fmt pl_plane_find_fmt(pl_gpu gpu, int out_map[4], const struct pl_plane_data *data);
// Upload an image plane to a texture, and output the resulting `pl_plane`
// struct to `out_plane` (optional). `tex` must be a valid pointer to a texture
// (or NULL), which will be destroyed and reinitialized if it does not already
// exist or is incompatible. Returns whether successful.
//
// The resulting texture is guaranteed to be `sampleable`, and it will also try
// and maximize compatibility with the other `pl_renderer` requirements
// (blittable, linear filterable, etc.).
//
// Note: `out_plane->shift_x/y` and `out_plane->flipped` are left
// uninitialized, and should be set explicitly by the user.
PL_API bool pl_upload_plane(pl_gpu gpu, struct pl_plane *out_plane,
pl_tex *tex, const struct pl_plane_data *data);
// Like `pl_upload_plane`, but only creates an uninitialized texture object
// rather than actually performing an upload. This can be useful to, for
// example, prepare textures to be used as the target of rendering.
//
// The resulting texture is guaranteed to be `renderable`, and it will also try
// to maximize compatibility with the other `pl_renderer` requirements
// (blittable, storable, etc.).
PL_API bool pl_recreate_plane(pl_gpu gpu, struct pl_plane *out_plane,
pl_tex *tex, const struct pl_plane_data *data);
PL_API_END
#endif // LIBPLACEBO_UPLOAD_H_

View File

@ -0,0 +1,638 @@
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBPLACEBO_VULKAN_H_
#define LIBPLACEBO_VULKAN_H_
#include <vulkan/vulkan.h>
#include <libplacebo/gpu.h>
#include <libplacebo/swapchain.h>
PL_API_BEGIN
#define PL_VK_MIN_VERSION VK_API_VERSION_1_2
// Structure representing a VkInstance. Using this is not required.
typedef const struct pl_vk_inst_t {
VkInstance instance;
// The Vulkan API version supported by this VkInstance.
uint32_t api_version;
// The associated vkGetInstanceProcAddr pointer.
PFN_vkGetInstanceProcAddr get_proc_addr;
// The instance extensions that were successfully enabled, including
// extensions enabled by libplacebo internally. May contain duplicates.
const char * const *extensions;
int num_extensions;
// The instance layers that were successfully enabled, including
// layers enabled by libplacebo internally. May contain duplicates.
const char * const *layers;
int num_layers;
} *pl_vk_inst;
struct pl_vk_inst_params {
// If set, enable the debugging and validation layers. These should
// generally be lightweight and relatively harmless to enable.
bool debug;
// If set, also enable GPU-assisted verification and best practices
// layers. (Note: May cause substantial slowdown and/or result in lots of
// false positive spam)
bool debug_extra;
// If nonzero, restricts the Vulkan API version to be at most this. This
// is only really useful for explicitly testing backwards compatibility.
uint32_t max_api_version;
// Pointer to a user-provided `vkGetInstanceProcAddr`. If this is NULL,
// libplacebo will use the directly linked version (if available).
PFN_vkGetInstanceProcAddr get_proc_addr;
// Enables extra instance extensions. Instance creation will fail if these
// extensions are not all supported. The user may use this to enable e.g.
// windowing system integration.
const char * const *extensions;
int num_extensions;
// Enables extra optional instance extensions. These are opportunistically
// enabled if supported by the device, but otherwise skipped.
const char * const *opt_extensions;
int num_opt_extensions;
// Enables extra layers. Instance creation will fail if these layers are
// not all supported.
//
// NOTE: Layers needed for required/optional extensions are automatically
// enabled. The user does not specifically need to enable layers related
// to extension support.
const char * const *layers;
int num_layers;
// Enables extra optional layers. These are opportunistically enabled if
// supported by the platform, but otherwise skipped.
const char * const *opt_layers;
int num_opt_layers;
};
#define pl_vk_inst_params(...) (&(struct pl_vk_inst_params) { __VA_ARGS__ })
PL_API extern const struct pl_vk_inst_params pl_vk_inst_default_params;
// Helper function to simplify instance creation. The user could also bypass
// these helpers and do it manually, but this function is provided as a
// convenience. It also sets up a debug callback which forwards all vulkan
// messages to the `pl_log` callback.
PL_API pl_vk_inst pl_vk_inst_create(pl_log log, const struct pl_vk_inst_params *params);
PL_API void pl_vk_inst_destroy(pl_vk_inst *inst);
struct pl_vulkan_queue {
uint32_t index; // Queue family index
uint32_t count; // Queue family count
};
// Structure representing the actual vulkan device and associated GPU instance
typedef const struct pl_vulkan_t *pl_vulkan;
struct pl_vulkan_t {
pl_gpu gpu;
// The vulkan objects in use. The user may use this for their own purposes,
// but please note that the lifetime is tied to the lifetime of the
// pl_vulkan object, and must not be destroyed by the user. Note that the
// created vulkan device may have any number of queues and queue family
// assignments; so using it for queue submission commands is ill-advised.
VkInstance instance;
VkPhysicalDevice phys_device;
VkDevice device;
// The associated vkGetInstanceProcAddr pointer.
PFN_vkGetInstanceProcAddr get_proc_addr;
// The Vulkan API version supported by this VkPhysicalDevice.
uint32_t api_version;
// The device extensions that were successfully enabled, including
// extensions enabled by libplacebo internally. May contain duplicates.
const char * const *extensions;
int num_extensions;
// The device features that were enabled at device creation time.
//
// Note: Whenever a feature flag is ambiguious between several alternative
// locations, for completeness' sake, we include both.
const VkPhysicalDeviceFeatures2 *features;
// The explicit queue families we are using to provide a given capability.
struct pl_vulkan_queue queue_graphics; // provides VK_QUEUE_GRAPHICS_BIT
struct pl_vulkan_queue queue_compute; // provides VK_QUEUE_COMPUTE_BIT
struct pl_vulkan_queue queue_transfer; // provides VK_QUEUE_TRANSFER_BIT
// Functions for locking a queue. These must be used to lock VkQueues for
// submission or other related operations when sharing the VkDevice between
// multiple threads, Using this on queue families or indices not contained
// in `queues` is undefined behavior.
void (*lock_queue)(pl_vulkan vk, uint32_t qf, uint32_t qidx);
void (*unlock_queue)(pl_vulkan vk, uint32_t qf, uint32_t qidx);
// --- Deprecated fields
// These are the same active queue families and their queue counts in list
// form. This list does not contain duplicates, nor any extra queues
// enabled at device creation time. Deprecated in favor of querying
// `vkGetPhysicalDeviceQueueFamilyProperties` directly.
const struct pl_vulkan_queue *queues PL_DEPRECATED;
int num_queues PL_DEPRECATED;
};
struct pl_vulkan_params {
// The vulkan instance. Optional, if NULL then libplacebo will internally
// create a VkInstance with the settings from `instance_params`.
//
// Note: The VkInstance provided by the user *MUST* be created with a
// VkApplicationInfo.apiVersion of PL_VK_MIN_VERSION or higher.
VkInstance instance;
// Pointer to `vkGetInstanceProcAddr`. If this is NULL, libplacebo will
// use the directly linked version (if available).
//
// Note: This overwrites the same value from `instance_params`.
PFN_vkGetInstanceProcAddr get_proc_addr;
// Configures the settings used for creating an internal vulkan instance.
// May be NULL. Ignored if `instance` is set.
const struct pl_vk_inst_params *instance_params;
// When choosing the device, rule out all devices that don't support
// presenting to this surface. When creating a device, enable all extensions
// needed to ensure we can present to this surface. Optional. Only legal
// when specifying an existing VkInstance to use.
VkSurfaceKHR surface;
// --- Physical device selection options
// The vulkan physical device. May be set by the caller to indicate the
// physical device to use. Otherwise, libplacebo will pick the "best"
// available GPU, based on the advertised device type. (i.e., it will
// prefer discrete GPUs over integrated GPUs). Only legal when specifying
// an existing VkInstance to use.
VkPhysicalDevice device;
// When choosing the device, only choose a device with this exact name.
// This overrides `allow_software`. No effect if `device` is set. Note: A
// list of devices and their names are logged at level PL_LOG_INFO.
const char *device_name;
// When choosing the device, only choose a device with this exact UUID.
// This overrides `allow_software` and `device_name`. No effect if `device`
// is set.
uint8_t device_uuid[16];
// When choosing the device, controls whether or not to also allow software
// GPUs. No effect if `device` or `device_name` are set.
bool allow_software;
// --- Logical device creation options
// Controls whether or not to allow asynchronous transfers, using transfer
// queue families, if supported by the device. This can be significantly
// faster and more power efficient, and also allows streaming uploads in
// parallel with rendering commands. Enabled by default.
bool async_transfer;
// Controls whether or not to allow asynchronous compute, using dedicated
// compute queue families, if supported by the device. On some devices,
// these can allow the GPU to schedule compute shaders in parallel with
// fragment shaders. Enabled by default.
bool async_compute;
// Limits the number of queues to use. If left as 0, libplacebo will use as
// many queues as the device supports. Multiple queues can result in
// improved efficiency when submitting multiple commands that can entirely
// or partially execute in parallel. Defaults to 1, since using more queues
// can actually decrease performance.
//
// Note: libplacebo will always *create* logical devices with all available
// queues for a given QF enabled, regardless of this setting.
int queue_count;
// Bitmask of extra queue families to enable. If set, then *all* queue
// families matching *any* of these flags will be enabled at device
// creation time. Setting this to VK_QUEUE_FLAG_BITS_MAX_ENUM effectively
// enables all queue families supported by the device.
VkQueueFlags extra_queues;
// Enables extra device extensions. Device creation will fail if these
// extensions are not all supported. The user may use this to enable e.g.
// interop extensions.
const char * const *extensions;
int num_extensions;
// Enables extra optional device extensions. These are opportunistically
// enabled if supported by the device, but otherwise skipped.
const char * const *opt_extensions;
int num_opt_extensions;
// Optional extra features to enable at device creation time. These are
// opportunistically enabled if supported by the physical device, but
// otherwise kept disabled.
const VkPhysicalDeviceFeatures2 *features;
// --- Misc/debugging options
// Restrict specific features to e.g. work around driver bugs, or simply
// for testing purposes
int max_glsl_version; // limit the maximum GLSL version
uint32_t max_api_version; // limit the maximum vulkan API version
};
// Default/recommended parameters. Should generally be safe and efficient.
#define PL_VULKAN_DEFAULTS \
.async_transfer = true, \
.async_compute = true, \
/* enabling multiple queues often decreases perf */ \
.queue_count = 1,
#define pl_vulkan_params(...) (&(struct pl_vulkan_params) { PL_VULKAN_DEFAULTS __VA_ARGS__ })
PL_API extern const struct pl_vulkan_params pl_vulkan_default_params;
// Creates a new vulkan device based on the given parameters and initializes
// a new GPU. If `params` is left as NULL, it defaults to
// &pl_vulkan_default_params.
//
// Thread-safety: Safe
PL_API pl_vulkan pl_vulkan_create(pl_log log, const struct pl_vulkan_params *params);
// Destroys the vulkan device and all associated objects, except for the
// VkInstance provided by the user.
//
// Note that all resources allocated from this vulkan object (e.g. via the
// `vk->ra` or using `pl_vulkan_create_swapchain`) *must* be explicitly
// destroyed by the user before calling this.
//
// Also note that this function will block until all in-flight GPU commands are
// finished processing. You can avoid this by manually calling `pl_gpu_finish`
// before `pl_vulkan_destroy`.
PL_API void pl_vulkan_destroy(pl_vulkan *vk);
// For a `pl_gpu` backed by `pl_vulkan`, this function can be used to retrieve
// the underlying `pl_vulkan`. Returns NULL for any other type of `gpu`.
PL_API pl_vulkan pl_vulkan_get(pl_gpu gpu);
struct pl_vulkan_device_params {
// The instance to use. Required!
//
// Note: The VkInstance provided by the user *must* be created with a
// VkApplicationInfo.apiVersion of PL_VK_MIN_VERSION or higher.
VkInstance instance;
// Mirrored from `pl_vulkan_params`. All of these fields are optional.
PFN_vkGetInstanceProcAddr get_proc_addr;
VkSurfaceKHR surface;
const char *device_name;
uint8_t device_uuid[16];
bool allow_software;
};
#define pl_vulkan_device_params(...) (&(struct pl_vulkan_device_params) { __VA_ARGS__ })
// Helper function to choose the best VkPhysicalDevice, given a VkInstance.
// This uses the same logic as `pl_vulkan_create` uses internally. If no
// matching device was found, this returns VK_NULL_HANDLE.
PL_API VkPhysicalDevice pl_vulkan_choose_device(pl_log log,
const struct pl_vulkan_device_params *params);
struct pl_vulkan_swapchain_params {
// The surface to use for rendering. Required, the user is in charge of
// creating this. Must belong to the same VkInstance as `vk->instance`.
VkSurfaceKHR surface;
// The preferred presentation mode. See the vulkan documentation for more
// information about these. If the device/surface combination does not
// support this mode, libplacebo will fall back to VK_PRESENT_MODE_FIFO_KHR.
//
// Warning: Leaving this zero-initialized is the same as having specified
// VK_PRESENT_MODE_IMMEDIATE_KHR, which is probably not what the user
// wants!
VkPresentModeKHR present_mode;
// Allow up to N in-flight frames. This essentially controls how many
// rendering commands may be queued up at the same time. See the
// documentation for `pl_swapchain_get_latency` for more information. For
// vulkan specifically, we are only able to wait until the GPU has finished
// rendering a frame - we are unable to wait until the display has actually
// finished displaying it. So this only provides a rough guideline.
// Optional, defaults to 3.
int swapchain_depth;
// This suppresses automatic recreation of the swapchain when any call
// returns VK_SUBOPTIMAL_KHR. Normally, libplacebo will recreate the
// swapchain internally on the next `pl_swapchain_start_frame`. If enabled,
// clients are assumed to take care of swapchain recreations themselves, by
// calling `pl_swapchain_resize` as appropriate. libplacebo will tolerate
// the "suboptimal" status indefinitely.
bool allow_suboptimal;
// Disable high-bit (10 or more) SDR formats. May help work around buggy
// drivers which don't dither properly when outputting high bit depth
// SDR backbuffers to 8-bit screens.
bool disable_10bit_sdr;
};
#define pl_vulkan_swapchain_params(...) (&(struct pl_vulkan_swapchain_params) { __VA_ARGS__ })
// Creates a new vulkan swapchain based on an existing VkSurfaceKHR. Using this
// function requires that the vulkan device was created with the
// VK_KHR_swapchain extension. The easiest way of accomplishing this is to set
// the `pl_vulkan_params.surface` explicitly at creation time.
PL_API pl_swapchain pl_vulkan_create_swapchain(pl_vulkan vk,
const struct pl_vulkan_swapchain_params *params);
// This will return true if the vulkan swapchain is internally detected
// as being suboptimal (VK_SUBOPTIMAL_KHR). This might be of use to clients
// who have `params->allow_suboptimal` enabled.
PL_API bool pl_vulkan_swapchain_suboptimal(pl_swapchain sw);
// Vulkan interop API, for sharing a single VkDevice (and associated vulkan
// resources) directly with the API user. The use of this API is a bit sketchy
// and requires careful communication of Vulkan API state.
struct pl_vulkan_import_params {
// The vulkan instance. Required.
//
// Note: The VkInstance provided by the user *must* be created with a
// VkApplicationInfo.apiVersion of PL_VK_MIN_VERSION or higher.
VkInstance instance;
// Pointer to `vkGetInstanceProcAddr`. If this is NULL, libplacebo will
// use the directly linked version (if available).
PFN_vkGetInstanceProcAddr get_proc_addr;
// The physical device selected by the user. Required.
VkPhysicalDevice phys_device;
// The logical device created by the user. Required.
VkDevice device;
// --- Logical device parameters
// List of all device-level extensions that were enabled. (Instance-level
// extensions need not be re-specified here, since it's guaranteed that any
// instance-level extensions that device-level extensions depend on were
// enabled at the instance level)
const char * const *extensions;
int num_extensions;
// Enabled queue families. At least `queue_graphics` is required.
//
// It's okay for multiple queue families to be specified with the same
// index, e.g. in the event that a dedicated compute queue also happens to
// be the dedicated transfer queue.
//
// It's also okay to leave the queue struct as {0} in the event that no
// dedicated queue exists for a given operation type. libplacebo will
// automatically fall back to using e.g. the graphics queue instead.
struct pl_vulkan_queue queue_graphics; // must support VK_QUEUE_GRAPHICS_BIT
struct pl_vulkan_queue queue_compute; // must support VK_QUEUE_COMPUTE_BIT
struct pl_vulkan_queue queue_transfer; // must support VK_QUEUE_TRANSFER_BIT
// Enabled VkPhysicalDeviceFeatures. The device *must* be created with
// all of the features in `pl_vulkan_required_features` enabled.
const VkPhysicalDeviceFeatures2 *features;
// Functions for locking a queue. If set, these will be used instead of
// libplacebo's internal functions for `pl_vulkan.(un)lock_queue`.
void (*lock_queue)(void *ctx, uint32_t qf, uint32_t qidx);
void (*unlock_queue)(void *ctx, uint32_t qf, uint32_t qidx);
void *queue_ctx;
// --- Misc/debugging options
// Restrict specific features to e.g. work around driver bugs, or simply
// for testing purposes. See `pl_vulkan_params` for a description of these.
int max_glsl_version;
uint32_t max_api_version;
};
#define pl_vulkan_import_params(...) (&(struct pl_vulkan_import_params) { __VA_ARGS__ })
// For purely informative reasons, this contains a list of extensions and
// device features that libplacebo *can* make use of. These are all strictly
// optional, but provide a hint to the API user as to what might be worth
// enabling at device creation time.
//
// Note: This also includes physical device features provided by extensions.
// They are all provided using extension-specific features structs, rather
// than the more general purpose VkPhysicalDeviceVulkan11Features etc.
PL_API extern const char * const pl_vulkan_recommended_extensions[];
PL_API extern const int pl_vulkan_num_recommended_extensions;
PL_API extern const VkPhysicalDeviceFeatures2 pl_vulkan_recommended_features;
// A list of device features that are required by libplacebo. These
// *must* be provided by imported Vulkan devices.
//
// Note: `pl_vulkan_recommended_features` does not include this list.
PL_API extern const VkPhysicalDeviceFeatures2 pl_vulkan_required_features;
// Import an existing VkDevice instead of creating a new one, and wrap it into
// a `pl_vulkan` abstraction. It's safe to `pl_vulkan_destroy` this, which will
// destroy application state related to libplacebo but leave the underlying
// VkDevice intact.
PL_API pl_vulkan pl_vulkan_import(pl_log log, const struct pl_vulkan_import_params *params);
struct pl_vulkan_wrap_params {
// The image itself. It *must* be usable concurrently by all of the queue
// family indices listed in `pl_vulkan->queues`. Note that this requires
// the use of VK_SHARING_MODE_CONCURRENT if `pl_vulkan->num_queues` is
// greater than 1. If this is difficult to achieve for the user, then
// `async_transfer` / `async_compute` should be turned off, which
// guarantees the use of only one queue family.
VkImage image;
// Which aspect of `image` to wrap. Only useful for wrapping individual
// sub-planes of planar images. If left as 0, it defaults to the entire
// image (i.e. the union of VK_IMAGE_ASPECT_PLANE_N_BIT for planar formats,
// and VK_IMAGE_ASPECT_COLOR_BIT otherwise).
VkImageAspectFlags aspect;
// The image's dimensions (unused dimensions must be 0)
int width;
int height;
int depth;
// The image's format. libplacebo will try to map this to an equivalent
// pl_fmt. If no compatible pl_fmt is found, wrapping will fail.
VkFormat format;
// The usage flags the image was created with. libplacebo will set the
// pl_tex capabilities to include whatever it can, as determined by the set
// of enabled usage flags.
VkImageUsageFlags usage;
// See `pl_tex_params`
void *user_data;
pl_debug_tag debug_tag;
};
#define pl_vulkan_wrap_params(...) (&(struct pl_vulkan_wrap_params) { \
.debug_tag = PL_DEBUG_TAG, \
__VA_ARGS__ \
})
// Wraps an external VkImage into a pl_tex abstraction. By default, the image
// is considered "held" by the user and must be released before calling any
// pl_tex_* API calls on it (see `pl_vulkan_release`).
//
// This wrapper can be destroyed by simply calling `pl_tex_destroy` on it,
// which will not destroy the underlying VkImage. If a pl_tex wrapper is
// destroyed while an image is not currently being held by the user, that
// image is left in an undefined state.
//
// Wrapping the same VkImage multiple times is undefined behavior, as is trying
// to wrap an image belonging to a different VkDevice than the one in use by
// `gpu`.
//
// This function may fail, in which case it returns NULL.
PL_API pl_tex pl_vulkan_wrap(pl_gpu gpu, const struct pl_vulkan_wrap_params *params);
// Analogous to `pl_vulkan_wrap`, this function takes any `pl_tex` (including
// ones created by `pl_tex_create`) and unwraps it to expose the underlying
// VkImage to the user. Unlike `pl_vulkan_wrap`, this `pl_tex` is *not*
// considered held after calling this function - the user must explicitly
// `pl_vulkan_hold` before accessing the VkImage.
//
// `out_format` and `out_flags` will be updated to hold the VkImage's
// format and usage flags. (Optional)
PL_API VkImage pl_vulkan_unwrap(pl_gpu gpu, pl_tex tex,
VkFormat *out_format, VkImageUsageFlags *out_flags);
// Represents a vulkan semaphore/value pair (for compatibility with timeline
// semaphores). When using normal, binary semaphores, `value` may be ignored.
typedef struct pl_vulkan_sem {
VkSemaphore sem;
uint64_t value;
} pl_vulkan_sem;
struct pl_vulkan_hold_params {
// The Vulkan image to hold. It will be marked as held. Attempting to
// perform any pl_tex_* operation (except pl_tex_destroy) on a held image
// is undefined behavior.
pl_tex tex;
// The layout to transition the image to when holding. Alternatively, a
// pointer to receive the current image layout. If `out_layout` is
// provided, `layout` is ignored.
VkImageLayout layout;
VkImageLayout *out_layout;
// The queue family index to transition the image to. This can be used with
// VK_QUEUE_FAMILY_EXTERNAL to transition the image to an external API. As
// a special case, if set to VK_QUEUE_FAMILY_IGNORED, libplacebo will not
// transition the image, even if this image was not set up for concurrent
// usage. Ignored for concurrent images.
uint32_t qf;
// The semaphore to fire when the image is available for use. (Required)
pl_vulkan_sem semaphore;
};
#define pl_vulkan_hold_params(...) (&(struct pl_vulkan_hold_params) { __VA_ARGS__ })
// "Hold" a shared image, transferring control over the image to the user.
// Returns whether successful.
PL_API bool pl_vulkan_hold_ex(pl_gpu gpu, const struct pl_vulkan_hold_params *params);
struct pl_vulkan_release_params {
// The image to be released. It must be marked as "held". Performing any
// operation on the VkImage underlying this `pl_tex` while it is not being
// held by the user is undefined behavior.
pl_tex tex;
// The current layout of the image at the point in time when `semaphore`
// fires, or if no semaphore is specified, at the time of call.
VkImageLayout layout;
// The queue family index to transition the image to. This can be used with
// VK_QUEUE_FAMILY_EXTERNAL to transition the image rom an external API. As
// a special case, if set to VK_QUEUE_FAMILY_IGNORED, libplacebo will not
// transition the image, even if this image was not set up for concurrent
// usage. Ignored for concurrent images.
uint32_t qf;
// The semaphore to wait on before libplacebo will actually use or modify
// the image. (Optional)
//
// Note: the lifetime of `semaphore` is indeterminate, and destroying it
// while the texture is still depending on that semaphore is undefined
// behavior.
//
// Technically, the only way to be sure that it's safe to free is to use
// `pl_gpu_finish()` or similar (e.g. `pl_vulkan_destroy` or
// `vkDeviceWaitIdle`) after another operation involving `tex` has been
// emitted (or the texture has been destroyed).
//
//
// Warning: If `tex` is a planar image (`pl_fmt.num_planes > 0`), and
// `semaphore` is specified, it *must* be a timeline semaphore! Failure to
// respect this will result in undefined behavior. This warning does not
// apply to individual planes (as exposed by `pl_tex.planes`).
pl_vulkan_sem semaphore;
};
#define pl_vulkan_release_params(...) (&(struct pl_vulkan_release_params) { __VA_ARGS__ })
// "Release" a shared image, transferring control to libplacebo.
PL_API void pl_vulkan_release_ex(pl_gpu gpu, const struct pl_vulkan_release_params *params);
struct pl_vulkan_sem_params {
// The type of semaphore to create.
VkSemaphoreType type;
// For VK_SEMAPHORE_TYPE_TIMELINE, sets the initial timeline value.
uint64_t initial_value;
// If set, exports this VkSemaphore to the handle given in `out_handle`.
// The user takes over ownership, and should manually close it before
// destroying this VkSemaphore (via `pl_vulkan_sem_destroy`).
enum pl_handle_type export_handle;
union pl_handle *out_handle;
// Optional debug tag to identify this semaphore.
pl_debug_tag debug_tag;
};
#define pl_vulkan_sem_params(...) (&(struct pl_vulkan_sem_params) { \
.debug_tag = PL_DEBUG_TAG, \
__VA_ARGS__ \
})
// Helper functions to create and destroy vulkan semaphores. Returns
// VK_NULL_HANDLE on failure.
PL_API VkSemaphore pl_vulkan_sem_create(pl_gpu gpu, const struct pl_vulkan_sem_params *params);
PL_API void pl_vulkan_sem_destroy(pl_gpu gpu, VkSemaphore *semaphore);
// Backwards-compatibility wrappers for older versions of the API.
PL_DEPRECATED PL_API bool pl_vulkan_hold(pl_gpu gpu, pl_tex tex, VkImageLayout layout,
pl_vulkan_sem sem_out);
PL_DEPRECATED PL_API bool pl_vulkan_hold_raw(pl_gpu gpu, pl_tex tex, VkImageLayout *out_layout,
pl_vulkan_sem sem_out);
PL_DEPRECATED PL_API void pl_vulkan_release(pl_gpu gpu, pl_tex tex, VkImageLayout layout,
pl_vulkan_sem sem_in);
PL_API_END
#endif // LIBPLACEBO_VULKAN_H_

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libplacebo</string>
<key>CFBundleIdentifier</key>
<string>com.kintan.ksplayer.libplacebo</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>libplacebo</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>87.88.520</string>
<key>CFBundleVersion</key>
<string>87.88.520</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>MinimumOSVersion</key>
<string>10.15</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,4 @@
framework module libplacebo [system] {
umbrella "."
export *
}