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