diff options
Diffstat (limited to 'src/include/libplacebo/renderer.h')
-rw-r--r-- | src/include/libplacebo/renderer.h | 847 |
1 files changed, 847 insertions, 0 deletions
diff --git a/src/include/libplacebo/renderer.h b/src/include/libplacebo/renderer.h new file mode 100644 index 0000000..d2e01e4 --- /dev/null +++ b/src/include/libplacebo/renderer.h @@ -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_ |